pax_global_header00006660000000000000000000000064150146344400014513gustar00rootroot0000000000000052 comment=d3c94ac44133d338dc26dc3c62166a2f4b938b29 Xastir-Release-2.2.2/000077500000000000000000000000001501463444000143465ustar00rootroot00000000000000Xastir-Release-2.2.2/.dir-locals.el000066400000000000000000000001431501463444000167750ustar00rootroot00000000000000((nil . ((indent-tabs-mode . nil) (c-basic-offset . 2) (tab-width . 2)) )) Xastir-Release-2.2.2/.travis.yml000066400000000000000000000200101501463444000164500ustar00rootroot00000000000000language: c matrix: exclude: - compiler: gcc include: - os: linux dist: bionic name: "Ubuntu-18.04LTS light w/ImageMagick" env: - MAGIC_BIN="/usr/lib/x86_64-linux-gnu/ImageMagick-6.9.7/bin-q16/Magick-config" script: - ./bootstrap.sh - ./configure CPPFLAGS="-I/usr/include/geotiff" - make - sudo make install - cd Davis - ./bootstrap.sh - ./configure - make - sudo make install - cd ../LaCrosse - ./bootstrap.sh - ./configure - make - sudo make install addons: apt: packages: - imagemagick - libmagickcore-dev - libmotif-dev - libcurl4-openssl-dev - libpcre3-dev - libdb5.3-dev - shapelib - libshp-dev - libxpm-dev - os: linux dist: focal name: "Ubuntu-20.04LTS gcc full-featured w/GraphicsMagick" env: - CFLAGS="${CFLAGS} -Wall -O2 -Wformat-truncation=2 -Wstringop-truncation -Wextra" before_script: - export CC="gcc" - echo ${CC} - ${CC} --version script: - ./bootstrap.sh - ./configure CPPFLAGS="-I/usr/include/geotiff" - make - sudo make install - cd Davis - ./bootstrap.sh - ./configure - make - sudo make install - cd ../LaCrosse - ./bootstrap.sh - ./configure - make - sudo make install addons: apt: packages: - graphicsmagick - libmotif-dev - libcurl4-openssl-dev - libpcre3-dev - libproj-dev - libdb5.3-dev - libax25-dev - shapelib - libshp-dev - festival - festival-dev - libgeotiff-dev - libgraphicsmagick1-dev - gpsman - gpsmanshp - libwebp-dev - libxpm-dev - os: linux dist: bionic name: "Ubuntu-18.04LTS gcc-9 full-featured w/GraphicsMagick" env: - CFLAGS="${CFLAGS} -Wall -O2 -Wformat-truncation=2 -Wstringop-truncation -Wextra" before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get update -q - sudo apt-get install gcc-9 -y before_script: - export CC="gcc-9" - echo ${CC} - ${CC} --version script: - ./bootstrap.sh - ./configure CPPFLAGS="-I/usr/include/geotiff" - make - sudo make install - cd Davis - ./bootstrap.sh - ./configure - make - sudo make install - cd ../LaCrosse - ./bootstrap.sh - ./configure - make - sudo make install addons: apt: sources: - llvm-toolchain-xenial-7 - ubuntu-toolchain-r-test packages: # - gcc-9 - graphicsmagick - libmotif-dev - libcurl4-openssl-dev - libpcre3-dev - libproj-dev - libdb5.3-dev - libax25-dev - shapelib - libshp-dev - festival - festival-dev - libgeotiff-dev - libgraphicsmagick1-dev - gpsman - gpsmanshp - libwebp-dev - libxpm-dev - os: osx name: "OSX semi-light w/GraphicsMagick" osx_image: xcode12.2 script: - ./bootstrap.sh - ./configure CPPFLAGS="-I/usr/include/geotiff" - make - sudo make install # - cd Davis # - ./bootstrap.sh # - LDFLAGS="-L/usr/local/opt/openssl/lib" ./configure # - make # - sudo make install # - cd ../LaCrosse # - ./bootstrap.sh # - LDFLAGS="-L/usr/local/opt/openssl/lib" ./configure # - make # - sudo make install addons: homebrew: packages: - berkeley-db - graphicsmagick - libgeotiff - openmotif - pcre - proj - shapelib - wget # - mysql # update: true - os: linux dist: xenial name: "Ubuntu-16.04LTS Exercise Configure Options" env: - MAGIC_BIN="/usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/Magick-config" script: - ./bootstrap.sh # - ./configure --without-festival CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-gpsman CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-libcurl CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-libproj CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-shapelib CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-geotiff CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-ax25 CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install # - ./configure --without-map-cache CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install - ./configure --without-graphicsmagick CPPFLAGS="-I/usr/include/geotiff" # - make clean - make # - sudo make install - ./configure --without-graphicsmagick --without-imagemagick CPPFLAGS="-I/usr/include/geotiff" # - make clean - make # - sudo make install - ./configure --without-shapelib --without-graphicsmagick --without-imagemagick CPPFLAGS="-I/usr/include/geotiff" # - make clean - make # - sudo make install - ./configure --without-imagemagick --without-graphicsmagick --without-shapelib --without-map-cache --without-libcurl --without-ax25 --without-libproj --without-geotiff --without-festival --without-gpsman CPPFLAGS="-I/usr/include/geotiff" # - make clean - make # - sudo make install # - ./configure --with-errorpopups CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install - ./configure --with-libgc CPPFLAGS="-I/usr/include/geotiff" # - make clean - make # - sudo make install # - ./configure --with-profiling CPPFLAGS="-I/usr/include/geotiff" # - make clean # - make # - sudo make install ## - ./configure --with-lsb CPPFLAGS="-I/usr/include/geotiff" ## - make clean ## - make ## - sudo make install ## - ./configure --with-postgis CPPFLAGS="-I/usr/include/geotiff" ## - make clean ## - make ## - sudo make install ## - ./configure --with-mysql CPPFLAGS="-I/usr/include/geotiff" ## - make clean ## - make ## - sudo make install - cd Davis - ./bootstrap.sh - ./configure - make - sudo make install - cd ../LaCrosse - ./bootstrap.sh - ./configure - make - sudo make install addons: apt: packages: - imagemagick - libmagickcore-dev - graphicsmagick - libmotif-dev - libcurl4-openssl-dev - libpcre3-dev - libproj-dev - libdb5.3-dev - libax25-dev - shapelib - libshp-dev - festival - festival-dev - libgeotiff-dev - libgraphicsmagick1-dev - gpsman - gpsmanshp - libwebp-dev - libgc-dev - libxpm-dev Xastir-Release-2.2.2/.vimrc000066400000000000000000000014331501463444000154700ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/AUTHORS000066400000000000000000000037261501463444000154260ustar00rootroot00000000000000 Developers and Contributors _________________________________________________________________ Here we attempt to list most of the Xastir developers and contributors who have devoted large amounts of time to making Xastir one of the best APRS(tm) clients ever. Unfortunately we can't devote much time to keeping this list current or adding new contributors. Xastir was originally written by Frank Giannandrea, KC2GJS (was KC0DGE). APRS(tm) is a Trademark of Bob Bruninga Developers and Contributors (in alphabetical order): DK7IN Rolf Bleher HI8GN Jose R Marte A IK0YUP Alessandro Frigeri K2DLS Dan Srebnick KA6HLD Jerry Dunmire KA9KIM Mike Sims KB3EGH Derrick Brashear KB3EHW Reuven Gevaryahu (our resident docs guy!) KC2ELS Jack Twilley KD5AMB Mark Grennan KD6VPE Jim Sevilla KD6ZWR Chris Bell KE4NFJ Gerald Stueve (K4INT) KG4IJB Charles Byam KM5VY Tom Russo N0RPM Jason Godfrey N0VH Jim Chandler N2YGK Alan Crosswell N3NYN Michael G Petry N7IPB Ken Koster N7TAP Olivier Calle N8YSZ Dan Brown PE1DNN Henk de Groot VE3UNW Richard Hagemyer VE6LFM Lloyd Miller WE7U Curt Mills SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used to describe it. So be it. Thanks Tony and Steve! Thanks go to all the people who have made individual contributions to the Xastir project by sending bug-reports, patches, or who have otherwise supported the project. There are too many to list. If you think that you are missing from this list contact the Xastir Development Team at . _________________________________________________________________ Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/CC_OpenStreetMap_logo.png000066400000000000000000000122631501463444000211730ustar00rootroot00000000000000PNG  IHDR'sRGBbKGD pHYs  tIME) dPtEXtCommentCreated with GIMPWIDATxyxTsf$IH JX $A.(^K}JU(zzmz}JXܠ Q [p!{&3G2 /Yss|n߇ JU? pqv1e&%zмhL7ͷ aaa#Aи\VUt:?z=Q?mintob"˲YRu/RϞ7jױvPlk9{\o]Bѐ0vaqцˮ\ĤmK1RSSU&ZJv0<  jAZkA@T*T*U,H$-(%Q$QidI9_ wA~>*^s{K_U$ iƬ97CSo5G˸1n6Obn-ݍWrᖯrvz}*2c2?8Y]x EZݷSju_CJ%2ߡ0H}b-C$P8K`.GVhDmyO%ix$@tL$>oө]RRe? FA-j l%{~ ,>>ZIz@bI[6l fù3jtԯ@|o+N@WkTqѩn*[s^{x| f_Y͸IvNv!no!6.VR'O}lwaÆcG 8/ډF9FV!oSm.RNX,XVIOO`׮]PTTnWεfYytc4 ?@`; B1p8}x9===XVINN555X"f3Ϯ{;R)3'j ^{wݡmǗP˕O$)y,HIˉ#>\N71#D9qGyҥr~~sMMM.O>mF;bUQaa!+VPHIMᵍ`4Ul6mҫΰ(䐒3?}^/>z^B  D~vyt*с)2CV3u NdZ*eS _6/hl,TiG{K'.;V125j5@ ơC;'TWW+淪׽4 6LFuj wjRUY}+8]oIƬܽd)w/YJƬܱ%9nd||^?vd(0j( }?Hd :V_3u&1mtNvL&#:X fKЀb B0Ue+Dqq&\bX(..V(\Į]%՚).(K3:q鵕AמKN_VZSH5L-^ ~Ưׯ`P=@h#Ǣ7@7A t; $)R 不˃"VM">ތ Jwu8zhw\\ |hZ{~ҹ6mVp.0׮u~ T5AA)0]Cee%gXmdddA &{zz< wZF^xxbuG.ܸ"19aMwQg7 (B-P jzz5M m@$#ccT΢O%U$A"EY۶ee,_\/F,e544mvGPaalz/} {uo ֯@OptvҫW3 MMaH`6D׫HIIAj4cьAK:#iʹ aЄyM9j@Gpsm-X|s.c2eJT{{{-..V:477WildeeIff&k֬9k~SAkQIq86TRf3+x/J0 $˫h<.L& 2vsV^z nEAjXc'tq0EDQ_ʄdzk>|_l7qDv{b A/Zδldff8fa%++댶Ç+ѼjJh p &b*** (";;9hX裘FXYitbaʕv\HbF3"AO' Wd-\}\1^HV^0^lSWN8 U7a?:;1 Dw,o6c2;w c<6Vvzꥭ0s8- :b*?oOS[mmm.9O19* DQQ))5N1'V7ɓ}cĉJ:|==]]1}/w1!/#p|l}FRR2 pY•KtwrQ*NzDðwܣbbT{Oc<4AQXXnqƱf͚Swh[I?U_Pc?Vb6),,$++KZ!++c6y8~O1EhbR'NTesqvu!h4 ƥ7{f!n# a,\tM7,`ߞշ̤8ZQH|*ٌ[;_eG0GÇ<3ڂa@CJ9;lX ϭ"HKKb`/fR'Q&.X|Ca6f3:k4w0jezgIlp;W];/ʏau3:~?cGslF_1u7jet:֬^C", ]]]2eL###죽txkdtV'],ܺhQ8y<ȽTF-MlR,0a$fIp4T(JEYg>t/_>$A$ϭ[o A1Ƞ?$Mp(-?.7F&LmS:\~a[߆qxW}x8*T})ݰT{DQBL'>>֬Yd#v]ar ?ĢF*wzA'I0y) t6ӝK}[^hLaMHosX&J(ͫ|٧N0GBT]I5bt=I'@WnMSMZ}7P"{@ 4ie\if#Dٓ1}\}u Ӂd$*.F H?a][g_;'dۙ:m*?ɏyͷ 33M6w?+5,+s|V?&Q}}ᜈg@?v:KV<,Їhg1&.z:ۍǃ/Q%@)]%t$f͙EsS3UUU477zIKK`0: (nj3/x`KV֬^?`dit 42Hy4 eHP{D0)Π;G]}_tׁ$[9{>gƦQeTUN@eJr. xt`0IENDB`Xastir-Release-2.2.2/CC_OpenStreetMap_txt.png000066400000000000000000000036361501463444000210560ustar00rootroot00000000000000PNG  IHDR@UsRGBbKGD pHYs  tIMElޫtEXtCommentCreated with GIMPWIDAThZ_Ho~涖d5M)DtPhlnv";PP wAي(`H! Vʈ9&|?}yk{ de( # 2_($Mٓ!K"NG&''I}}=4_NRb~Jrss֭[Imm-q8)~N''D.v XBrssI^^r QD"ZMFFFڦ%3d`` eիW6lBD<EgggHE$ݻwq[SS?tX,bp)y ߿1::EA?Ǐg4 ~?~?4 X?|B˅X,˅={`||||1lS|BJD2Ld]g{x<DBz5t1X,F4ӧqm̙3"!P91ArQc˅#GѣGĉ4^ܹ]va۶mB,쫫|2󑝝 ٌjm?!QYY"Ю>B f QsgϞh4B*B" `0-- X7%h4 N±cbhݍF{,\.\.OyP. ՞yj!XwIm:i AAz\t߸q|XXX@gg'Ν;G5͘_bf\9ϟPH$j|RrFݍ8cP(Ly-lWR)>Lp58uJ%v؁V?}ԸϞ=K+ ۷߿g5^[[P(G+++D4^?PXXH7b߿0ɱbqۏd2hjjm"U8G* S^B0177/BRszO;QKKK)f? "b1%H&D1l6J%>}{&NFXmQPP@݋M \9'j=mlH$G.xT*+m;_}=oJn˘իWj#eɓ'j_|IkCjSVyʱ~r;( !FPPn݂^ &''a6 _ h[LlgaxxX 33304Asq(hAEElقS >;[ "PUURp8pQH$䠹^pAqݨH_I$L&L&b ^| JX JݞC{GGi}zoo/uVa4_pMHҔSʁ˖n|&ۋ/~B4Asq9;$C,# 2 3/_jE]IENDB`Xastir-Release-2.2.2/CONTRIBUTING.md000066400000000000000000000513411501463444000166030ustar00rootroot00000000000000# Contributing to the Xastir project Hello possible new developer, and welcome to the Xastir project! ## Ways to contribute There are many ways to contribute to a project, and not all mean that you have to write code. * You can ask and answer questions on the Xastir mailing list * You can report bugs * You can fix bugs * You can add or modify features in Xastir ### Asking and answering questions Please subscribe to our mailing list as listed on the official Xastir web site, http://xastir.org/. We would prefer it if you would not use Xastir's git hub issue tracker just to ask questions, as this is not the ideal forum and doesn't reach the full Xastir user community. Your best bet is to get your question in front of as many users' eyes as possible, and the mailing list is the way to do that. Once you're confident enough with Xastir to be answering users' questions, your presence on the mailing list will naturally allow you to see and answer those questions, too. ### Reporting bugs If you believe you might have found a bug, your first step might be to ask about it on the mailing list to see if it's really a bug, if you're making a mistake, or if it's just a difference between what you expect and what the code actually does. If you are reasonably sure that you have found a real bug and wish to report it, open an issue on the Xastir Github repository at https://github.com/Xastir/Xastir. Realize that Xastir is entirely a volunteer effort largely moved forward by very busy people, and your bug might not get fixed in short order, and it might not even get fixed unless you fix it yourself. ### Fixing bugs Another way you can contribute is to fix bugs yourself and submit pull requests to the group for your changes to be added to the main code base. You could fix bugs that you find yourself, or could look through the existing list of issues on Github and pick one to fix. If you do this, you will want to follow the procedure below that describes how to submit code changes for review and acceptance. ### Adding or modifying features in Xastir Maybe Xastir is lacking some feature you really want, or you really would like to make some other feature of Xastir work differently. The first step here might be to start a discussion on the mailing list to see if other users like your addition or modification before pressing ahead with it, but you could always just go ahead with the development and offer it as a suggested change through the pull request mechanism. Asking on the mailing list first is more likely to get a faster response when your pull request shows up.. ## General guidelines for contributing code In order to get contributed patches accepted more easily by the Xastir developers: * Read "Developer Guidelines and Notes" in the "HowTos" section of Xastir's Wiki (http://xastir.org). Make sure to follow the formatting and indentation rules, and in particular the tab format (spaces, not tabs). If you don't like some of the formatting rules, abide by them anyway for consistency. Some of the developers don't like some of the formatting rules either, but consistency is more important than ideas we might have of coding style! * Check the Xastir issue tracker: http://github.com/Xastir/Xastir/issues You need a GitHub account to create new issues, but this is free. This is one of the best places to see what needs to be worked on, and to see if anyone else has had a similar idea. * Check with the Xastir-Dev list first to see if anyone else is working on that particular idea or section of code. * Verify on the Xastir-Dev list that your idea has some merit and chance of being accepted before you put your valuable time into the patch. * Make sure you're willing to abide by the GPL license with respect to your patch. * Use as generic C as possible, and comment what you've done, in English please! * Keep in mind that Xastir runs on multiple operating systems, so code for that. Some #ifdef's may be required in order to make it work for the various operating systems. * Xastir can be run in multiple languages, so code for that. If any user text is added, make sure to add language strings for them to the language files. If you don't know a particular language, add it to all of the language files in English. It will be translated by others later. ## Contributing code changes to the project While it is always possible to create a patch set and email the result to Xastir developers, this is no longer a desirable way to proceed. The preferred method of contributing source changes is through GitHub "pull requests." (See https://help.github.com/articles/about-pull-requests/) In a (rather large) nutshell this process goes like this: * Log in to Xastir's github repo at https://github.com/Xastir/Xastir.git and click the "Fork" button. This will create a copy of the repo that you have full control of. Once you have created a fork, here's a general approach you can use: * Clone your repo: cd git clone https://github.com/youruserid/Xastir.git cd Xastir The result of this step is that you will have a primary remote named "origin" that points at your forked repository. It will also have checked out the default branch, which in the case of the Xastir repo is just the "master" branch. * Add the official repo as a second remote called "upstream": git remote add upstream https://github.com/Xastir/Xastir.git Now your local repo knows about two remote repos -- yours, and the official project repo. Now make git sync to this remote, too: git fetch upstream * Create a topic branch to work on: git checkout -b * Do all your work while checked out in this branch. As you work, use git add/git commit commands to save your changes in logical chunks. Staging your changes in multiple commits this way helps keep the project history readable. See the notes below regarding formatting of commit messages, please. * When you have finished your work (or when you think you have) and are ready to ask for it to be reviewed and accepted, you will need to publish your changes to GitHub and initiate a pull request. * First, make sure your repo has an up-to-date master branch: ``` git fetch upstream # This fetches changes in the official rep git checkout master # go back to the master branch git merge upstream/master # brings your local master up to date git push origin # this brings your GitHub fork up to date git checkout # get your branch back ``` * Always rebase your feature branch so that it branches off of the current head of the master branch: ``` git rebase master # makes sure that your branch is based # on the most recent version of master ``` * Now publish your branch in your GitHub fork (your "origin" remote). git push -u origin Now your changes exist on the named branch in your GitHub repo, and may be shared with others. NOTE: If you have refrained from touching the code on the master branch, the merge of upstream master will always be as simple as shown here, with no conflicts possible --- all you're doing is grabbing what others have done while you were working. In times of great activity on master (there are seldom such times) it is possible, though, that the rebase operation can show conflicts between upstream changes and your changes that you will have to fix yourself. Resolving these conflicts requires editing your code, fixing the conflict markers, then doing additional git add/git commit operations and a third command to tell git rebase to continue after the conflict resolution. Please see the Pro Git book at https://git-scm.com/book/en/v2 for guidance should this happen to you. * A good practice at this point, before you've asked the Xastir developers to merge your work, is to send an email to the xastir-dev mailing list and ask others to test out your work. They can easily check out your fork and make sure there are no hidden issues you hadn't detected. See below for a suggestion of the easiest way to check out other people's topic branches. * Now you are ready to ask for your code to be reviewed and accepted. * Open your web browser to your GitHub repo for your fork at https://github.com/youruserid/Xastir.git. * Using the pull-down menu, select your feature branch name. * To the right, you'll see a button marked "Pull request." Click it to begin the process of creating an automated request to pull your code into the main repo. Fill out all of the form and create a pull request. * A member of the Xastir project will review your changes and comment on the pull request. If the changes are straightforward, your request may be accepted directly, or you may be requested to make further changes. * If you need to add more commits to address concerns brought up in the review of your pull request, just make them on your topic branch and push them again: ``` git checkout git add git commit git push ``` Since you have already associated your topic branch with your forked remote in a previous step, it is no longer necessary to say "-u origin branchname" here. * If this goes on for very long, it could come to pass that master has changed again. If so, you may need to rebase and force-push your topic branch. Ideally, you should endeavor to make your pull requests as easy to test and review as possible, so that it doesn't take forever for developers to get around to testing them and merging them. There are lots of guidelines out there about how to make good pull requests. Please read https://github.com/blog/1943-how-to-write-the-perfect-pull-request for one such article. There is also a pretty nice tutorial on how to do your first pull request at https://www.thinkful.com/learn/github-pull-request-tutorial/ ## Git Commit Message Format Git commit messages need to be in a certain format to make the best use of the "git log" commands. In particular the first line needs to be 50 chars or less, then a BLANK LINE, then a detailed commit message. See this link for more info: http://chris.beams.io/posts/git-commit/ ## Checking out other people's work It was mentioned above that sometimes it is a good practice to ask other people to check out your code changes before a pull request is opened. This section contains some simple ways for Xastir users and developers to check out code in other people's repos with a minimum of fuss. Say user "sumgai" has a topic branch named "sumnufeetyur" in a fork of Xastir at "https://github.com/sumgai/Xastir.git". You want to pull those changes and test them out. This can always be done just by cloning the entire fork, but that is not necessary, since most of the fork is a straight copy of the official repo. You can instead just grab sumgai's changes: * I'm assuming you're already checked out from the master branch, but let's make sure: git checkout master * In your regular Xastir clone directory, create a new branch to hold sumgai's work, and switch to it: git checkout -b sumgai-sumnufeetyur When you do this, all you've done so far is to create a new name for a copy of master. * Now pull sumgai's branch into yours: git pull https://github.com/sumgai/Xastir.git sumnufeetuyr Your sumgai-sumnufeetyur branch will now match sumgai's sumnufeetur branch exactly. This does generally work best if sumgai has kept his branch rebased off of master, which is why we recommend that approach. * You can now build the code and test it as usual. * When you're done testing sumgai's code, you can go back to the unmodified Xastir just by doing "git checkout master," and rebuilding the code. If you no longer want to keep a copy of sumgai's work around, you can delete the branch with git branch -D sumgai-sumnufeetyur **Note to developers**: The process of doing this checkout of others' branches is exactly what GitHub recommends as the first steps to resolving pull requests manually through the CLI instead of through github's web interface. ## Debugging hints Xastir is a multi-threaded and multi-process application. It uses both threads and forks to do it's work. You must have a debugger that is capable of following these kinds of twists and turns in a program. Many older versions cannot. ### Old notes on using GDB with Xastir *The notes in this section were taken from an old email thread and were written by Tom Russo* According to everything I can find about GDB, debugging of multithreaded apps has been supported in gdb for some time, and are certainly supported in gdb 6.x. For the last couple days I've been running xastir inside gdb instead of at the command prompt --- perhaps I won't keep forgetting to start it with -t now, and when it crashes I'll be where I need to be. This is possibly an option for you, too, if you're seeing segfaults frequently enough and can't solve the core file question. Try this: gdb /usr/local/bin/xastir > run -t *The ">" above is a gdb prompt --- don't type it!* When it crashes, it'll pop you right out into the debugger, whether a core file was created or not. You could then view the active threads: info threads and get a stack trace of where the crash happened: where You could also probably list the code near where the crash happened: list If you send the output of those three commands to the xastir-dev list then it might help us narrow down the causes. ### Other old debugging notes *This section was also taken from an old email chain, and was written by Curt Mills* Note that the meaning of the "-t" command-line flag has been reversed *[Ed. Note: from what it was in earlier days of Xastir]*. "xastir -?" should show the change once you compile it. This means that we'll do core dumps by default upon segfault instead of using the internal Xastir segfault handler. We've also re-enabled the "-g" compile option for GCC so that debugging information will remain embedded in the executable (unless you strip it). This should aid the development team to debug problems. > Also, I cannot find anything in man bash that talks about core > dumps nor segmentation faults. Seems like some stuff we're just supposed to know. _How_ we're supposed to know I don't know either... ;-) Perhaps that last bit about SUID/SGID might be a clue: There are often exceptions to the rules for SUID/SGID programs. Try _not_ setting Xastir SUID (if you're not using AX.25 kernel networking ports that is) to see if you get a core file. Can you send a SIGSEGV to the running process and make it dump? I just tried this and I'm not getting a core file either. Ah, I see in the "man bash" page: ulimit -a All current limits are reported This gives me: core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) unlimited cpu time (seconds, -t) unlimited max user processes (-u) 6139 virtual memory (kbytes, -v) unlimited So... Looks like I need to set "ulimit -c" and try again: ulimit -c unlimited Now when I do "kill -11 " I get this: [1]+ Segmentation fault (core dumped) xastir and this: -rw------- 1 archer users 12320768 2006-02-02 09:31 core.7586 I just added "ulimit -c unlimited" to my .profile. For what it's worth, if Xastir has SUID permission bit set (4755) I don't get a core dump, but if it is reset I do (0755). I can invoke ddd like this (it uses gdb under the hood): ddd /usr/local/bin/xastir core.7586 & or gdb like this: gdb -c core.7586 /usr/local/bin/xastir Once you have the program and core file loaded into the debugger you can display a backtrace to see where the program died. In the case of ddd, it's Status->Backtrace, then you click on one of the entries to make the source code window display the exact location. Another good debugger to try is "UPS". Another note about core files: Sometimes they get written where you don't expect. I just had one appear in ~/.xastir/tmp, so if you think you should have a core file and can't find it, try: find . -type f | grep core The core file may be written to a directory that Xastir is currently in, instead of where you started Xastir from. ### Customized debugging builds Sometimes it is helpful to build xastir with specialized compiler options to aid in debugging. For example, if you're trying to hunt down elusive segfaults, and you're using GCC, it might be wise to build with "-O -g -fno-inline" to prevent the compiler from optimizing quite so vigorously; aggressive optimization can sometimes lead to the debugger saying the code died on one line when in fact it's happening somewhere else. To build with custom CFLAGS like this, just tell configure what you want CFLAGS to be: mkdir -p build cd build ../configure CFLAGS="-O -g -fno-inline" Naturally, unless you're using build directories separate from the source directory (see below under "Segregating specialized builds"), you need to build every file after changing configure like this, so do a make clean before building: make clean make make install Remember not to "make install-strip" when trying to do debugging builds, or your core files will not have debugging symbols in them and it will be harder to get useful information out of the debugger. ### Segregating specialized builds The automake/autoconf setup of xastir makes it easy to maintain several different builds of the code without having to clean out the directory and rebuild every time. One does this with "build directories" and executable suffixes. To use this capability, make sure you're starting with a completely clean source directory. In the directory where you normally do your "git pull", do a make distclean. This will remove anything that configure created as well as anything that make created. From this point forward, you don't build xastir in the source code directory anymore. Make an empty directory somewhere --- this will be your build directory. I put my build directories in parallel with the source code directory. So my tree looks like this: XASTIR-DEV | +----/Xastir (source directory) | +---/build-normal | +---/build-debug and so on. Some developers put their build directories inside the Xastir tree instead. It doesn't matter, but does change how you invoke configure (you have to use the correct relative path to configure below). So I would do: cd XASTIR-DEV mkdir -p build-normal In the build directory, you run configure using the path to the configure script: cd build-normal ../Xastir/configure make make install The configure script uses the path that you gave when you ran it to figure out where to find the source code. The beauty of this is you can make a second build without doing a make clean: cd XASTIR-DEV mkdir -p build-debug cd build-debug ../Xastir/configure --program-suffix="-debug" CFLAGS="-O -g -fno-inline" make && sudo make install This will build a second binary called "xastir-debug" and install it, but because you've done the build in a separate directory, your normal compile is untouched. cd ~/XASTIR-DEV/xastir git pull cd ../build-normal make && sudo make install cd ../build-debug make && sudo make install will update both of your builds. I also use this technique to share a single xastir source tree over NFS, building the code for multiple operating systems in separate build directories. (log in to CYGWIN machine, mount NFS directory) cd /mounted/directory/XASTIR-DEV mkdir -p build-cygnus ../Xastir/configure make && make install It can also be used to maintain specialized configurations, for example a build with "rtree" disabled, a build with map caching disabled, etc. This is a good development trick to keep yourself honest --- make sure you can still build all your custom builds when you've done a large hacking run, and want to check if you have broken things inside ifdefs. Doing that without build directories requires a huge number of configure/make/make distclean cycles. ## More? Anything else? Let's hear about what's still confusing or needs to be expanded in this document. Thanks! APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/COPYING000066400000000000000000000431271501463444000154100ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Xastir-Release-2.2.2/COPYING.LIB.LESSTIF000066400000000000000000000612611501463444000171240ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Xastir-Release-2.2.2/ChangeLog000066400000000000000000034563021501463444000161350ustar00rootroot000000000000002012-11-02 * ChangeLog Xastir project stopped updating the ChangeLogs in 2012, and until then the changelog was generated manually from CVS history. The project no longer uses CVS, and now relies on git history to show the history of the project. Please see the output of "git log" if you want to know what has happened to the code and why, and add the "--name-status" option if you want to know what files were changed. 2012-11-01 11:57 we7u * .cvsignore, AUTHORS, ChangeLog, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.CYGWIN, README.Contributing, README.OSM_maps, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, callpass.1, changes.txt, configure.ac, install-xastir, testdbfawk.1, update-xastir, xastir.1, xastir_udp_client.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/OSM_Cloudmade_administrative.dbfawk, config/OSM_Cloudmade_highway.dbfawk, config/OSM_Cloudmade_natural.dbfawk, config/OSM_Cloudmade_poi.dbfawk, config/OSM_Cloudmade_water_and_coastline.dbfawk, config/arealm.dbfawk, config/areawater.dbfawk, config/cousub.dbfawk, config/cousub00.dbfawk, config/edge.dbfawk, config/featnames.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsc_ddmmyy_09.dbfawk, config/nwsc_ddmmyy_09b.dbfawk, config/nwsc_ddmmyy_10.dbfawk, config/nwsc_ddmmyy_10a.dbfawk, config/nwshzddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzddmmyy_09.dbfawk, config/nwsmzddmmyy_11.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddap12.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsozddmmyy_09.dbfawk, config/nwsw_ddjn12.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsw_ddmmyy_09.dbfawk, config/nwsw_ddmmyy_10.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwsz_ddmmyy_09.dbfawk, config/nwsz_ddmmyy_10.dbfawk, config/nwsz_ddmmyy_10b.dbfawk, config/nwsz_ddmmyy_10c.dbfawk, config/nwszoddmmyy.dbfawk, config/pointlm.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/stored_track.dbfawk, config/tabblock.dbfawk, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tl_2009_nn_county.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.d72_d710, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.d72_d710, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/BUILDRPMS, scripts/Coordinate.pm, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/UIView2XastirLog.pl, scripts/Xastir_tigerpoly.py, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable, scripts/example_objects.log, scripts/geopdf2gtiff.pl, scripts/get-fcc-rac.pl, scripts/get-gnis, scripts/get-maptools.sh, scripts/get-pop, scripts/get_shapelib.sh, scripts/kiss-off.pl, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl, scripts/object2shp.pl, scripts/pos2shp.pl, scripts/slideshow.pl, scripts/test_coord.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/track-get.pl, scripts/waypoint-get.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.h, src/awk.h, src/bulletin_gui.h, src/color.h, src/database.h, src/datum.h, src/db_gis.h, src/dbfawk.h, src/draw_symbols.h, src/fcc_data.h, src/festival.h, src/fetch_remote.h, src/geo.h, src/gps.h, src/hashtable.h, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.h, src/igate.h, src/interface.h, src/io.h, src/lang.h, src/leak_detection.h, src/list_gui.h, src/macspeech.c, src/main.h, src/map_OSM.c, src/map_OSM.h, src/map_cache.h, src/maps.h, src/messages.h, src/objects.h, src/popup.h, src/rac_data.h, src/rotated.h, src/rpl_malloc.h, src/shp_hash.h, src/snprintf.h, src/symbols.h, src/tile_mgmnt.h, src/track_gui.h, src/util.h, src/wx.h, src/x_spider.h, src/xa_config.h, src/xastir.h, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating the Copyright notices. Bumping revision to 2.0.2 in preparation for stable release. 2012-10-22 17:37 tvrusso * src/interface.c: Tidy up a comment and remove some now-commented-out code. At this point, everything that I had hoped to be in the next stable release is in place. 2012-10-22 16:59 we7u * src/: interface.c, interface_gui.c, xa_config.c: The rest of the code to implement "TNC Delay" for the serial tnc types of interfaces. This is most useful with a KAM TNC. Note that one can hand edit the value up to 9,999,999 us in the Xastir config file, but pressing the togglebutton will enter 1,000,000 us by default. Thanks for that idea Tom! 2012-10-22 16:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.h, src/interface_gui.c, src/xa_config.c: Implementing the GUI and save/restore portions of the "Add Delay" togglebutton for the three types of Serial TNC interfaces. The back-end code which actually uses the button value hasn't been coded yet. 2012-10-11 11:25 we7u * scripts/get-fcc-rac.pl: Fixing the RAC database fetch/install. 2012-10-11 11:09 we7u * scripts/get-NWSdata: Updating for the current set of NWS filenames. 2012-10-11 10:58 tvrusso * symbols/: Makefile.am, icon.png: Add a PNG icon for Xastir, converted from the icon.xbm file in the src directory. I did this because I generally create a desktop shortcut to Xastir on my laptop, and as of the most recent version of Gnome I am unable to use an xbm to do so, but a PNG works. This new icon is installed into ${prefix}/share/xastir/symbols and may be used by the user to define a custom icon for a desktop shortcut. Remember, the Xastir project does not directly support distro-specific (or desktop-specific) packages, but we do want to make sure that those who generate such packages have the tools and files they need to do so. 2012-10-10 15:18 tvrusso * help/: help-Dutch.dat, help-Portuguese.dat: The Dutch and Portuguese help files were actually not in Dutch or Portuguese, but English, and were woefully outdated. Copied the current English helpfile into those two, so at least the only thing that's wrong with them would be that they're not in the language they're supposed to be. 2012-10-10 15:16 tvrusso * ChangeLog, help/help-English.dat: Regenerate ChangeLog from CVS logs. Add a "what's new in Xastir 2.0.1" section to the on-line help. Looking over our non-English helpfiles, it is clear that it has been a very long time since anyone has translated the help into other languages. The German help file hasn't been updated since Xastir 1.2, Spanish hasn't been updated since 1.1, and several languages have help files, but they're still in English. 2012-10-10 14:46 tvrusso * scripts/cvs2cl.pl: Add cvs2cl script (from http://www.red-bean.com/cvs2cl/cvs2cl.pl) to our tools. This generates a ChangeLog from cvs commit logs. 2012-10-07 10:41 tvrusso * configure.ac: Move probe for proj to before probe for shapelib. When using internal shapelib, the probe checks whether "use_proj" is "yes", but until this commit, use_proj was unset until *AFTER* the shapelib probe. This led to warnings from the shell about unary "=" in a test (if test $use_proj = "yes") 2012-10-05 13:19 we7u * scripts/get-NWSdata: Updating a file or two, and changing the order of FILE1 and FILE2 in the definitions to match the order they are on the NWS web pages. We will need to check this file again on/after Oct 11 as several of the filenames change then. 2012-10-05 12:56 we7u * scripts/get-fcc-rac.pl: Changing the RAC address to one that currently works. The old site looks to have a brand spanking new version of Drupal on it, so they may have messed up the rest of the machine temporarily (or permanently). 2012-09-26 21:15 tvrusso * acinclude.m4, configure.ac: Remove some unnecessary macros from the probes for Berkeley DB. The code in acinclude.m4 to probe for Berkeley DB was copied from another project, and included a macro that tried to guess how to add a "runpath" to the build. On most systems this is either -Rlibrarydirectory or -Wl,rpath,librarydirectory, but the macro in our acinclude.m4 was in fact correctly identifying the way to do it ONLY on Linux, and then discarding the information anyway. Thus, this was a no-op on Linux, and was wrong elsewhere (but also a no-op). The technique used to do the probe also broke when the compiler was clang, but again, to no effect because the result was discarded anyway. SO since the result wasn't used, why probe it? I have removed the macros and replaced the use of "XASTIR_ADD_LIBRARY_TO" with a simple shell variable assignment. While I was at it, I removed the deprecated two-argument call to AM_INIT_AUTOMAKE. It has started causing newer versions of automake to complain, and has been deprecated for some time. 2012-09-23 09:19 tvrusso * src/: db.c, fcc_data.c, igate.c, interface.c, location_gui.c, main.c, map_OSM.c, map_WMS.c, map_cache.c, map_geo.c, map_shp.c, map_tiger.c, maps.c, messages.c, messages_gui.c, objects.c, rac_data.c, track_gui.c, util.c, xa_config.c, xa_config.h: Big commit for a little, insidious threading problem. xa_config.c provides a function called get_user_base_dir(char*) that returns a pointer to a string that is the concatenation of the base configuration directory for Xastir (usually ~/.xastir, but selectable by the user with a command line option or environment variable) and the argument. This function was highly thread-unsafe --- it kept a local static char array that it used to build the concatenated string, then returned a pointer to the local array. This function was used in multiple threads, meaning that one thread could start scribbling into the static array while another was writing into it. I first tried to fix this by adding a mutex that locked the writes for all but one thread at a time, but that wasn't even good enough, because after unlocking the write mutex another thread could write into the buffer while the first thread was reading the results just produced. The result of this mess was a highly unpredictable tendency for Xastir to start producing corrupted paths from this function. This would show up most often on multi-core machines with threading libraries that let threads run simultaneously on different cores, but it could show up on single-core machines with just the right scheduler. It is revealed most easily by enabling multiple logging options (e.g. TNC logging, NET logging, WX logging) and PNG snapshots all at once. In testing, I found this sufficient to produce corrupted file paths in an hour or so. I'm somewhat surprised that nobody has ever reported this issue, because I've been seeing it for ages. This commit replaces the original get_user_base_dir implementation with one that requires the caller to provide its own buffer, and completely removes the use of the static buffer. More than 200 calls to get_user_base_dir had to be modified, but some simplifcation was also possible --- I was able to replace a few usages like this: xastir_snprintf(dest_string, sizeof(dest_string), "%s", get_user_base_dir("tmp")); with: get_user_base_dir("tmp", dest_string, sizeof(dest_string)); get_user_base_dir still returns the pointer to the destination string, so it can still be used as an argument to log_data or xastir_snprintf where necessary. I also replaced several wasteful uses of the function. There were places where get_user_base_dir was being called repeatedly with the same argument many times in a single function. I replaced this usage in many cases with a single call to store the answer in a local buffer, and use that repeatedly. Since implementing this change I have seen Xastir run without producing a single corrupted path, even with TNC, NET, and WX logging and PNG snapshots turned on. 2012-09-21 18:32 tvrusso * configure.ac, src/main.c: Ifdef out the hack added to main.c to deal with the broken Xorg-server 1.7.5. This server version had a bug that interfered with all motif programs, causing them to grab the cursor and never release it when a context (pop-up) menu was created. The bug was promptly fixed, but not before several distros locked in version 1.7.5 as their supported version. The workaround ungrabs the cursor, but has the annoying side-effect of making the user hold down the button that brings up the menu, rather than allowing a quick click to access it. This commit puts the hack into an ifdef, and enables the user to select the workaround by adding "--with-xorg_175_workaround" to the configure line. The default behavior is now to NOT use the workaround. The workaround and configure.ac code to enable it should be removed completely in one release cycle. Xorg-server 1.7.5 is long gone, and keeping this code around is a nod to the fact that some people do not upgrade for years. One more release cycle should be enough to forget this mistake ever happened. 2012-09-20 22:11 tvrusso * src/map_OSM.c: Patch from Tom Hayward (KD7LXL): This patch fixes an issue in the OSM tile download loop. If a tile is 404, 403, or any other error that doesn't return a valid image, imagemagick (or gm) puts the error info in &exception. Subsequent iterations read &exception, note the error, and fail to composite any further tiles. This patch adds GetExceptionInfo() to the end of the loop, so subsequent iterations do not start off with error info in the exception struct. 2012-09-19 07:56 tvrusso * Davis/src/db2APRS.c, LaCrosse/src/open2300db2APRS.c: Make sure to include before using umask(), to avoid compiler warning about implicit declaration. 2012-09-14 13:57 tvrusso * config/tnc-startup.kam, src/interface.c: Definitive fix for KAM TNCs. The KAM apparently does not go into converse mode if one sends "K\r" and immediately sends the stuff you want to go into the converse. It requires a tiny delay between the command to go into converse mode and the data. I have inserted a 50ms delay after sending the converse command, which should be insignificant enough that nobody will need it to be a configurable option. This fix has been confirmed to end the problems with KAM TNCs, and the 50ms delay was the smallest delay tested. Also commented out two commands in tnc-startup.kam that do not apparently exist in the KAM. 2012-09-08 15:07 tvrusso * Davis/src/db2APRS.c: Reverting my last change to the Davis Meteo->APRS glue program. This is in response to testing by Dean Groe, who is so far the only person on the xastir mailing list who has fed back any information about the behavior of the code after my last commit. Turns out that Meteo does not appear to put "Total Rain" (rain since station reset) into the database in the "raintotal" field, it appears to put "rain since midnight" there, i.e. "total rain for today." This is not what Xastir means, since it has a separate spot for "today's rain." Thus, it is pointless to be sending the extra data to Xastir, because it is a duplicate of something else we already have. I am changing only the Davis database glue program, and leaving in place the LaCrosse changes --- LaCrosse stations *do* maintain their own record of "total rain" and open2300 does put that data into the database. It's just Meteo that doesn't. 2012-08-31 16:39 tvrusso * Davis/configure.ac, Davis/src/db2APRS.c, LaCrosse/src/open2300db2APRS.c, src/wx.c: Fix for Davis and LaCrosse weather stations. Neither of the two "db2APRS" programs for these stations provided "total rain" (rain since wx station reset), and thus Xastir would show a blank in the Own Weather Data dialog box for this. Further, LaCrosse weather stations don't report rain-since-midnight, and by not having total rain available, Xastir isn't able to compute the missing datum. This commit does three things: adds total rain to the string that db2APRS and open2300db2APRS send adds code to Xastir to parse the new bit of data adds code to Xastir to compute rain-since-midnight if total rain is available AND rain-since-midnight is not sent from the wx station. WARNING: THE CODE FOR db2APRS has NOT been tested except to assure that it compiles cleanly. I have no Davis weather station to test it on. The LaCrosse code runs correctly. 2012-08-26 11:34 tvrusso * INSTALL, README.Getting-Started: Update documentation to reflect some changes in GPSMan and GPSManShp. 2012-08-26 11:28 tvrusso * src/main.c: Current versions of gpsman and gpsmanshp now require "Shapefile" and "dim=2" instead of "Shapefile_2D" For quite a long time the gpsman maintainer kept backward compatibility, but it's gone now. This commit resolves issue http://sourceforge.net/tracker/?func=detail&aid=1820056&group_id=45562&atid=443271 in the sourceforge bug tracker. 2012-08-26 11:11 tvrusso * acinclude.m4: Remove bashism from configure process, per sourceforge bug https://sourceforge.net/tracker/?func=detail&aid=3422711&group_id=45562&atid=443271 2012-08-25 09:38 tvrusso * src/: awk.c, bulletin_gui.c, color.c, datum.c, db_gis.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, fetch_remote.c, geo-client.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, main.c, map_OSM.c, map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_pop.c, map_shp.c, map_tif.c, map_tiger.c, messages.c, messages_gui.c, objects.c, popup_gui.c, rac_data.c, rotated.c, rpl_malloc.c, shp_hash.c, snprintf.c, sound.c, testdbfawk.c, tile_mgmnt.c, track_gui.c, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, xa_config.c, xastir_udp_client.c: update neglected copyright dates. Notably, update the one that shows up in the Help->About dialog. 2012-08-22 18:05 tvrusso * help/help-English.dat: Update help file to reflect recent change to "Serial TNC with GPS on AUX port" interface type, documenting the 'Send Control-E to get GPS data?' checkbox. I can only update this in English. Translations requested for our other supported languages. 2012-08-22 17:41 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface_gui.c, src/main.c: Remove a horrid work-around of some bad behavior of Xastir with Kenwood D7* radios with attached GPS. Back in 2006, several Xastir users noticed that when Xastir was attached to a Kenwood D700 (and other Kenwood APRS radios) using the "TNC with GPS on AUX port" interface type, every time Xastir tried to transmit the TNC would reply with an "Eh?" error when sent the MYCALL line that precedes a posit. We realized that there must be some kind of junk in the TNC buffer that was causing the MYCALL line to not be recognized. In some cases, this had bad consequences, especially if no previous MYCALL had succeeded --- the result would be that the TNC would transmit using the default MYCALL, "NOCALL". Since we couldn't for the life of us figure out what the junk in the buffer was, we kludged: Before sending MYCALL, Xastir would send a carriage return, letting the "eh?" error happen where it had no consequence. This was a horrid kludge, as it just swept the real problem under the rug. The real issue is that "Serial TNC with GPS on AUX port" was written to support devices like the Kantronics KPC-3+, which requires that Xastir send a Control-E to the TNC in order to poll it for GPS data. This is how the KPC-3+ multiplexes the output serial port --- normally it sends packet data to the serial port, but immediately after receiving a Control-E from the connected computer, it sends one NMEA string from the GPS instead. The Kenwwood radios stream the GPS data and packet data together all the time, and not only do not require a Control-E to switch between them, they don't even read the Control-Es. The "Eh?" errors from the Kenwood TNCs were it complaining that MYCALL was preceded by all those Control-E characters that Xastir had been sending since the last transmit. This commit adds a configuration option to the Serial TNC with GPS on AUX port set-up dialog so that one can turn this control-E feature on and off as appropriate. THIS HAS USER-VISIBLE IMPACT FOR ALL KENWOOD USERS: If you are currently using Xastir with a Kenwood radio, after doing this update you MUST open your interface property dialog and de-select the 'Send Control-E to get GPS data?" check box. If you do NOT take this step, you will begin seeing the old "Eh?" problem on your TNC, and may well transmit your posit as NOCALL. This may seem an annoyance, but really, this is the fix that we should have put in place six years ago. 2012-08-14 15:14 tvrusso * src/db.c: Fix two instances of a logical AND being used where a bit-wise AND was intended. In this case, the test was supposed to be checking that a station posit was not a third-party packet, but was improperly doing flag && ST_3RD_PT instead of flag & ST_3RD_PT. This impacts ONLY speech-enabled band opening alerts. It is unlikely that anyone was even using these. I found this error only because clang spits out warnings about it. The specific warning is that one is attempting to do a logical AND with a constant value (which is more likely an error than intentional). 2012-08-13 10:22 tvrusso * src/: database.h, wx.c: EXPERIMENTAL COMMIT FOR TESTING PURPOSES. This commit modifies the weather station code so taht stations which provide 1-hour, 24-hour, and since-midnight rain rates (e.g. Davis through Meteo and db2APRS, LaCrosse, and Davis APRS Data Logger) do not have those station- provided data overwritten by Xastir when it tries to recalculate these quantities from "total rain" (i.e. total rainfall since the weather station was reset). The Davis Meteo/LaCrosse code does not even provide "total rainfall" information (though the database they access does in fact have this information), and the APRS Data Logger does not provide total rainfall. All three provide per-hour and 24-hour rain data, and the Data Logger provides rain-since -midnight. What this code does is add a flag to the WeatherRow structure that is set to 1 by stations that provide total rain, and to zero by stations that provide the rate data instead. In "cycle_weather", the three rate strings are only overwritten if the flag is 1, and are left as the station set them if the flag is 0. This should address issues of transmitted rain rates being completely incorrect for Davis and LaCrosse stations. Needs a lot more testing to assure that there is no impact on other stations. This code should result in no change in Xastir's behavior for any station other than Davis or LaCrosse. 2012-08-08 19:19 tvrusso * src/: main.c, xa_config.c: Patch by Tom Hayward. This commit allows the "posit interval" slider to go all the way to zero. If zero, Xastir will not emit timed beacons. It also adds a SIGUSR2 signal handler. If Xastir receives a SIGUSR2, it will beacon immediately. This commit provides all the functionality requested by David Ranch on the Xastir mailing list in this post: http://lists.xastir.org/pipermail/xastir/2012-August/020936.html 2012-07-27 12:58 tvrusso * src/: interface.c, interface.h: Remove commented-out, hard-coded choices of 'conv' and 'k' to put a TNC into "converse" mode. The Interface Properties dialog now allows a user to specify this at run time, and the presence of this commented-out code was confusing some users into thinking they still might need to edit source code to change it. 2012-07-24 17:17 tvrusso * LaCrosse/weatherdump.sql: Modify mysql database for LaCrosse to support more digits of precision for wind direction and other data that can exceed 99.9. "decimal(3,1)" means 3 digits with one past the decimal, i.e. +/-99.9. It was being used for fields that could take values well outside this range. I know that in at least one prior incarnation, this usage accepted 3 digits to the left of the decimal, but now it doesn't. My weather station has been misreporting wind direction ever since I did a major overhaul that required re-loading the mysql data from a dump. 2012-07-10 14:02 we7u * Makefile.am: Tweaking the URL for the cycle map for OSM (shows contours). 2012-07-05 11:53 tvrusso * src/: igate.c, messages.c: Silence some warnings that showed up when building with CLang instead of GCC. One (in igate.c) is just a misuse of "debug_level && 1024" instead of "debug_level & 1024), and the changes in messages.c are all about use of things like: found =- 1; which it warns as a potential mistake, since it is common to intend this to be: found -= 1; Making it found = -1; clarifies the intent for the compiler and stops it from warning. 2012-05-31 11:49 tvrusso * src/wx.c: Fix incorrect test of sscanf return value. When I changed the scanf to ignore the PXXX field, I forgot to decrease the value. 2012-05-31 11:41 tvrusso * src/wx.c: Add a string to the APRS DataLogger debug output. 2012-05-26 19:57 tvrusso * src/wx.c: Fix what seems to be a serious error in the Davis APRS DataLogger code. When I first wrote this section I decoded pXXX into "wx_prec_24" and PXXX into "wx_prec_00" since pXXX means "rain in last 24 hours" and PXXX means "rain since midnight." But Xastir actually computes those things itself, and the DAVISMETEO code puts pXXX into "wx_rain_total" instead. AA9VI has been having Issues with his DataLogger, in that Xastir is zeroing out the rainfall improperly. Turns out that's because I'm never setting wx_rain_total, and Xastir needs that. So I'm removing "rp-" and "rP-" from the debug output, no longer saving PXXX into wx_prec_00 (it's discarded now), and am now saving pXXX into wx_rain_total so that Xastir can handle it properly. This should fix Mike's problem. 2012-05-15 08:29 tvrusso * src/map_tif.c: Replace include of "projects.h" with "proj_api.h" and remove use of what is now considered an internal structure (struct PJ). Replace that usage with a pointer to such a structure (projPJ, which is a typedef to a pointer to a PJ). Proj.4 has removed "projects.h" from the installation of that library, because much that's in it is considered private implementation details that should not have been exposed. That many packages use those internals directly is considered a problem in those other packages, and a bug request in proj.4's bug tracker to reinstate projects.h as an installed file was closed with the status "wontfix". Codes that use the public API of proj.4 are supposed to include "proj_api.h" and use the API calls, not direct access to internal data structures or functions that are not intended for use outside the library. 2012-05-14 13:38 tvrusso * config/Makefile.am, config/nwsozddap12.dbfawk, config/nwsw_ddjn12.dbfawk, scripts/get-NWSdata, src/testdbfawk.c: Update get-NWSdata to fetch the very latest NWS data. Some of the files it was trying to get are non longer available. Before committing, I assured that *ALL* files that get-NWSdata downloads have corresponding matching dbfawk files. Two of the files (oz and w) have had their dbf signatures change, so needed new dbfawk files. Updated Makefiles to install these new files (which I've named according to a new convention, instead of _ddmmyy_year, I'm using mmyy that matches the dbf file to which it corresponds). Fix a spelling error in testdbfawk ("mathing" instead of "matching"). 2012-05-10 18:55 tvrusso * src/: db.c, maps.c: Comment out fprintfs to stderr that were introduced by last commit. They are spewing info to stderr of an exact sort that other types of weather alerts have commented out. 2012-05-08 11:04 tvrusso * src/wx.c: Fix debug output for Davis APRS DataLogger so that it actually prints the decoded values for 24-hour and since-midnight precipitation. 2012-05-06 09:09 tvrusso * configure.ac: make a single change of if [ "$var" = "yes" ] to if test "$var" = "yes" because I found that a Fedora 15 install was complaining about the former. 2012-03-05 10:49 we7u * symbols/: tornado.xbm, winter_wx.xbm, wntr_strm.xbm: Removing no longer used weather alert files. We renamed them slightly to match the alert_tag text in the NWS weather alerts. 2012-03-05 10:47 we7u * symbols/Makefile.am, symbols/torndo.xbm, symbols/winter_storm.xbm, symbols/winter_weather.xbm, src/map_shp.c, src/util.c, src/util.h: A rewrite of a patch supplied by Arnaud, F4EIR, which simplifies how we do alert->tag processing. We now grab the alert tag, change it to lower-case, then find a matching file on the filesystem. If not found, we grab one called "alert.xbm" as a default. This change will allow adding more files over time for more types (or Country's) alerts. Arnaud has plans to add support for France's weather alerts. 2012-03-02 12:28 we7u * README.Getting-Started, README.MAPS: Updating the copyright year for these two files. 2012-03-02 12:26 we7u * config/Makefile.am, config/gfe_coastal_waters.dbfawk, config/gfe_coastal_waters_warnings.dbfawk, config/gfe_fire_weather.dbfawk, config/gfe_metro_areas.dbfawk, config/gfe_public_weather.dbfawk, scripts/Makefile.am, scripts/get-BOMdata, src/alert.c, src/db.c, src/maps.c, src/util.c: Tweaks to allow using Australian Bureau of Metrology weather alerts in Xastir. This allows lighting up zones in a similar manner to the NWS weather alerts. Thanks to Geoff Gatward, VK2XJG/VK8GG, for this work! 2012-03-02 12:10 we7u * config/nwsmzddmmyy_11.dbfawk, config/nwsz_ddmmyy_11.dbfawk, scripts/get-NWSdata: Updates to the NWS fetch script and dbfawk files by Geoff Gatward, VK2XJG/VK8GG. Thanks! 2012-03-01 10:11 we7u * FAQ: Adding 4.34 question/answer from the web-based FAQ, and 4.35 from a question answered by Tom Russo on the mailing list (added with permission). 2012-02-04 16:10 tvrusso * README.Getting-Started, README.MAPS, scripts/Makefile.am: Change scripts Makefile.am to remove misuse of "pkglib_SCRIPTS" as this usage was one that was not intended to be correct, but was silently accepted by older versions of automake. Now automake enforces certain rules about what directory prefixes may be used with what "primaries" (such as _SCRIPTS and _DATA), and "pkglib" is forbidden as a prefix to "_SCRIPTS." This change also changes where scripts are installed. They used to get installed to /usr/local/lib/xastir, now they go to /usr/local/share/xastir/scripts. Documentation has been updated to fix references to the old directory. 2011-10-20 19:08 tvrusso * README.MAPS: Testing CVSROOT/loginfo change. 2011-10-20 18:45 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added a new box in the TNC properties dialog for setting the CONVERSE mode command. If blank it will get set to "k" which most TNC's accept. Can be set to "conv" for TNC's like the KPC-2 on an individual port basis. 2011-09-08 12:47 tvrusso * config/: Makefile.am, nwsz_ddmmyy_11.dbfawk: Add a new dbfawk file for the newest NWS Zone file, which once again has different dbf signature than all previous versions. 2011-09-05 13:24 tvrusso * scripts/geopdf2gtiff.pl: Remove creation options for PACKBITS compression, until I figure out why that's creating tiffs Xastir can't read. 2011-09-05 12:58 tvrusso * scripts/geopdf2gtiff.pl: Add a "fix neatline" option for GeoPDFs with bad neatlines, such as the most recent US Topo editions, which have neatlines that include all the collar. This hack works when the user specifies --fixneatline or -f, and rounds the left, right, top, and bottom of the image down to the nearest 7.5' quad boundary, and uses those values to construct its own neatline prior to calling gdalwarp with the -cutline -crop_to_cutline options. 2011-09-05 10:54 tvrusso * scripts/geopdf2gtiff.pl: Add compress=packbits to geotiff creation options for minor disk space savings. 2011-09-05 10:29 tvrusso * scripts/: Makefile.am, geopdf2gtiff.pl: Added script to convert GeoPDF files to usable GeoTIFF files. This involves extracting the neatline from the GeoPDF, then doing a gdalwarp to strip the collar and warp to EPSG:4326 coordinate system (WGS84 equidistant cylindrical projection), and finally to dither to 8 bit if there is more than one band present. I have found that some GeoPDF files lie about their neatlines, saying the neatline encloses the whole raster including the collar. There is nothing to be done about this except to hand-craft an FGD file for such GeoPDFs. With an FGD file, Xastir will collar-strip itself. This seems only to be a problem with some of the fancier new-style GeoPDF files, the "Digital Maps, Beta." 2011-07-06 00:45 we7u * config/: Makefile.am, tnc-startup.d72_d710, tnc-stop.d72_d710: New start/stop files for Kenwood D72 and D710, contributed by Kai Günter, LA3QMA. Thanks! 2011-05-31 08:37 gstueve * config/Makefile.am, config/nwsc_ddmmyy_10a.dbfawk, config/nwsmzddmmyy_11.dbfawk, config/nwsw_ddmmyy_10.dbfawk, config/nwsz_ddmmyy_10c.dbfawk, scripts/get-NWSdata: Make sure we have good mapping files for current NWS data files. Also get current set of files from NWS. 2011-03-26 20:07 jedunmire * src/map_OSM.c: - fix for downloading tile '5 of 4' bug - the bug and the fix are cosmetic and should not impact any other operations. 2011-02-25 22:06 we7u * config/: Makefile.am, nwsc_ddmmyy_10.dbfawk, nwshzddmmyy.dbfawk, nwsz_ddmmyy_10b.dbfawk: Updating dbfawk files to match current set of NWS Shapefiles. 2011-02-25 15:06 we7u * scripts/get-NWSdata: Updating to the most recent valid NWS files for alerts. We'll need to update our dbfawk files to match these. 2011-01-23 17:29 we7u * scripts/get-NWSdata: Updating to latest NWS Shapefiles. 2011-01-03 17:30 we7u * README: Added the OpenSuSE-11.3 repository to the notes plus a command-line option to configure which picks up another needed library location. 2010-12-31 04:58 we7u * help/help-English.dat: Revising the tactical callsign text a bit. 2010-12-31 04:41 we7u * FAQ: Changed the "Can I run multiple Xastir's at once" answer to incorporate use of the new(er) "-c" command-line flag. 2010-12-31 04:17 we7u * help/help-English.dat: Added info about publishing tactical callsigns across the air and later revoking those assignments via APRS messaging. 2010-12-20 15:43 jedunmire * src/map_OSM.c: - Re-organized a few lines in map_OSM.c so that it not produce an error message when *Magick libraries are not used. 2010-12-04 17:37 tvrusso * configure.ac, src/shapelib/contrib/Makefile.am: Fix configure/make so that it works properly when internal shapelib is being built on a system without libproj. 2010-11-08 17:48 tvrusso * Makefile.am: Fix for bug reported by Jeremy Utley, in which using DESTDIR at install time was depositing some CC_*.png files in a directory that ignored DESTDIR. 2010-10-25 20:25 we7u * configure.ac: Bumping CVS up to v2.0.1 for further development. 2010-10-25 20:02 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Setting up for the v2.0.0 stable release. 2010-10-24 10:01 we7u * config/language-French.sys: Updates by Arnaud, F4EIR. Thanks! 2010-10-24 09:59 we7u * config/language-German.sys: Updates by Rolf, DK7IN. Thanks! 2010-10-05 07:14 chicoreus * scripts/db_gis_mysql.sql: Fixing script to generate database and tables for MySQL based persistence. Previous versions include invalid syntax. Changes herein largely follow patch by Dan Zubey N7NMD. This script has now been tested both with grant statments commented out and with grants included. 2010-09-30 08:35 gstueve * scripts/get-NWSdata: Update files for current boundaries. 2010-09-28 20:55 jedunmire * src/map_geo.c: - eliminate the warning about a missing prototype for DistroyImagePixels() but enabling prototypes for 'private' functions in GraphicsMagick. 2010-09-23 19:24 jedunmire * src/map_OSM.c: - changes to transparency code for OSM tiled maps. This fixes the problem with 16-bit *Magick quantums. 2010-09-21 07:46 we7u * src/list_gui.c: A patch by Jason Godfrey, N0RPM, which fixes the segfault on list close problem. We were calling XtDestroyWidget() on child widgets, but calling it on the parent is sufficient. We just have to make sure there aren't any references to those child widgets first. 2010-09-08 11:13 jedunmire * Makefile.am, src/Makefile.am, src/tile_mgmnt.c, src/tile_test.c: - Removed obsolete tile experiment application (tile_test) - Stopped using http 'newer than' requests for OSM tiles. The 'newer than' test was ignored by all observed OSM servers and caused corrupted downloads and long delays for the topOSM tiles. - Changed the names of the TopOSM files so that they layer automatically. 2010-08-17 10:26 gstueve * src/main.c: Add setlocale() back in place to calm Warnings about charset mismatch. 2010-08-14 16:21 we7u * src/wx.c: Fixes for One-Wire-Daemon ARNE protocol mode to allow the use of the current string output: 12 parameters instead of 19. We allow use of either format now. 2010-08-14 14:32 jedunmire * Makefile.am, OSM_template, README.OSM_maps, src/map_OSM.c, src/map_OSM.h, src/map_geo.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c: - fix for '1 of 0' tile download message - fixed a memory leak in map_OSM.c - fixed installation of OSM CC icons - added support for .jpg tiles - implemented transparency for tiles. No more red blocks for missing tiles, tiles can be stacked, and lower levels show through for missing tiles. - zoom level limits for OSM maps - New map definitions for topOSM 2010-08-13 14:53 we7u * src/map_shp.c: A fix for segfaults caused by some Shapefile maps. Kyle and Nathan Mills were my consultants for fixing this bug, though the final bug-fix was mine. 2010-08-10 02:11 we7u * src/xa_config.c: Faster processing of the config file. We now call fseek to reset to the beginning of the file only if we don't find a particular option the first time through. We were calling it before every search, plus were reading in another line in the loop before we checked whether we had found the current option (making us go one too far each time). 2010-08-10 01:39 we7u * .cvsignore, src/.cvsignore: Adding a few files to .cvsignore to keep the cvs status clean. 2010-08-10 01:22 we7u * src/: alert.c, db.c, interface.c, interface.h, util.c, util.h, x_spider.c, xa_config.c: More work to help assure that config file reading/writing is consistent no matter the locale. Replacing more dangerous string functions with safer functions. Combined split_string_char and split_string into one function. Added get_float() and store_float() function to simplify code. 2010-08-10 01:07 we7u * src/main.c: Adding more setlocale() calls before we read in the config data. 2010-08-04 04:12 we7u * config/: OSM_Cloudmade_administrative.dbfawk, Makefile.am, OSM_Cloudmade_highway.dbfawk, OSM_Cloudmade_natural.dbfawk, OSM_Cloudmade_poi.dbfawk, OSM_Cloudmade_water_and_coastline.dbfawk: Adding dbfawk files for the Open Street Maps "Cloudmade" Shapefile extracts. 2010-08-01 22:12 we7u * configure.ac: Mark GeoTiff support as a "no" if we can't find the geotiff include files. 2010-08-01 21:06 we7u * configure.ac: Removing the extra -I for finding libgeotiff. It appears to be distribution-specific, depending on where they decide to stuff the include files. libgeotiff itself when installed from sources goes into /usr/include and Xastir finds it readily. 2010-08-01 15:25 we7u * configure.ac: Updating path to libgeotiff include files. 2010-07-30 20:12 jedunmire * README.OSM_maps, src/fetch_remote.c, src/fetch_remote.h, src/map_OSM.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c: - cached OSM tiles are not checked for updates after 7 days - tile downloads will use http pipelining if supported by the server - new debug level, 8192 for verbose curl output 2010-07-30 11:18 we7u * Makefile.am: Fixing a minor hitch the install-exec-hook. 2010-07-29 14:57 jedunmire * src/map_OSM.c: - fixed compile error when map-cache is disabled 2010-07-27 09:48 we7u * src/fetch_remote.c: Adding a prototype needed on some systems. 2010-07-27 01:40 we7u * CC_OpenStreetMap_logo.png, CC_OpenStreetMap_txt.png, ChangeLog, Makefile.am, OSM_template, README.OSM_maps, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/Makefile.am, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_WMS.c, src/fetch_remote.c, src/fetch_remote.h, src/map_geo.c, src/map_tiger.c, src/maps.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c, src/track_gui.c, src/util.c, src/util.h: Open Street Maps tiling patches by Jerry Dunmire, KA6HLD. Way to go Jerry! 2010-07-21 04:52 we7u * .cvsignore, src/shapelib/contrib/.cvsignore: Updating .cvsignore files to current build configuration. 2010-07-12 23:12 we7u * src/shapelib/contrib/: my_nan.h, shpgeo.c: Attempting to fix the "endian-ness" tests. 2010-07-12 11:22 we7u * src/shapelib/contrib/my_nan.h: Fixing up BYTE_ORDER so that internal Shapelib compiles on more machines. 2010-07-11 16:39 we7u * src/: main.c, objects.h: Getting rid of the final two compiler warnings, again by switch to the use of intptr_t instead of int. Other systems may have more warnings, but this OpenSuSE-11.2 64-bit system compiles Xastir cleanly now. 2010-07-11 16:31 we7u * src/: draw_symbols.c, interface.c, map_shp.c, messages_gui.c, objects.c, shp_hash.c, testdbfawk.c: Getting rid of more compiler warnings, mostly by casting to/from intptr_t. 2010-07-11 14:41 we7u * src/rtree/: index.c, index.h, rect.c: Fixed some long-standing compiler warnings in the rtree code. Seems to still work properly. 2010-07-11 13:30 we7u * src/shapelib/: dbfdump.c, shputils.c, contrib/dbfcat.c, contrib/shpdxf.c, contrib/shpgeo.c, contrib/shpproj.c: More minor tweaks to get rid of compiler warnings. Of particular note are some TODO entries added to a couple of files for two enumerated values that weren't being handled in "switch" statements. There still isn't any code for those case statements, but the compiler warnings are gone. 2010-07-11 01:01 we7u * src/shapelib/shputils.c: Adding some braces for some "if" statements so that the enclosed else clause won't be ambiguous. 2010-07-11 00:57 we7u * src/shapelib/: shpdump.c, shptreedump.c, contrib/shpdxf.c: Fixing a few more compiler warnings. 2010-07-11 00:51 we7u * src/shapelib/: shptreedump.c, shputils.c, contrib/shpcentrd.c, contrib/shpdata.c, contrib/shpdxf.c, contrib/shpfix.c, contrib/shpinfo.c, contrib/shpproj.c, contrib/shpwkb.c: Fixing more compiler warnings. There are a few left yet. 2010-07-11 00:24 we7u * src/shapelib/: dbfdump.c, shprewind.c, shputils.c, contrib/dbfcat.c, contrib/dbfinfo.c, contrib/shpcentrd.c, contrib/shpdata.c, contrib/shpdxf.c, contrib/shpgeo.c, contrib/shpinfo.c, contrib/shpproj.c, contrib/shpwkb.c: Fixing multiple minor warnings with Shapelib. Still plenty left. 2010-07-10 23:31 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Changing the shapelib and shapelib/contrib Makefile.am files so that the binaries don't get installed during "make install" 2010-07-10 23:22 we7u * src/shapelib/: Makefile.am, shputils.c, contrib/Makefile.am: Setting up the rest of shapelib and shapelib/contrib so that everything compiles. Had to add an include to shputils.c and add a "1" parameter to exit() in one spot. 2010-07-10 22:52 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Now building libshape.a in both the shapelib and the shapelib/contrib directories so that we can build executables in both places successfully. 2010-07-10 22:39 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Adding more binaries into the build. The ones in "contrib" still depend on "libshape.a" in the "shapelib" dir and we still need to figure out how to build that library first. 2010-07-10 13:53 tvrusso * src/shapelib/: Makefile.am, contrib/Makefile.am: Modifications to internal shapelib support so that dbfinfo (from the contrib directory) builds when internal shapelib builds. Until now, none of the "contrib" programs were built. 2010-07-06 23:16 we7u * src/main.c: Patch by Jerry Dunmire to prevent use of F4 key (Open Street Map optimum zoom) when Disable Fast Zoom is activated on the Map menu. 2010-07-03 15:09 we7u * scripts/: coord-convert.pl, inf2geo.pl, mapfgd.pl, overlay.pl, ozi2geo.pl, permutations.pl, ridge_radar.pl: Removing the Copyright noticed from scripts that were released to the public domain. They are mutually exclusive. 2010-07-02 00:17 we7u * config/tl_2009_aiannh.dbfawk: I screwed up the credit on that last commit. Those dbfawk files come to us courtesy of Peter Gamache, KC0TFB. Sorry about that! 2010-07-02 00:12 we7u * config/: Makefile.am, tl_2009_aiannh.dbfawk, tl_2009_aits.dbfawk, tl_2009_arealm.dbfawk, tl_2009_areawater.dbfawk, tl_2009_county.dbfawk, tl_2009_cousub.dbfawk, tl_2009_edges.dbfawk, tl_2009_mil.dbfawk, tl_2009_nn_county.dbfawk, tl_2009_pointlm.dbfawk, tl_2009_zcta5.dbfawk: Contributions by Kevin Paetzold, K1KWP. Thanks! 2010-07-02 00:08 we7u * scripts/: Makefile.am, ridge_radar.pl: Adding ridge_radar.pl, which computes a .geo file for a particular NWS abbreviation. Contribution by Jeremy McDermond (NH6Z). Thanks! 2010-06-30 16:31 we7u * src/map_OSM.c: Adding the ImageMagick ifdef's back in. Patch by Jerry Dunmire. 2010-06-29 23:41 we7u * src/: main.c, map_geo.c: F4 key multiple maps fix by Jerry Dunmire. 2010-06-29 23:25 we7u * src/: interface.c, main.c, wx.c, wx.h: A fix for Radio Shack/Huger/Oregon Scientific weather stations connected via the WX200d daemon. This fix may also help direct-connected weather stations of the above type, but since I don't have any to test with, it's unknown until someone tries. 2010-06-29 10:01 we7u * Makefile.am, tigermap.geo: First step at removing tigermap.geo: Making it invisible to the user. 2010-06-28 14:25 we7u * OSM_cloudmade_1.geo, OSM_cloudmade_2.geo, OSM_cloudmade_5.geo, OSM_cloudmade_998.geo, OSM_cloudmade_999.geo, OSM_cycle.geo, OSM_mapnik.geo, OSM_osmarender.geo, OSM_skiing.geo: Removing .geo files that are now created from a template. 2010-06-28 13:49 we7u * OSM_template: Need to commit a new file after Jerry's latest patch for things to work for everyone else! 2010-06-28 12:17 we7u * OSM_cloudmade_1.osm, OSM_cloudmade_2.osm, OSM_cloudmade_5.osm, OSM_cloudmade_998.osm, OSM_cloudmade_999.osm, OSM_cycle.osm, OSM_mapnik.osm, OSM_osmarender.osm, OSM_skiing.osm: A bit of cleanup: Getting rid of the no-longer-used *.osm files. 2010-06-28 12:14 we7u * Makefile.am, OSM_cloudmade_1.geo, OSM_cloudmade_2.geo, OSM_cloudmade_5.geo, OSM_cloudmade_998.geo, OSM_cloudmade_999.geo, OSM_cycle.geo, OSM_mapnik.geo, OSM_osmarender.geo, OSM_skiing.geo, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_geo.c, src/maps.c: Mods by Jerry Dunmmire WRT OSM. His notes: Summary of changes: - scaling corrected - requested OSM map size limited to 2000x2000 and +/-89 deg latitude - no 'binned' zoom levels - new function key (F4) to 'optimize' zoom level for OSM - .osm maps eliminated - OSM map files (.geo) built from a single template Details: scaling corrected: This required a major rewrite of the map_OSM.c code since the map_tiger.c code that it was based on did not support Mercator projection. Note that due to size limitations from the server and the use of Mercator scaling when the OSM bitmap images are rendered, some OSM maps will not fill the display window. This is particularly common when using a large display window. Selecting an optimized OSM zoom level (F4) will generally, but not always, result in bit map image that fills the window. map size limitations: The OSM map server that is used by this code limits the returned bitmap image to 2000 pixels in either direction. Also, as a side effect of the Mercator projection, latitude values must be limited to -90 < lat < 90. no binned zoom levels: Attempts to constrain the linear Xastir scaling to the binned OSM levels has been unsuccessful. The final straw was a problem with float to integer transitions that would result in looping and oscillation between levels. new function key to optimize OSM zoom levels: Since bitmap images do not scale well, they will always look best when the Xastir scale is closest to the OSM scale. A function key (F4) has been defined that will adjust the Xastir scale to the nearest OSM level and redraw the screen. Note that even if the scale is not changed, the F4 key will redraw the screen- this is intentional on my part. The F4 key works only if an OSM map is selected. If the F4 key is already defined for some other use on your system you can specify an alternative key by modifying the map files (OSM*.geo). The specified value must be an X11 KeySym value. Setting the value to 0 will disable the key. .osm maps eliminated Since binned scale levels are no longer supported, the .osm extension is no longer needed. .osm file will not be installed. If your maps directory (typically /usr/local/share/xastir/maps/Online/) contains .osm file from an previous install you will have to remove them by hand. You should also re-index your files (Map->Configure->Index:Reindex ALL maps) to remove them from the Map Chooser. OSM map files (.geo) built from a single template: This is primarily of interest to developers and results in a cleaner source tree. 2010-06-28 12:01 we7u * configure.ac: Commenting out the tests for libgps, which we're currently not using. 2010-06-18 22:35 we7u * src/interface.c: Skipping the hostname lookup if we pass an IP address instead of a hostname. 2010-06-18 22:11 we7u * src/interface_gui.c: Changing default GPSD port to 2947. 2010-06-18 21:57 we7u * configure.ac, src/interface.c: Changes to support pre-2.90 and post-2.90 versions of GPSD network connections. We now send the "R\r\n" command across (old method), then then send: ?WATCH={"enable":true,"nmea":true}\r\n (new method). Between the two strings either version of GPSD daemon gets kick-started into sending us NMEA strings. 2010-06-17 20:41 we7u * configure.ac: Changing one summary line (text only). 2010-06-17 20:07 we7u * configure.ac, src/interface.c: Added the configure test for libgps and the gps.h header file, necessary to continue with adding gpsd support into Xastir. More to do yet. 2010-06-17 16:24 we7u * src/util.c: Added a debugging statement, but it's commented out. Useful at times. 2010-06-15 07:29 we7u * OpenStreetMaps.osm: Part of the OSM linear patch by Jerry Dunmire. 2010-06-15 07:28 we7u * Makefile.am, OSM_cloudmade_1.geo, OSM_cloudmade_1.osm, OSM_cloudmade_2.geo, OSM_cloudmade_2.osm, OSM_cloudmade_5.geo, OSM_cloudmade_5.osm, OSM_cloudmade_998.geo, OSM_cloudmade_998.osm, OSM_cloudmade_999.geo, OSM_cloudmade_999.osm, OSM_cycle.geo, OSM_cycle.osm, OSM_mapnik.geo, OSM_mapnik.osm, OSM_osmarender.geo, OSM_osmarender.osm, OSM_skiing.geo, OSM_skiing.osm, src/map_OSM.c, src/map_OSM.h, src/map_geo.c: OpenStreetMaps linear scaling patches by Jerry Dunmire. Thanks! 2010-06-10 19:04 we7u * OpenStreetMaps.geo: Another patch by Jerry Dunmire, KA6HLD. 2010-06-10 19:02 we7u * Makefile.am, OpenStreetMaps.osm, src/main.c, src/map_geo.c, src/maps.c: Another OSM patch by Jerry Dunmire, KA6HLD. 2010-06-09 16:28 we7u * src/: db.c, igate.c, interface.c, interface_gui.c, main.c, map_OSM.c, map_WMS.c, map_shp.c, map_tiger.c, maps.c, messages_gui.c, objects.c, view_message_gui.c, wx_gui.c: More tweaks by Jerry Dunmire, KA6HLD. These get rid of some compiler warnings with newer GCC compilers. 2010-06-09 11:51 we7u * AUTHORS, Makefile.am, OpenStreetMaps.geo, src/Makefile.am, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_geo.c: Initial patches to use Open Street Maps with Xastir. This appears to be a good replacement for the now-defunct Tigermap server. Patches contributed by Jerry Dunmire, KA6HLD. Thanks Jerry! 2010-05-27 07:01 gstueve * scripts/: get-fcc-rac.pl, get-gnis: Uodate copyright info in a couple of scripts. 2010-05-07 09:23 tvrusso * src/main.c: Add a very simple hack cribbed from the "Grace" project http://patch-tracker.debian.org/patch/series/view/grace/1:5.1.22-5/motiflockup.diff to work around some extreme breakage introduced by Xorg server around version 1.7.5. This breakage changed the way the server handles "passive grabs" and has broken *all* motif programs that use XmCreatePopupMenu (among other things); such programs will grab the mouse cursor upon creating the pop-up and restrict cursor motion to within the parent widget of the intended popup, rendering the desktop completely unusable until the X server is killed. The correct fix is to update Xorg server (the fix is apparently in the yet-to-be-released 1.7.6), but that is not an option for some users of systems that only use stable releases of Xorg, and sometimes not even then (think Ubuntu, where they tend to stick only to bug-fix updates in a given LTS tree, and don't go to the next release number). Thus, it is necessary either to patch motif libraries or work-around the issue in applications. Since patching motif libraries is not a reasonable thing to require of our users, it's worthwhile to hack Xastir. The work-around ungrabs the mouse cursor immediately after the call to XmCreatePopupMenu. It's an almost trivial modification of the code. Tested on Xorg-server 1.6.5 and Xorg-server 1.7.5. Looks good, so committing it. The fix does have one unfortunate side effect on the newer server , as it is somewhat more difficult to tap the right mouse button and get the right-click menu to stay up, but it is possible. On the older server it appears to have no effect at all, which is good. 2010-04-23 07:00 gstueve * src/bulletin_gui.c: Remove annoying blank line from end of bulletin list. 2010-04-21 12:36 gstueve * config/Makefile.am: Fix source identification to work for BSD make. Should now work for new and old make utilities. I like these derived language files to test for added labels as I admit to a language deficiency. 2010-04-19 10:48 gstueve * config/Makefile.am: Permit derived language files to be generated from source file w/o requiring configure elements to be rerun. 2010-04-19 10:45 gstueve * config/Makefile.am, config/nwsz_ddmmyy_10.dbfawk, scripts/get-NWSdata: Add matching dbfawk file for new zone description file from NWS. 2010-03-10 22:24 we7u * src/db.c: Initializing a temp area object's color to a value to get rid of a compiler warning. 2010-03-10 20:03 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c: Mike, W2SWR, attempted to deploy Xastir over a MySQL database, and in the process helped to find multiple issues, including both an inability to compile xastir with just --with-mysql, and multiple causes for segfaults starting and stopping database interfaces and saving data. This commit addresses these issues. Xastir now compiles and runs with either or both --with-mysql and --with-postgis, as reqired definitions for each have now been appropriately included with preprocessor directives. The key fix for stability is in db_gis.h, the connection array has been redefined from an array pointer to an array, and the MYSQL object in the Connection struct has been changed from a MYSQL pointer to a MYSQL. Calls to methods that pass database connections have been rewritten to pass the address of the connection (&aDbConnection), rather than the connection. Multiple other fixes, mostly involving correcting the use of pointers, have been made to the db_gis.c code, and these have been tested and found to work with storage and retrieval of large quantities of internet feed data (on the order of 800,000 records) to both MySQL and Postgis databases, with xastir compiled with --with-mysql, --with-postgis separately, and with --with-mysql --with-postgis together. Also fixed a user interface bug that prevented retention of a selection of mysql(spatial) as a database type. 2010-03-05 21:52 we7u * FAQ: Adding more info to the Fedora 12 right-click bug problem/solution. 2010-02-28 07:47 we7u * scripts/inf2geo.pl: Added some comments about GM/IM prerequisites. Made it clear what the script does for the user. 2010-02-27 17:33 we7u * src/x_spider.c: Client connections to Xastir's server port had this problem: The last connected client, if it disconnected, would lock up the server. The pointer code taking care of removing objects in the linked list has been reworked. It no longer matters which order of client connects/disconnects are applied to the server. Thanks to Nathan Mills for helping me figure this out and test this. 2010-02-19 17:33 gstueve * src/interface.c: Fix spelling in error message that lintian found. 2010-02-16 20:13 chicoreus * src/db_gis.c: The node_path stored to a mysql database is not being truncated correctly with xastir_snprintf(), as the current length of the station->node_path_ptr that is providing the character array is used as the limit, rather than the maximum length allocated for the node_path into which it is being placed, thus causing a crash on trying to store a MySQL record for a position when the path exceeds 56 characters in length. 2010-02-16 17:47 we7u * FAQ: Tweaked the Fedora 12 right-click answer to point to "yum update". 2010-02-11 21:13 we7u * src/util.c: Taking an initial WIDE2-1 out of the equation which looks for WIDEn-N following WIDEn-N. 2010-02-06 19:48 we7u * Makefile.am: Setting up README.CYGWIN so that it gets copied to the docs directory with the rest of the docs during the install step. 2010-02-03 09:37 we7u * FAQ: Added Kevin K1KWP's note about getting right-click menus working in Fedora 12. 2010-02-01 10:37 gstueve * testdbfawk.1, xastir_udp_client.1: Quiet some warnings from manpages about hyphens and minus signs. 2010-01-31 12:10 we7u * configure.ac: Bumping the revision number for new development. 2010-01-31 12:09 we7u * README.Contributing: Updating text to call out the new place for the developers instructions (Xastir.org Wiki). 2010-01-31 00:45 we7u * ChangeLog: Committing latest ChangeLog (derived from cvs log) before release. 2010-01-31 00:44 we7u * symbols/symbols.dat: Updated wheelchair symbol plus new power plant symbol by Kyle Mills. Thanks! 2010-01-31 00:24 we7u * README.CYGWIN: A re-written Cygwin install by David Flood, KD7MYC. Thanks! 2010-01-31 00:19 we7u * README.MAPS: Tweaks by David Aitcheson, kb3efs. Thanks! A few minor tweaks by we7u. 2010-01-30 23:42 we7u * ChangeLog: Committing latest changelog before release. 2010-01-30 23:41 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.8 stable release. Changing revision numbers. 2010-01-30 18:12 we7u * AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, callpass.1, changes.txt, configure.ac, install-xastir, testdbfawk.1, update-xastir, xastir.1, xastir_udp_client.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/AUTHORS, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/Makefile.am, config/arealm.dbfawk, config/areawater.dbfawk, config/cousub.dbfawk, config/cousub00.dbfawk, config/edge.dbfawk, config/featnames.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsc_ddmmyy_09.dbfawk, config/nwsc_ddmmyy_09b.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzddmmyy_09.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsozddmmyy_09.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsw_ddmmyy_09.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwsz_ddmmyy_09.dbfawk, config/nwszoddmmyy.dbfawk, config/pointlm.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/stored_track.dbfawk, config/tabblock.dbfawk, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Coordinate.pm, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/UIView2XastirLog.pl, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/get-NWSdata, scripts/get-fcc-rac.pl, scripts/get-gnis, scripts/get-maptools.sh, scripts/get-pop, scripts/get_shapelib.sh, scripts/inf2geo.pl, scripts/kiss-off.pl, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl, scripts/object2shp.pl, scripts/overlay.pl, scripts/ozi2geo.pl, scripts/permutations.pl, scripts/pos2shp.pl, scripts/slideshow.pl, scripts/test_coord.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/track-get.pl, scripts/waypoint-get.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_pop.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testdbfawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating Copyright notice for 2010. 2010-01-25 20:09 chicoreus * src/db_gis.c: Make fails with errors when configured with just --with-mysql. Fixing nesting of HAVE_POSTGIS and HAVE_MYSQL directives so that xastir will build with just --with-mysql. Both compiler warnings and runtime errors remain when built --with-mysql --without-postgis. 2010-01-16 22:27 tvrusso * src/main.c: Fix three instances of a string compare being attempted by: char chararray[EXTENT] read chararray from some file if (chararray == "string literal") { } which is bad form in C and could lead to undefined behavior. The correct way to do this is with strcmp or strncmp. I replaced this with: if (strncmp(chararray,"string literal",strlen(chararray))==0) { } This is silently accepted by most older compilers, but is warned about by gcc 4.4 (the default compiler in Ubuntu 9.10). 2010-01-12 11:32 tvrusso * src/objects.c: Fix to my most recent fix; make sure that the code that doesn't get the compiler warning actually does the same thing that it did before the fix. 2010-01-12 09:47 tvrusso * src/objects.c: Minor tweak to silence a warning about "dereferencing type-punned pointer breaks strict-aliasing rules." 2010-01-11 19:30 tvrusso * src/: db.c, objects.c: Fix two bugs. 1) Bug 1698474 in the sourceforge tracker (Expire code messes up internal linked-list order) The title of the bug is erroneous. The expire code doesn't mess up any internal linked-list order. The expire code was being messed up by a broken linked-list order. What was breaking the list was the handling of our own objects. Code throughout objects.c was continually resetting the time stamp of station records to sec_now() withouth then moving the station record to the end of the time-sorted list. This led to the time-sorted list not being time-sorted anymore. The expire code explicitly depends on the list remaining sorted at all times. There was also a small block of code dating back to version 1.1 of db.c that also skipped moving a station record in the time-sorted list if it was our object or item. This very old code appears to do nothing at all. I have removed it. The time sorted list MUST be kept in time-sorted order. There was also a variable (object_is_mine_previous) that was set by this block of code but never accessed anywhere else. I've removed that variable, too. Additionally, the check_station_remove function erroneously checks "is_my_station" to determine if the station or object in question is owned by "me." It should be checking (is_my_station || is_my_object_item) to be consistent with the older conditional that is commented out just above it. 2) Creating an object that has the same name as a previously killed object would lead to an "immovable" object being created. This bug was never entered into the issue tracker. Prior to this commit, the following actions would create an object that could not be moved: create object a delete object a create object a Once the second create was done, the object a could not be moved by any means on the screen -- either by dragging with the Move button down or using the Modify Object dialog. The reason was that the code to handle resurrecting a killed object was improperly flagging the new object as being "my station" in addition to being flagged as "my object." The code that decodes position strings would see this flag and refuse to move the object "because I know my position better." Furthermore, the resurrection code would remove the old killed record from the name-sorted list, but not really delete the station record, leaving it in the time-sorted list. This also impacted expiration. This commit fixes the improper flagging as "my station" and completely deletes the station record for a killed object when we create a new object with the same name. 2010-01-01 15:04 we7u * src/main.c: Fixed some side-effects regarding zoom boxes when map lock is enabled. 2010-01-01 06:22 gstueve * src/db.c: Recall one of my tests from the wild. It escaped before its' time. 2009-12-31 03:10 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Finishing up the map lock code. 2009-12-29 13:56 we7u * src/main.c: Detaching the map lock from three areas where they are more complicated operations and therefore aren't easily done by mistake. Therefore no map lock required for those three. 2009-12-27 08:26 gstueve * callpass.1, testdbfawk.1, xastir.1, xastir_udp_client.1: Update APRS site reference to useful URL. 2009-12-27 07:29 gstueve * callpass.1: Add reference to xastir in NAME section to allow `apropos` to associate. 2009-12-25 07:20 we7u * README: Updating the SuSE 11.x ham repository info. 2009-12-22 13:37 gstueve * Makefile.am, src/db.c, src/lclint.script: Add additional man pages to list for publication. 2009-12-22 13:20 gstueve * callpass.1, testdbfawk.1, xastir.1, xastir_udp_client.1: Add simple documentation for all applications. Provide APRS reference in NAME section for 'apropos' & 'whatis' lookup. Make sure NAME section is parseable for scanning. 2009-12-22 02:56 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c, src/xastir.h: Adding map zoom/pan lock feature to the Map menu. 2009-12-17 09:44 gstueve * xastir.spec.in: Allow rpmbuild spec to work for 64bit environments also. 2009-12-08 11:34 we7u * README.MAPS: Updating the location of the RAC callsign manual download to match the URL in the get-fcc-rac.pl script. 2009-12-07 16:34 tvrusso * FAQ: Update FAQ to include updated answer to the "black images from imagemagick" question, and add a FAQ about compilation woes due to use of ImageMagick with HDRI support. 2009-12-04 10:54 tvrusso * src/: map_WMS.c, map_geo.c, map_tiger.c: Fix for the problem where Xastir will display black images when compiled against GraphicsMagick with its new default QuantumDepth of 8, or ImageMagick with its optional QuantumDepth of 8. The problem was that when the image was not a colormapped image (e.g. JPEG or other full color type), Xastir was assuming (incorrectly) that a Quantum was the same type as the red, green, and blue components of an XColor, and using the Quantums directly out of the pixel_pack in a call that required the latter. The result was that when pack_pixel_bits returned, the result was always that the packed pixel bits were always 0x000000, because it was taking the high-order 8 bits from the unsigned short to which the unsigned char was being cast. What was needed was a little block of code that massaged the pixel_pack values into unsigned shorts at that point if QuantumDepth is 8. This fix applies the same fix to map_tiger, map_geo and map_WMS, all of which had duplicated code (ugh) that made the same mistaken assumption of Quantum/unsigned short equivalence. This fix does NOT address the problem that exists on a few systems, where ImageMagick has been compiled with HDRI (High Dynamic Range Image) support. On those systems, a Quantum is not even an integer type, it's a float or double. Dealing with *that* mess will be harder. Ideally, the duplicated code between map_WMS, map_geo, and map_tiger should be consolidated according to good software engineering principles. 2009-11-26 08:52 tvrusso * LaCrosse/src/open2300db2APRS.c: Fix for an insidious bug in open2300db2APRS that relied on an unsafe internal behavior of the mysql API. The function Get_Latest_WX makes 2 SQL queries to the server, one to get the highest value of the "timestamp" field present in the DB, an another to get the row with that timestamp. Only after the first query was the function calling "row = mysql_fetch_row(&result)". That function returns a char ** that can be used to pick off the field values. Somehow, despite never being called after the second query, the row array still managed (on some systems) to have the right data in it --- presumably because the API call was returning a pointer to an internal block of memory that contained the field values, and on the systems where this worked that block wasn't moving. When I upgraded my BSD system and recompiled mysql, this started failing, and open2300db2APRS would segfault. Calling mysql_fetch_row after the second query fixes it. While I was at it, I fixed a mistake in some debug output that prints the number of fields retrieved by the query. 2009-11-09 12:46 we7u * scripts/UIView2XastirLog.pl: New script to convert UI-View log files to Xastir-format log files. Timestamp info is currently removed during the conversion. 2009-10-13 23:25 we7u * scripts/get-NWSdata: Updating the get-NWSdata script to snag the latest-latest NWS Shapefile maps used for weather alerts. 2009-10-13 23:24 we7u * config/: Makefile.am, nwsc_ddmmyy_09b.dbfawk, nwsmzddmmyy_09.dbfawk, nwsozddmmyy_09.dbfawk, nwsw_ddmmyy_09.dbfawk, nwsz_ddmmyy_09.dbfawk: Adding yet another round of dbfawk files to match new NWS Shapefile signatures. 2009-10-11 22:18 we7u * configure.ac: Bumping devel version up to 1.9.7 2009-10-10 11:28 we7u * scripts/: do_xastir_release_dev, do_xastir_release_stable: Updating to new SourceForge release process. 2009-10-10 10:41 we7u * ChangeLog, configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.6 stable release. 2009-08-12 11:59 we7u * src/main.c: Adding minWidth and minHeight to the fallback resources string in main() to attempt fixing the compiz/fusion bug with tiny unsizeable dialogs. 2009-08-12 11:14 we7u * FAQ: Adding a blurb regarding "compiz" and cigar-shaped windows in Xastir. Thanks to Tom R. for this text which I modified somewhat. 2009-07-31 21:19 tvrusso * config/nwsc_ddmmyy_09.dbfawk: Add a comment about the difference between this file and the nwsc_ddmmyy file. 2009-07-31 21:17 tvrusso * config/: Makefile.am, nwsc_ddmmyy_09.dbfawk: Add a new nwsc_ddmmyy file with different signature to match the very latest shapefiles. I am adding this as a new dbfawk instead of modifying the existing one so that those who don't wish to update their shapefiles will not have to, and those who have only the new ones will actually be able to use them. Xastir will pick the dbfawk file with the matching signature. 2009-07-31 15:38 we7u * src/wx_gui.c: Changing the weather alert FINGER server since WXSVR.net has been offline for a while. We're switching to Pete's new system (AE5PL) which is already online and functional. 2009-07-30 12:41 tvrusso * symbols/symbols.dat: Change color of ICP (Incident Command Post, /c) symbol to match the color specified in FEMA and NWCG ICS materials. (I'm working through lots of these courses while simultaneously trying to get Xastir integrated more into our local SAR system, and getting these discrepancies of terminology and symbology fixed is important). 2009-07-28 15:51 tvrusso * config/predefined_SAR.sys: Make predefined SAR objects conform with NIMS standard ICS terminology. There is no "Helipoint" in that terminology. The term "Helispot" is used for what we were previously calling a "Helipoint." 2009-07-28 15:49 tvrusso * src/objects.c: Fix predefined object name to conform with standard ICS terminology. A "Helispot" is a temporary landing place for helicopters. There is no "Helipoint" in standard ICS terminology. 2009-07-28 14:35 we7u * src/alert.c: Temporary change to allow viewing of compressed-zone format alerts sent by Pete Loveall, AE5PL's server. 2009-07-27 18:44 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Display of latest comment if H2O symbol plus object or item, and the comment time = the latest object/item update time. This is to support fast viewing of flood gauges during emergencies, using the data from the Firenet gage.pl script. 2009-06-29 00:14 we7u * src/db.c: Fixing Canadian callsign lookup to add VO and VY prefixes. 2009-06-19 23:01 tvrusso * src/shp_hash.c: Insert a conditional around code that uses a pointer returned by SHPReadObject. A user is finding that SHPReadObject is having an fread problem on one of his shapefiles, and returning NULL. This commit prevents Xastir from trying to dereference the null pointer. 2009-06-03 21:25 we7u * src/shapelib/: dbfadd.c, dbfcreate.c, shpadd.c, shpcreate.c, shpdump.c, shptest.c, shptreedump.c, shputils.c: Getting rid of compiler warnings due to unused variable. 2009-06-03 15:24 we7u * src/shapelib/: dbfadd.c, shpcreate.c: Adding includes for string.h to get rid of compiler warnings. 2009-06-03 14:57 tvrusso * src/shapelib/Makefile.am: Not really sure why this worked before but now doesn't work for Curt, but there was nothing in the src/shapelib/Makefile.am to make the {shp,dbf}{add,create} programs link with the shapelib we just built. Put that in. Rebootstrap before trying. 2009-05-22 16:23 we7u * scripts/pos2shp.pl: Changed some comments WRT the TODO for the comment field. 2009-05-22 14:41 we7u * README.MAPS: Adding bits about APRS Overlay files and the pos2shp.pl script. 2009-05-22 14:35 we7u * scripts/Makefile.am: Adding pos2shp.pl to list of scripts to install. 2009-05-22 14:23 we7u * scripts/pos2shp.pl: Better version. Limits $name to 9 chars and chops trailing spaces on same. 2009-05-22 14:14 we7u * scripts/pos2shp.pl: First working version. Needs more error checking, needs to assure the name field is properly formatted, and needs to do something with the comment field yet. 2009-05-22 13:16 we7u * scripts/pos2shp.pl: Updated comments, removed live_or_dead code. Has NOT been converted to parse POS format files yet (Overlay files). 2009-05-22 11:19 we7u * scripts/pos2shp.pl: Start of a pos2shp.pl script. No code changes yet from the original object2shp.pl script it started from. 2009-05-22 10:44 tvrusso * src/shapelib/Makefile.am: Change internal shapelib makefile so that it *does* install the create and add programs if we're building with internal shapelib. Note: This should not be tested by those who have shapelib tools installed from a package unless you know how to do it without clobbering them. Hint: configure --prefix=/some/other/base/than/usr/local will make sure that the new test install doesn't clober anything that the normal install created. 2009-05-22 10:30 tvrusso * src/shapelib/Makefile.am: Add "noinst_PROGRAMS" to the internal shapelib build so that shpcreate, shpadd, dbfcreate and dbfadd are built if the user is building the local shapelib. They are not installed, because I didn't want to test that feature. To make it so that they *are* installed when make install is called, one needs only change "noinst_PROGRAMS" in src/shapelib/Makefile.am to "bin_PROGRAMS" . 2009-05-19 13:47 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/wx.c: Add support for the Davis 6540 "Weatherlink for APRS" with "Streaming Data Logger". This attachment to the Davis Vantage Pro causes the device to stream APRS posits (sans fromcall, tocall, and path) to the serial port instead of requiring polling. With such a device, Meteo and the associated glue program (db2APRS or whatever it's called) are unnecessary, so long as this patch is in place. Also update language files as needed. 2009-05-09 07:15 tvrusso * src/db.c: Move "create_garmin_waypoint" call outside of "if (sound_play_prox_message)" conditional. A local user was completely confused why his garmin wasn't receiving waypoint data from Xastir, and when I hunted through the coude found that this feature only works if you have audio alerts for proximity warnings turned on. This seems wrong, so I moved the conditionals around so that waypoints are created if you're within proximity warning distance, whether or not you've actually got the old audio alarm turned on for proximity warnings. 2009-04-30 12:25 gstueve * src/: database.h, db.c: Fix band opening logic to ignore 3rd party traffic. Should make this really work for band opening and not messages from network. Fix Bug ID:2749796. 2009-04-30 11:52 gstueve * src/: main.c, shp_hash.c, shp_hash.h: We already know the current time, there is no need to ask again. 2009-04-29 20:08 gstueve * scripts/get-fcc-rac.pl: Minimize memory footprint for constrained systems. Do memory intense activity as late as possible. 2009-04-25 23:40 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c: Fix an annoyance related to DF bearing reports. Sometimes a bad parse of garbled Mic-E data causes Xastir to think that a D700 (or other mobile) is sending a DF report. Even if only a single such garbled transmission is received, the station is shown with DF bearing information for as long as it's in the database. Watching a mobile drive around with randomly moving DF beam lines is distracting. Not being able to make it go away without restarting Xastir has been annoying. Another way for this to happen is for some bonehead (such as KM5VY) to create a series of DF objects from an external program with his callsign as base name and sequential numbers to identify the reports (say "KM5VY-1", "KM5VY-2", etc.) until he happens to hit the SSID of the station that's sending the reports (say, KM5VY-8). What happens is the "object" data gets attached to the Xastir instance itself. This bogus beam heading shows up forever until shutting down Xastir. This happened today on a SAR ELT DF practice. The name of the bonehead has not been changed to protect the bonehead. This commit adds the ability to clear such bogosity. Now, the "Station Info" dialog for any station with DF bearing information has a "Clear DF Bearing" button that will zero out the bearing and NRQ strings for the station, removing the unwanted (and presumably incorrect) bearing lines until the station transmits them again (which probably means they're wanted and not incorrect). 2009-04-25 21:53 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Add a map-decluttering option. Prior to this commit, "Station->Filter Display->Display DF Attributes" would draw a pair of bearing lines for every DF object. The lines drawn represented the stated beamwidth of the report. Unfortunately, in a big DFing operation, this rapidly leads to a huge clutter on the map, making it very difficult, if not impossible, to read. I saw this during a big DF practice this morning, and just had to change it. I have added two new buttons under Display DF Attributes: "Display DF Beamwidth" and "Display DF Bearing." Selecting the first and not the second gives the current behavior. Selecting the second and not the first draws only the stated bearing, not the beamwidth. Selecting both draws all three lines for those who really, really like cluttered maps. The color of red used for the bearing line and the beamwidth lines is slightly different. I tried to set up xa_config so that when people first start up Xastir after updating, they'll recover the original behavior --- "Display DF Bearing" defaults to off if it's not found in the config file. Unless the new option is deliberately selected, users should not notice the change. Both Display DF Bearing and Display DF Beamwidth are greyed out if "Display DF Attributes" is deselected. Updated all the language files with the "update-language.pl" script to support the new menu items. A lot of other things got changed in the language files with this action, but those seemed mostly to be comments. 2009-04-24 13:10 gstueve * scripts/get-fcc-rac.pl: Move sort back to system package. PERL does parsing well, not sorting. 2009-04-17 16:10 we7u * config/: arealm.dbfawk, areawater.dbfawk, cousub.dbfawk, cousub00.dbfawk, edge.dbfawk, featnames.dbfawk, pointlm.dbfawk, tabblock.dbfawk: Updating the URL for the Shapefiles to point to the 2008 shapefiles instead of 2007! 2009-04-17 09:12 we7u * config/: Makefile.am, arealm.dbfawk, areawater.dbfawk, cousub.dbfawk, cousub00.dbfawk, edge.dbfawk, featnames.dbfawk, pointlm.dbfawk, tabblock.dbfawk: Adding the dbfawk files worked on by Richard Polivka, N6NKO, Craig Anderson, N6YXK, and Dale Seaburg, KG5LT, which help to nicely render 2008 Tiger Shapeline files. A note from Craig about layering: "...use "vi" on the map_index.sys file while xastir is not running. Once you are editing the file, use the following 3 commands in "vi" to change the layers. This assumes that, like with my xastir, new maps get added into the list at layer 1000. :g/tabblock/s/01000/00995/ :g/pointlm/s/01000/00996/ :g/arealm/s/01000/00997/ (translation: global search throughout the file for lines with "arealm" and substitute on that line for "01000", a "00997") This moves the tabblock (& tabblock00) files, pointlm files, and arealm files down underneath the roads maps. Otherwise the roads can get covered up by urban background coloring. Or you can do this through the GUI interface as well." 2009-04-16 19:55 we7u * src/wx.c: Fixing up the Peet Bros 2000 data logging and packet mode decoding for wind direction. These were really 4-character fields but the first two chars should be zeroed out. We were reading in only the 2nd two characters and then zeroing them out (the reading of interest). 2009-04-16 14:20 tvrusso * scripts/values.pl.in: Change values.pl.in so it references #!/usr/bin/perl instead of #!/bin/perl. Neither is strictly correct since perl could be installed just about anywhere on any system, but this brings it in line with all the rest of the scripts here. Ideally the location of the perl interpreter should be probed by configure and substituted in all the scripts, but that is probably more work than it's worth given that all of our scripts have had /usr/bin/perl hardcoded all this time. #!/usr/bin/env perl is sometimes suggested to make such scripts system-independent, but this is generally considered a security vulnerability because it uses the first "perl" that appears in the user's path, which might be a malicious bit of code. 2009-04-16 12:34 tvrusso * configure.ac, scripts/Makefile.am, scripts/values.in, scripts/values.pl.in: Remove inappropriate use of GNU Make extensions in scripts/Makefile.am. These were introduced to generate scripts/values and scripts/values.pl from scripts/values.in and scripts/values.pl.in, but this is the wrong approach. Generating these files from the .in's should be done by adding them to the configure.ac AC_CONFIG_FILES list and by using standard substitution strings in the .in files. Non-standard substitution strings can also be used if one also adds AC_SUBST calls to the configure.ac file. The standard substitution string for prefix is @prefix@ not @PREFIX@. 2009-04-16 12:26 gstueve * scripts/Makefile.am: Makefile should actually work properly for split source/build configuration. 2009-04-16 11:56 gstueve * scripts/Makefile.am: Make sure proper Makefile is updated when Makefile.am is updated. 2009-04-16 11:39 we7u * src/: main.c, messages.h, view_message_gui.c, xa_config.c: Saving/restoring the status of the CAD Objects buttons and the View Messages TNC/NET/MINE selection buttons. 2009-04-16 11:28 gstueve * scripts/: get-NWSdata, get-gnis, get-pop: Remove another possible bashism reported by checkbashisms script. 2009-04-16 09:25 we7u * scripts/: Makefile.am, slideshow.pl: Adding slideshow.pl, a script which snags the snapshot.png files into a separate directory and renames them for possible later use as a slideshow or animated movie. 2009-04-13 13:18 gstueve * scripts/get-pop: Position files are only ASCII, don't push AK or HI through recoding. 2009-04-13 13:10 gstueve * scripts/get-pop: Adjust download site to complete list. Retain tamu site for reference. 2009-04-13 11:34 gstueve * src/: locate_gui.c, maps.h: Add ability to locate map features from population format files. 2009-04-13 11:13 gstueve * src/map_pop.c: Missed these. Had compiled on other system. Mistyped entry. 2009-04-13 10:32 gstueve * src/: map_gnis.c, map_pop.c: Found a couple of locations that could get unhappy about trying to read bad data. 2009-04-13 10:16 gstueve * scripts/Makefile.am, scripts/get-pop, src/Makefile.am, src/map_pop.c, src/maps.c: Reintroduce previous population geolocator processing into new file type. The .pop file extension will reflect the old information. GNIS does not have authorative population data, we should use census info. The script will look to aprs.tamu.edu but I was not able to locate all of the states data files. 2009-04-08 09:24 gstueve * scripts/get-gnis: Get rid of bashism that escaped my first tests. 2009-04-08 09:17 gstueve * scripts/get-gnis: Add recode to convert AK & HI UTF-16 files to UTF-8 to give us a fighting chance to actually locate anything in those states. 2009-04-07 14:17 gstueve * scripts/get-gnis: USGS has made geocodes a moving target. Current file is 20090401. 2009-04-07 02:23 gstueve * src/main.c: Repair damage to map properties dialog inflicted by last check-in. 2009-04-06 09:07 gstueve * src/interface_gui.c: Move Path entries around to reduce vertical challenge. 2009-04-05 17:28 gstueve * src/map_gnis.c: Update field sequence to match current GNIS file layout. 2009-04-04 23:10 gstueve * src/list_gui.c: Update max display list to symbolic count. 2009-04-04 21:14 gstueve * src/list_gui.c: Clean up station list to actually line up with icon and line height. 2009-04-04 19:21 gstueve * src/objects.c: Maintain pointer to cursor to keep memory usage clean. 2009-04-04 11:37 gstueve * scripts/: .cvsignore, Makefile.am, coord-convert.pl, get-NWSdata, get-fcc-rac.pl, get-gnis, icontable.pl, values.in, values.pl.in, xastir-fixcfg.sh, xastir-migrate.sh: Fix the scripts to match the structure for placement of files by using -prefix from configure process to allow matchup to FHS placement. 2009-04-04 11:28 gstueve * m4/xmhtml.m4: Wrap macro name to keep everyone happy. Remove autoreconf complaint. 2009-04-03 07:08 gstueve * src/: main.c, main.h: Upgrade to session aware application space. Permit GNOME window manager to clean up without warning message about unsaved data. Permit restart to keep proper character translations for display. Clean up some free memory leaks and update for Motif 2.0 XmString functions. 2009-04-02 18:22 gstueve * src/interface.c: Remove extraneous include entry. 2009-04-02 15:09 gstueve * src/xastir.h: Remove external reference to internal application close out function. 2009-03-31 20:06 tvrusso * scripts/object2shp.pl: Fix a minor, but completely inconsequential error in this script. It would produce shapefiles with every shape having the same ID attribute. Doesn't matter at all since ID is not used for anything, but this is the right fix. 2009-03-31 12:56 we7u * src/rac_data.c: Fixing a 64-bit mode bug in the RAC callsign lookup code. 2009-02-06 09:22 gstueve * README.MAPS: Add hint for Australian rules Weather Alerts & update address for FCC data. 2009-02-06 08:51 gstueve * scripts/get-NWSdata: Update to latest from US NWS. 2009-01-08 17:53 we7u * README.win32: Adding notes WRT a Cygwin xorg-x11-devel 7.x compile error and how to fix it, courtesy of David Flood, KD7MYC. 2009-01-02 00:15 we7u * src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testdbfawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, m4/Makefile.am: Updating copyright notices for 2009. 2009-01-01 23:58 we7u * src/: rtree/Makefile.am, rtree/card.c, rtree/card.h, rtree/gammavol.c, rtree/index.c, rtree/index.h, rtree/node.c, rtree/rect.c, rtree/sphvol.c, rtree/split_l.c, rtree/split_l.h, rtree/split_q.c, rtree/split_q.h, shapelib/Makefile.am, shapelib/contrib/Makefile.am: Updating the copyright notices for 2009. 2009-01-01 23:56 we7u * scripts/: LSB-BUILD, LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB, Makefile.am, Xastir_tigerpoly.py, example_objects.log, get-NWSdata, get-fcc-rac.pl, get-gnis, get-maptools.sh, get_shapelib.sh, langElmerFudd.pl, langMuppetsChef.pl, langOldeEnglish.pl, langPigLatin.pl, langPirateEnglish.pl, toporama250k.pl, toporama50k.pl, xastir-fixcfg.sh, xastir-migrate.sh: Updating copyright notices for 2009. 2009-01-01 23:54 we7u * callpass/: Makefile.am, callpass.c: Updating the copyright notices for 2009. 2009-01-01 23:51 we7u * symbols/Makefile.am, symbols/symbols.dat, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui: Updating the copyright notices for 2009. 2008-12-31 20:37 we7u * src/xa_config.c: Changing xastir.cnf -> xastir.cnf.1 to a copy_file() call instead of a move(). This assures that we'll always have a config file in place even if we error-out before we can complete the next block which renames xastir.cnf.tmp -> xastir.cnf. 2008-12-31 20:18 we7u * src/xa_config.c: A better ordering for writing the config file. We now write a temporary file. If successful, we rename all the backups and then rename the temporary file as the current config file. This should help to minimize the instances of config file corruption. 2008-12-09 08:10 we7u * FAQ, README, README.Contributing, README.Getting-Started, README.win32: Adding notes about having to subscribe to the mailing lists before posting. 2008-11-26 09:39 we7u * src/draw_symbols.c: Correcting a comment. 2008-11-24 12:27 we7u * scripts/example_objects.log: Adding a link to the Xastir Wiki where images of these objects can be seen. 2008-11-12 15:26 tvrusso * src/map_geo.c: Comment out the use of GetOnePixel and the variable it assigns to. This is for two reasons: 1) F*!#*ng ImageMagick has broken its API yet again with version 6.4.5, making GetOnePixel no longer compatible with usage prior to 6.4.4 2) map_geo.c does this: PixelPacket target; target=GetOnePixel(image,0,0) after which it does NOTHING with the pixel so retrieved. So commenting out this useless line is less work than what I had started doing, which was hacking the configure detection of ImageMagick to distinguish between pre-6.4.5 and post-6.4.5, and coding around this garbage. I Hate ImageMagick. 2008-10-17 00:18 we7u * config/tnc-startup.aea: Turning on the HID function which is required on AEA TNC's for proper identification if they're digipeating. Since we have digipeating turned on in this file... 2008-10-16 09:20 we7u * ChangeLog: Updating for devel release. 2008-10-08 21:57 we7u * src/map_shp.c: Getting rid of a 64-bit compiler warning by changing an "(int)NULL" to a "0". 2008-10-08 21:56 we7u * src/db.c: Changing a debug format so that it doesn't cause a warning on 64-bit machines. 2008-10-08 08:11 we7u * src/maps.c: Getting rid of two compiler warnings: One by forcing a terminator into the first char of a string buffer instead of doing an empty xastir_snprintf(), another by casting a strlen() result to an int for an fprintf. 2008-10-07 23:10 we7u * src/shp_hash.c: Reverting back to the original code for strncpy() in this module: The previous change caused a panic. 2008-10-07 22:59 we7u * src/shp_hash.c: Getting rid of another strncpy() call. 2008-10-07 22:43 we7u * src/util.c: Forcibly terminating a string as an added precaution. 2008-10-07 22:42 we7u * src/shp_hash.c: Adding some blank lines to delimit an strcpy() call. 2008-10-07 22:41 we7u * src/objects.c: Getting rid of an strcat() call. 2008-10-07 22:41 we7u * src/db.c: Getting rid of some strncpy() calls. 2008-10-07 22:40 we7u * src/awk.c: Updating a comment. 2008-10-07 22:14 we7u * src/: db.c, fcc_data.c, hostname.c, igate.c, interface.c, interface_gui.c, locate_gui.c, map_WMS.c, map_geo.c, map_shp.c, map_tiger.c, maps.c, messages.c, objects.c, util.c, wx.c, x_spider.c, xa_config.c: Fixing some off-by-one errors in string handling. 2008-10-07 21:42 we7u * src/: alert.c, main.c: Fixing some off-by-one errors in string handling. 2008-10-06 22:04 we7u * src/main.c: Fixing the my_text string buffer in TrackMouse() so that it won't get overrun. The worst conditions are English Units, Dist/Bearing Status enabled, Degrees/Minutes/Seconds, zoomed out to world view and putting the mouse in the "corner" of the world (10,000+ miles). This results in about 54 characters being used whereas the original string buffer was only capable of holding 49. 2008-09-26 07:30 gstueve * src/x_spider.c: Make sure both sides of the pipe are satisfied before releasing the memory. The system is not happy about trying to read data from free space. 2008-09-24 12:44 we7u * .cvsignore: Ignore the derived file "xastir-lsb.spec" as well. 2008-09-24 12:18 we7u * src/.cvsignore: Ignoring testdbfawk now instead of testawk file. 2008-09-24 11:03 gstueve * src/map_tiger.c: Found one more place that needed to release ExceptionInfo when interrupted. 2008-09-24 09:16 tvrusso * README.MAPS, scripts/LSB-BUILD, src/Makefile.am, src/testawk.c, src/testdbfawk.c: Rename "testawk" to "testdbfawk" and add it to the list of programs that "make install" will install. This addresses a couple of issues: 0) Testawk is a *terrible* name for this program, because in fact it does not test "awk", the system program, but rather "dbfawk," the Xastir feature inspired by awk but completely unrelated to awk in any other sense. 1) testawk was never installed by Xastir's build process, meaning that packagers of Xastir binaries for various systems did not bundle this little program with their binary packages. There is even a bug in debian's bug tracker from an Xastir user asking that the xastir package have testawk installed (in a non-standard place because of its "generic, even misleading name") by the .deb package. I've updated README.MAPS and the LSB-BUILD script to make them refer to testdbfawk instead of testawk. I'll still have to change various web resources so they point at the new program, too. 2008-09-22 13:19 we7u * src/x_spider.c: Removing an earlier change 'cuz it makes the server ports die when a client disconnects. Without this line they appear to be solid again. 2008-09-11 06:07 we7u * src/main.c: Grey'ing out the xfontsel buttons when that app's not available. 2008-09-09 22:38 we7u * src/xa_config.c: Saving/restoring the tracking station callsign to/from the config file, but not saving the state of the tracking toggle. This means that the last tracked callsign will be remembered but tracking will not be on when Xastir starts up. 2008-09-09 22:17 we7u * src/db.c: A proper label for the new "Track Station" button on the Station Info dialog. 2008-09-09 22:11 we7u * src/db.c: Initial working version of "Track Station" from the Station Info dialog. Still needs additions to the language files for the button label. 2008-09-09 20:10 we7u * src/interface.c: Adding some comments near four areas that cause compiler warnings which we can currently do nothing about. 2008-09-09 20:09 we7u * src/testawk.c: Changing an int* to an int to get rid of a compiler warning about a mismatch. 2008-09-09 20:07 we7u * acinclude.m4: Adding /opt/local/ directory to the test for binaries (MacPorts). Changing the order of some compiler flags to help find GM before IM on FreeBSD systems. 2008-09-09 08:47 we7u * src/util.c: Changing the return type for a curl function to get rid of a warning caused by newer versions of libcurl. 2008-09-09 08:37 we7u * src/: main.c, track_gui.c: Adding #ifdef's around SED and MV calls. 2008-09-09 08:20 we7u * src/main.c: Added #ifdef around XFONTSEL call so that absence of the binary won't cause compile problems. 2008-09-08 09:13 we7u * ChangeLog, scripts/Makefile.am: Adding lang* scripts to package build. Updating ChangeLog to latest. 2008-09-03 08:46 gstueve * config/.cvsignore: Get CVS to forget about the generated language files. 2008-09-03 08:43 gstueve * src/main.c: Get valgrind to stop complaining about the lost blocks in the app_context. 2008-09-03 06:06 we7u * scripts/langPirateEnglish.pl: Translating "Maps" as well as "Map". 2008-08-31 16:45 we7u * scripts/langMuppetsChef.pl: Enabling more of the regex. Much better "translation". 2008-08-31 16:27 we7u * scripts/: langElmerFudd.pl, langMuppetsChef.pl, langPigLatin.pl, langPirateEnglish.pl: More updates to the derived language scripts. 2008-08-31 15:31 we7u * scripts/langOldeEnglish.pl: Rewriting the script so that anchoring & substitutions work in the regex. 2008-08-31 13:52 we7u * bootstrap.sh, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl: Updates to derived languages scripts, preparing for possible future uses. 2008-08-31 09:26 we7u * scripts/langPirateEnglish.pl: More for TLAPD. 2008-08-30 18:56 we7u * scripts/langPirateEnglish.pl: More Pirate updates. 2008-08-30 18:14 we7u * scripts/langPirateEnglish.pl: Latest Pirate updates. 2008-08-30 17:31 we7u * scripts/langPirateEnglish.pl: Added a few more Xastir-specific translations. 2008-08-30 16:30 we7u * INSTALL, README.Getting-Started, README.win32, bootstrap.sh, config/Makefile.am, help/help-English.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, src/main.c: Adding five new official languages to the "-l" flag in Xastir. 2008-08-30 16:28 we7u * scripts/: langElmerFudd.pl, langMuppetsChef.pl, langOldeEnglish.pl, langPirateEnglish.pl: Adding more official languages. 2008-08-29 22:21 we7u * scripts/langPigLatin.pl: Changing a comment to avoid the RCS tag substitution as well. 2008-08-29 22:19 we7u * scripts/langPigLatin.pl: Changed the match string so that RCS/CVS won't substitute a new Id: string in our REGEX expression. 2008-08-29 22:12 we7u * scripts/langPigLatin.pl: Renamed from PigLatin.pl 2008-08-29 22:11 we7u * scripts/PigLatin.pl: Moving this file to langPigLatin.pl 2008-08-28 08:14 gstueve * scripts/: get-maptools.sh, get_shapelib.sh: Use available resources to make use of temporary file as safe as possible. 2008-08-28 07:24 gstueve * scripts/get_shapelib.sh: Use same library logic as get-maptools.sh and clear temporary file for our use. 2008-08-28 07:22 gstueve * scripts/get-maptools.sh: Make sure to get temporary file out of way so we don't copy into something outside our expectation. 2008-08-27 06:25 tvrusso * acinclude.m4: Introduce proper quoting of AC_CACHE_CHECK arguments in XASTIR_GUESS_RUNPATH_SWITCH macro. 2008-08-27 06:23 tvrusso * acinclude.m4: Fix the XASTIR_GUESS_RUNPATH_SWITCH macro so that it uses AC_CACHE_CHECK with a CACHE-ID that conforms to the naming conventions expected. In versions of autoconf 2.62 and later, using a CACHE-ID without the "_cv_" string included in its name produces an annoying and possibly confusing warning message: configure.ac:572: warning: AC_CACHE_VAL(xastir_runpath_switch, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... acinclude.m4:1131: XASTIR_GUESS_RUNPATH_SWITCH is expanded from... acinclude.m4:1120: XASTIR_ADD_LIBPATH_TO is expanded from... acinclude.m4:964: XASTIR_BERKELEY_DB_CHK_LIB is expanded from... ../../lib/m4sugar/m4sh.m4:508: AS_IF is expanded from... ../../lib/autoconf/general.m4:2461: AC_COMPILE_IFELSE is expanded from... ../../lib/autoconf/general.m4:2469: AC_TRY_COMPILE is expanded from... acinclude.m4:1059: XASTIR_BERKELEY_DB_CHK is expanded from... configure.ac:572: the top level several times during bootstrap. By renaming "xastir_runpath_switch" to "xastir_cv_runpath_switch" throughout acinclude.m4, this warning is silenced and the variable is cached as intended. According to the autoconf documentation, cache variables *MUST* have the "_cv_" string in their names. It is only in recent versions of autoconf that violating this requirement is actually flagged as a warning. 2008-08-25 08:19 gstueve * src/testawk.c: Add prefix to indicate that we are printing hexadecimal value. 2008-08-21 09:50 gstueve * src/bulletin_gui.c: Make sure everything is allocated for bulletins before use. 2008-08-21 09:48 gstueve * src/dbfawk.c: Release memory & directory after we finish with them. 2008-08-18 19:02 gstueve * scripts/get-fcc-rac.pl: No need to extract unsorted file to disk. Process directly into script. 2008-08-15 13:24 we7u * configure.ac, scripts/BUILDRPMS: Setting up for 1.9.5 development versions. 2008-08-15 12:51 we7u * ChangeLog: Updating ChangeLog to match latest changes (for upcoming stable release). 2008-08-15 12:50 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Updating version numbers for upcoming stable release. 2008-08-15 12:41 we7u * configure.ac: Checking for curl/curl.h include file in the libcurl test to make sure we can actually compile with it. Also only check for wget if the libcurl tests fail. 2008-08-14 21:39 we7u * configure.ac: Adding a "--without-libcurl" option to configure. 2008-08-14 21:36 we7u * acinclude.m4: Slight reformatting of help text (added spaces). 2008-08-12 12:16 we7u * src/db.c: Changing a tab to a newline at the end of Tactical Call in Station Info box. This prepares us for longer tactical calls. 2008-08-05 20:03 gstueve * src/map_geo.c: Found one more place to release ExceptionInfo for ImageMagick, hopefully last needed to minimize unbalanced memory usage in maps. 2008-08-04 07:27 we7u * xastir-min.spec.in, xastir.spec.in, scripts/BUILDRPMS: Getting rid of include/Xm/Xm.h requirement in RPM build spec files. Uncommenting a few print statements in the BUILDRPMS script that were commented out by mistake. 2008-08-03 10:26 we7u * xastir-min.spec.in, xastir.spec.in: Updating to new path for Motif include files. 2008-08-03 09:18 we7u * scripts/BUILDRPMS: Preparing for creation of SuSE-11.0 RPM's. 2008-08-01 19:14 we7u * src/db.c: Adding debug_level filtering to the TACTICAL code. 2008-08-01 07:55 we7u * ChangeLog: Updating ChangeLog before doing -dev release. 2008-08-01 05:42 gstueve * src/: map_geo.c, map_WMS.c, map_tiger.c: Make sure that error returns are covered by ImageMagick release code. 2008-07-31 23:21 gstueve * src/map_gdal.c: Give GDAL a chance to release data from GDALAllRegister at end of run. 2008-07-31 20:24 gstueve * src/map_WMS.c: Make sure to deal with cleaning up ExceptionInfo when finished with map. 2008-07-31 20:20 gstueve * src/map_tiger.c: Make sure to cleanup allocated space before returning to caller. ImageMagick exceptionInfo needed to be destroyed when finished. 2008-07-31 17:09 we7u * src/: main.c, xa_config.c: Reverting to "fixed" font as the default for the SYSTEM and STATION fonts. 2008-07-30 08:24 we7u * src/: database.h, db.c, util.c: More Tactical Call changes: Assignments before a station shows up work. Clearing an assignment causes the string to be freed and the pointer nulled. Max tactical call length is now 57. 2008-07-28 02:10 we7u * src/db.c: Cleaning up the input parameters for one of the new tactical call helper routines. Leading/trailing spaces on callsign or tac-callsign affect the results little now. Lower-case callsigns are converted to upper case now. One minor annoyance: Blanking out callsigns using messages to TACTICAL results in this being displayed in the station chooser when there are more than one station under the mouse: "()". The proper display should be the callsign in that case, so perhaps spaces are still getting saved in the tactical callsign slot -or- the tactical callsign string isn't getting free'd and the pointer NULLed out (the latter is most likely). 2008-07-28 01:37 we7u * src/: db.c, util.c, util.h: The beginnings of being able to share Tactical Call data with others over the air. This code works, decoding messages sent to "TACTICAL" which are in one of these four formats: My Home WE7U-3=My Home WE7U-3=My Home;WE7U-12=Curt's Jeep;WE7U-15=I Don't Know WE7U-3=;WE7U-12=;WE7U-15= In the first case it'll assign "My Home" as the tactical callsign for the station that sent the message. In the last case it'll remove tactical callsigns for the listed stations. For testing remember that you can't send a new message to TACTICAL until the previous message has either timed-out or been cancelled. 2008-07-18 08:26 gstueve * scripts/get-NWSdata: Update to current Marine Zone. There are changes due in September for a few of the zone files. Need to watch for implementation date. 2008-07-11 15:03 tvrusso * acinclude.m4: Fix spelling error in AC_SEARCH_LIBS line for Magick/MagickCore. This is mostly irrelevant, because LIBS already has the right stuff in it if Magick-config --libs isn't lying, and for most users this test will be a no-op. 2008-07-10 08:46 chicoreus * src/db_gis.c: Issue: 2015173 Missing #ifdef for MySQL causes xastir to segfault when built with only --with-postgis. Found by Jeffrey Johnson. 2008-07-07 15:26 tvrusso * src/maps.c: Fix map metadata for upper left corner. Previously, the code was using the same coordinate pair to compute the upper left and lower right corner strings. For some reason, this ultimately made somewhat correct labels for UTM, but completely wrong labels for Lat/Lon. Since this simple change makes the code produce correct labels for all coordinate systems, and the other shouldn't have worked for any, I feel safe committing it. But I would have liked to understand why it worked at all for UTM. 2008-07-07 09:53 we7u * ChangeLog: [no log message] 2008-07-03 07:55 gstueve * src/alert.c: Increase size of titles for alerts to allow for large area alerts to be processed w/o loss of compressed info. 2008-07-03 06:12 we7u * src/db.c: If text on black background style selected, draw a black rectangle in that corner of the map first so that the scale lines show up well. 2008-07-02 17:12 gstueve * AUTHORS, src/main.h: Update current callsign for K4INT. 2008-07-02 12:06 gstueve * src/map_WMS.c: Remove extra fclose(f) of already closed file. Keep everyone happy. 2008-07-02 11:03 we7u * src/db.c: Decode DAO patch by Tapio Sokura, OH2KKU. This doesn't do anything with any datum transmitted, but does give us the extra precision sent via the DAO extension. We still need to change the white precision rectangle for the station on our map to make it smaller (not included in this change). 2008-07-02 06:54 we7u * src/db.c: Feature request 756236: Have Range Scale and Ruler text at bottom of map screen follow the same text style selection as the station text, to make them easier to read. 2008-07-01 20:04 we7u * src/: bulletin_gui.c, db.c, draw_symbols.c, geocoder_gui.c, interface_gui.c, list_gui.c, locate_gui.c, location_gui.c, main.c, map_geo.c, maps.c, messages_gui.c, objects.c, popup_gui.c, track_gui.c, view_message_gui.c, wx_gui.c, xastir.h: The remaining major updates to allow changing the "system" or "menu" font throughout the applicaton. 2008-06-30 18:47 gstueve * scripts/get-gnis: Remove extra path separator. 2008-06-30 16:40 we7u * src/: draw_symbols.c, main.c, maps.c, popup_gui.c, xa_config.c, xastir.h: Patches to implement a GUI interface for changing fonts, plus added error-checking to some of the font code. 2008-06-30 16:39 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: The first of two commits adding a GUI interface for changing system/ station/atv_id fonts. 2008-06-30 07:02 gstueve * scripts/get-gnis: Update path for file from USGS and adjust suffix for current file layout. 2008-06-27 13:10 we7u * src/main.c: More menus converted to allow using user-specified fonts. 2008-06-27 12:48 we7u * src/: main.c, popup_gui.c, xa_config.c, xastir.h: Adding the capability for users to specify the fonts used for the system fonts, station fonts (on map screen), and the ATV_ID font. Currently the users will have to edit the fonts in xastir.cnf, but later a GUI access method for editing can be added. 2008-06-27 12:45 we7u * src/maps.c: Fixing the initialization of arrays for map labels. 2008-06-27 06:41 we7u * configure.ac, src/main.c, src/track_gui.c: Adding path tests for "mv", "sed", and "xfontsel", plus the correct bits of code in the .c files to use those paths. 2008-06-26 12:10 we7u * src/main.c: Specifying more of the font characteristics for the font used when USE_LARGE_STATION_FONT is defined. 2008-06-26 07:41 we7u * src/db.c: A fix for the Citizen's Weather filter to get rid of the new "DW" prefixed stations, plus more strict filtering so that we don't also get rid of Uruguay and Phillipines weather stations with this same filter. 2008-06-25 16:30 we7u * src/main.c: Fixing the system fonts so that they work on more systems. 2008-06-25 06:41 we7u * scripts/toporama250k.pl: Updated the instructions for running the script plus got rid of DOS line-end characters that had somehow crept in. Those line-end characters prevented the Perl interpreter from running on Linux. 2008-06-25 06:39 we7u * scripts/toporama50k.pl: Updated the instructions for running the script. 2008-06-25 06:38 we7u * help/help-English.dat: Changed the name of the fcc-get script to get-fcc-rac.pl 2008-06-25 06:37 we7u * src/db.c: Station Info: Special-case check for objects sent by "WINLINK". We keep the object name as the "origin" in this case instead of "WINLINK". This solves the "FCC" instead of "RAC" button problem for objects with Canadian callsigns, allowing us to look of RAC licensing information. 2008-06-24 08:52 we7u * README.Getting-Started, README.MAPS: Updating the name of the get-fcc-rac.pl script in the docs. 2008-06-24 08:48 we7u * scripts/: Makefile.am, fcc-get, fcc-get.pl, get-fcc-rac.pl: Combined fcc-get and fcc-get.pl into one script called get-fcc-rac.pl 2008-06-23 15:42 we7u * README: Adding the SuSE-11.0 Ham Radio repository URL. 2008-06-13 06:43 gstueve * scripts/get-NWSdata: Remove the bashism to keep people happy. 2008-06-13 00:37 gstueve * config/nwsz_ddmmyy.dbfawk: Actually get the signature template right for Watches. 2008-06-13 00:25 gstueve * config/: nwsmzddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Actually get the template to match the available dataset. 2008-06-12 20:27 gstueve * scripts/get-NWSdata: Missed that one of the files was in a different directory. 2008-06-12 18:49 gstueve * scripts/get-NWSdata: Introduced bashism to reduce size & improve consistency for all files. 2008-06-12 12:30 gstueve * config/Makefile.am, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, scripts/get-NWSdata: Adjust script and dbfawk for current set of files from NWS. There are newer sets of files for upcoming dates. 2008-06-11 06:39 gstueve * src/x_spider.c: Reduce side effects of free memory by clearing pointer after deallocation. 2008-06-09 12:28 we7u * scripts/: LSB-BUILD, LSB-BUILD-ALL, LSB-BUILD-GRAPHICSMAGICK: Committing latest changes for LSB build. Am not done yet getting LSB to build properly on OpenSUSE-10.3, but this is a good start. 2008-06-09 12:25 we7u * ChangeLog: Keeping it up to date with CVS commits. 2008-06-09 12:23 we7u * scripts/do_xastir_release_stable: Changed SF upload process to match what they currently allow. 2008-06-09 12:23 we7u * scripts/do_xastir_release_dev: Change SF upload process to match what they currently allow. 2008-06-04 04:23 gstueve * src/db.c: Allow Objects that have space in name to work with Tactical Call Sign addition. 2008-05-30 08:32 gstueve * src/db.c: Add tactical call sign to station pick list when multiple stations under cursor. 2008-05-29 10:15 we7u * FAQ, README.Getting-Started: Updating some of the PATH wording. 2008-05-27 12:04 gstueve * src/messages.c: Start fixing elements to allow Group & Bulletin messages to go unacknowledged. 2008-05-21 09:08 tvrusso * src/util.c: Fix makeMultiline (an unused function) so that it produces offsets in the same sense that xastir decodes them --- i.e. that positive longitude offsets are west of the reference point. 2008-05-09 11:20 gstueve * src/interface.c: Make sure not to add break character if no altitude to be reported. 2008-05-09 11:18 gstueve * src/: util.c, util.h: Make sure course and speed are treated as non-negative numbers only. 2008-05-06 04:05 gstueve * scripts/fcc-get.pl: Remove extra CR at end of each line and deal with full list only once. 2008-05-05 13:00 gstueve * scripts/: Makefile.am, fcc-get, fcc-get.pl: Adjust fcc file processing to deal with vanity call update. 2008-05-02 09:58 tvrusso * acinclude.m4: Change "AC_CHECK_LIB" to "AC_SEARCH_LIBS" for ImageMagick. A recent update to ImageMagick stuffs the "WriteImage" function into libMagickCore instead of libMagick, and the older probe was missing it. With this change, I see that WriteImage gets found without adding anything to LIBS, because "Magick-config" already stuffed the right thing into LIBS. 2008-04-13 22:31 we7u * src/util.c: Fixing a bug found with latest wget: --timestamping and -O options can't be used together. Getting rid of the timestamping option which we can live without. 2008-04-13 21:31 we7u * src/util.c: Updating wget and libcurl fetches to specify "Xastir" as the user-agent string in the request. This is to support the new restrictions that findu.com has implemented. 2008-03-20 21:11 chicoreus * src/: db.c, interface_gui.c, main.c: Minor cleanup of comments and un-needed code from testing problems with database connections. 2008-03-20 21:00 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c: Identified and fixed problem underlying stability of multiple database connections (space for connection structures was incorrectly allocated so that writing an error message into one connection overwrote memory used by another connection). Fixed additional problems related to connection failures and added more resilience to database connection problems. 2008-03-18 19:10 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c, main.h: Overhaul of the way sql database connections are handled, reducing the complexity by eliminating the ConnectionList struct, and creating an array of Connections, one for each interface. More than one database connection can now be run at once, though there is still an issue with pointers or memory handling somewhere and instabilites can be produced by stopping and starting database connections. Moved all the db_gis related debug_level tests from 1 to 4096. 2008-03-11 20:27 tvrusso * acinclude.m4: Fix a fairly dumb thing in the probe for Berkeley DB --- it was always resetting the result (BDB_LIB_FOUND) to "-ldb" even if the actual library found was something else. This variable was used only to report to the user what library was found, never as the actual "-l" flag. This could have led to confusion, but not improper operation. 2008-03-06 12:47 we7u * scripts/BUILDRPMS: Updating to SuSE-10.3 for generation of RPM's. 2008-03-03 20:00 tvrusso * README.MAPS: Add link to FAA digital data products web site. You can purchase FAA sectionals in GeoTIFF format there. 2008-02-29 08:54 chicoreus * src/: database.h, db.c, db_gis.c, interface_gui.c: Added trails to db_gis code. Multiple points from one station retrieved from a database query are added as trailpoints. Existing stations heard from other sources and retrieved from a database query aren't duplicated as DataRows, but have appropriate trail points added (if the existing position is older than the database data, the existing position becomes as trailpoint; if the database data is older, it gets added as trailpoints). Added timeformat to add_simple_station, as Postgresql and MySQL timestamps don't both include the local timezone "%z" in the current simple station query formats. Added APRS_WXn character constants as a workaround, since AprsTypes and Record Type character constants are used inconsistently in DataRow.record_type, and AprsTypes without character constants don't write cleanly into MySQL or Postgresql database records. Added and commented out lines to start database connections from interfaces Left commented out as multiple open database connections are still unstable and segfault. 2008-02-27 20:02 gstueve * scripts/fcc-get: FCC moved the database again. Look for it in new place. 2008-02-21 20:57 chicoreus * src/: database.h, db.c, db_gis.c, interface.c: Improvements to the tollerance of the db_gis code to problems with connections to databases and improved reporting of problems in making connections. Added code to add tracks for stations retrieved from the database. Still needs work, as the existing db.c code for adding stations and points to the tracks of stations makes different assumptions about the order in which positions are recieved than the order of records queried in db_gis.c. 2008-02-21 20:51 chicoreus * scripts/: db_gis_mysql.sql, db_gis_postgis.sql: Adding some indexes to speed up retrieval of station records. Adding a view that could be used with mapserver to return icon files for each station. 2008-02-16 08:15 we7u * src/main.c: Switching the Garmin RINO processing to use uncompressed packets for now as there is a problem with either this section of code or the Compressed encoding code for particular positions. Change the ABOUT message to include additional copyright information. 2008-02-07 18:47 chicoreus * src/: main.c, main.h, maps.c, maps.h, xa_config.c: Adding two new KML export features: 1) KML Snapshots - on a regular basis (using the same timing as PNG snapshots), write all currently known stations to a kml file. 2) KML file to accompany PNG snapshots. After converting snapshot.png to snapshot.jpg, the accompanying snapshot.kml file can be used to layer the snapshot.jpg image on the landscape in a kml application. The KML produced is valid and appears to work, but hasn't been extensively tested. This (along with the allready committed export a single station track to kml feeature) should complete the feature request for KML export: http://sourceforge.net/tracker/index.php?func=detail&aid=1863377&group_id=45562&atid=443274 2008-02-07 18:35 chicoreus * help/help-English.dat: Added help text describing KML export and snapshot features. 2008-02-07 18:33 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding menu item for regular snapshots of all heard stations to a kml file, analogus to png snapshots. 2008-02-07 18:29 chicoreus * scripts/: kml_snapshot_feed.kml, kml_snapshot_to_web.sh: An example kml file and a shell script to allow png snapshots with their accompanying snapshot.kml file to be used as a regularly updated kml feed on a webserver (allowing the current snapshot from xastir to be draped over the landscape in a kml application remotely subscribing to the feed.) 2008-01-29 19:08 chicoreus * help/help-English.dat: Correcting a spelling error (found by Curt). Placing more references to button titles in quotes to make the description of the station info dialog more consistent. Clarifying (hopefully) some of the description of saving tracks from the station info dialog. 2008-01-25 21:45 chicoreus * src/: db.c, util.c, util.h: Added a utility function to return a date/time in w3c timestamp format, required for valid timestamps in kml files. Rearranged the log station to kml code, and added timestamped placemarks for each location of a station in a track. This produces kml output that validates, and should behave like the "Shroeder" whale shark example file (moving a station location along its track as a time slider control is moved in Google Earth). This has not yet been tested to see if the behavior is as desired. 2008-01-24 22:21 chicoreus * INSTALL, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat: Localization for Station->Export All->Export kml menu items. User documentation of KML export. User documentation for spatial database support. Added some fault recovery comments to spatial database configuration section of INSTALL. 2008-01-24 22:18 chicoreus * src/: database.h, db.c, main.c: Adding Station->Export all menu, with option to export all station records to a single kml file. 2008-01-24 14:36 chicoreus * src/: interface_gui.c, main.c, objects.c: Fix for bug 1863228. Lesstif doesn't yet fully support combo boxes, which are used in 4 places in Xastir (for user configurable predefined objects file in defaults dialog, cad object line type in the cad object details dialog, and twice in the interface properties dialog when defining a sql database interface. An alternate lesstif menu that mimics a combo box control (modified from xpdf's XPDFViewer.cc), is applied in three of these four cases (the fourth currently only has a single option, and might not be the best control for the situation, picking database schema type[s]). This has been tested on lesstif 0.94.4 and openmotif 2.3.0. 2008-01-23 00:23 we7u * src/interface.c: Added "volatile" keyword to a couple of variables to assure they don't get overwritten by longjmp. 2008-01-22 23:34 we7u * src/track_gui.c: Converting from mucking with pointers to pass to variables to a thread, to passing a pointer to a struct instead. This last method should avoid architecture-dependent problems in the download findu trail processing. 2008-01-22 23:08 we7u * src/track_gui.c: Added a comment regarding a section of code which does type-punning and may be architecture-dependent. 2008-01-22 23:07 we7u * src/messages.c: Commented out "altgroup" section of conditional which always equates to true ('cuz it's an address). 2008-01-22 23:05 we7u * src/interface.c: Added a couple of comments. 2008-01-22 22:00 we7u * src/map_cache.c: Reformatting debug statement so that it won't generate compiler warnings. 2008-01-22 20:49 we7u * src/wx.c: Fixing a buffer overrun. Found via a compiler warning on OpenSuSE-10.3 2008-01-22 20:48 we7u * src/map_geo.c: Reformatting a debug statement so it won't cause compiler warnings. 2008-01-22 20:47 we7u * src/map_gdal.c: Getting rid of a conditional that always evaluates as true: The address of "label". 2008-01-22 20:46 we7u * src/map_dos.c: Fixing an array overflow condition that has existed for a LONG time. Found via a compiler warning on OpenSuSE-10.3 2008-01-22 20:45 we7u * src/map_WMS.c: Changing debug statement format so it won't cause a compiler warning to be issued. 2008-01-22 20:43 we7u * INSTALL: Adding a note about RINO's: That Xastir cannot cause a poll of the remote RINO units over the air. 2008-01-18 18:49 chicoreus * src/db_gis.c: More cleanup of db_gis code. 2008-01-18 18:48 chicoreus * src/main.c: Adding test in UpdateTime to avoid opening the same database interface twice during startup if it is marked to both activate on startup and load stations on startup. 2008-01-17 19:21 chicoreus * src/: db.c, db_gis.c, main.c: Minor stability improvements to db_gis code. Adding some sanity checks for null database connections when running queries to reduce segfaults. Begining cleanup of the db_gis code. Removing some leftover unused variables and code. Explicit type casting of some pointers in function calls to suppress compiler warnings. 2008-01-16 20:33 chicoreus * src/: database.h, db.c, db_gis.c, main.c, objects.c: First pass at exporting station tracks as kml files. On clicking store track on the station information dialog, both an xastir format file and a kml file for the selected station will be written to ~/.xastir/tracklogs Added more comments on how database schema version and series compatability should work. Fixed (superficially) a bug where station data would be written to a non-open database connection causing a segfault. Connection handling in db_gis is fragile and needs review. 2008-01-16 11:38 we7u * scripts/: BUILDRPMS, LSB-BUILD: Updating to 1.9.3 release number. 2008-01-16 11:33 we7u * AUTHORS, ChangeLog, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/PigLatin.pl, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-NWSdata, scripts/get-gnis, scripts/get-maptools.sh, scripts/get_shapelib.sh, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating the copyright notices for 2008. 2008-01-16 10:32 we7u * configure.ac: Preparing for devel release, bumping revision number. 2008-01-10 07:35 chicoreus * src/: interface.c, main.c, objects.c: Fixing bug where objects/items created by the user are not displayed until Xastir is restarted. Adding more debugging information when loading predefined objects from a file. 2008-01-09 21:06 chicoreus * src/: db.c, db_gis.c: Fix from Curt for some compile warnings in xastirWKTPointToLatitude(). Fix to incorrect data being written to MySQL table simpleStationSpatial in the origin and node_path fields. Note: When selecting data from MySQL simpleStationSpatial, use the AsText() function on position. For example, to retrieve the 10 most recently heard stations: select station, symbol, overlay, aprstype, AsText(position), transmit_time, origin, record_type, node_path from simpleStationSpatial order by transmit_time desc limit 10 ; 2008-01-08 17:22 chicoreus * src/interface.c: Possible bug fix for the can't have two sql database interfaces open at the same time issue. Pointers around Connections need review. 2008-01-08 07:00 chicoreus * src/: db_gis.c, db_gis.h, interface.c, main.c: db_gis.c closeConnection now linked to stop button on interfaces. SQL database state (open,closed,error[on connect only]) state shown on interface list. 2008-01-07 20:35 chicoreus * INSTALL, scripts/db_gis_mysql.sql, scripts/db_gis_postgis.sql, src/db_gis.c, src/interface_gui.c, src/objects.c: Added some installation instructions for spatial database support. Added a workaround for lesstif not having full implementation of combo boxes (borrowed from xpdf's XPDFViewer.cc) to the dbms selection control on the spatial database interface dialog. Fix needs to be propagated to several other places. Fixes to sql scripts to build mysql and postgis database tables. 2008-01-01 14:58 chicoreus * src/: database.h, db.c, db_gis.c, db_gis.h, interface.c, interface.h, interface_gui.c, main.c, main.h, xa_config.c: Significant updates to db_gis code, supporting storage of station data to both MySQL and postgis enabled Postgresql databases. Stations heard in Xastir can have the core station information logged to either a Postgres or MySQL database (Bug: currently both aren't working at the same time), and then retrieved in a subsequent Xastir session (or by a different Xastir instance, or by another GIS application (such as QGIS over a postgis database populated from Xastir)). Tested with MySQL 5.0.32, may not work with MySQL 4.1. Tested with Postgres 8.1.9 2008-01-01 14:50 chicoreus * scripts/: db_gis_mysql.sql, db_gis_postgis.sql: Adding sql scripts to create tables for persistent storage of basic station data. One script for mysql, another for postgis enabled postgresql. Currently only supports a single simple table with the minimun station information. 2007-12-18 12:56 tvrusso * configure.ac: Fix improper probing of curl library when LSB is not being used. AC_CHECK_LIB can have two or three arguments. With two arguments it tests for the presence of a function named in the second argument in the library named by the first argument, and if found defines HAVE_LIBxxxxx and adds -lxxxxx to LIBS. In the three-argument case, it does the probe the same way, but instead of the default "define HAVE_LIBxxxxx and add -lxxxxx to LIBS" it does what it's told in the third argument. That means if you want to rely on HAVE_LIBxxxxx and LIBS="${LIBS} -lxxxxx" then you have to do it yourself in the third argument. The AC_CHECK_LIB for curl was only doing the extra thing, which was to set "use_curl" to "yes". I recently discovered this by trying to build and use xastir on a freshly installed system that had libcurl but no wget (most of my other systems have both). The bug in the use of AC_CHECK_LIB meant that libcurl was found, but never linked in nor was HAVE_LIBCURL ever set in config.h. With this fix, curl is now both properly detected *and* the detection properly communicated to the code. 2007-12-13 22:23 tvrusso * config/tgr2shp.dbfawk: Add "P" feature class to handle "Provisional" road data in TIGER/Line shapefiles. According to the TIGER/Line Technical Documentation for feature class "P" The U.S. Census Bureau has created a new CFCC type that may appear on street features only. Some streets that normally would be classified as "A" class features may be coded with a "P" instead of the "A" to indicate that the feature is a a "provisional" feature. Provisional features are those streets that were added from reference sources or other programs in preparation for Census 2000, but were not field verified by census staff during field operations or through the use of aerial photography or imagery. As these featues are verified in futuer operations the provisional flag will be removed for subsequent TIGER/Line releases. The numeric portion of the CFCC still classifies the street as if an "A" were preceding it. So this just involves changing the matching pattern from CFCC=A... to CFCC=[AP]... in all the feature-class A rules. 2007-12-05 08:40 tvrusso * README.MAPS: Add more text to the section on Geocommuity's DRG Data Bundle deals. Turns out that some areas have DRGs produced by some agency other than the USGS, and those agencies don't necessarily produce GeoTiff files with proper metadata. The Tennesee Valley Authority is among those agencies that don't properly include GeoTiff tags for projection and datum. This renders DRG data bundles for states with portions of their area covered by the TVA partially defective --- special preprocessing is necessary to get the files into a state that can be used in Xastir. 2007-11-14 07:05 tvrusso * README.MAPS: Add a pointer to a vendor of inexpensive GeoTIFF format DRGs for the US. They're one of the USGS's data partners that is listed elsewhere in the document, but in a different context. Thanks to Eric, KZ5ED, for calling it to my attention. 2007-11-07 13:37 tvrusso * src/: main.c, map_WMS.c, map_geo.c, map_tiger.c, maps.c: Work around the fact that ImageMagick's api.h rudely includes their autoconf-generated config.h, which therefore defines the same PACKAGE and VERSION macros that we do. In most files, this produces an annoying but harmless warning message about a redefinition. For main.c, however, it cause Magick's PACKAGE name and VERSION to be used in place of our own. That is, our About window will announce that we're ImageMagick version 6.3.x. For the files in which it's a harmless warning, I've done an #undef of the two macros to shut up the compiler warnings. In main.c, I've created two new char* variables and initialized them to PACKAGE and VERSION before including magick's api.h, and then undef'd them. This preservs the contents of our macros by substituting them in C code right away, then gets rid of them so the warnings are shut up. Attempting to do: #define XASTIR_PACKAGE PACKAGE #undef PACKAGE #include #undef PACKAGE #define PACKAGE XASTIR_PACKAGE doesn't help. All that does is silence the warning. Magick's package name is still used when we try to use the PACKAGE macro later. Macro expansions aren't variable assignments, and the code above does nothing more than define PACKAGE to PACKAGE and thence to "ImageMagick", after briefly allowing api.h to change its meaning without warning. Adding an "#undef XASTIR_PACKAGE" after all that is even worse, and results in fatal compilation errors. There's probably some preprocessor game that can be played to kludge this, but saving the string we want to keep somewhere where it's safe from preprocessor meddling seems the better choice. 2007-11-06 09:10 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.2 stable release. 2007-09-24 19:41 we7u * src/track_gui.c: Finished the regex code for converting HTML->Text for downloaded findu.com tracks. 2007-09-22 03:53 we7u * src/track_gui.c: Commenting out unused variable. 2007-09-22 03:25 we7u * configure.ac: Commenting out the html2text discovery code. 2007-09-22 03:25 we7u * configure.ac: Checking in the html2text discovery code in case we may want it in the future. 2007-09-22 03:24 we7u * src/track_gui.c: Doing the html2text via sed statements. 2007-09-22 01:29 we7u * src/track_gui.c: Converting the downloaded findu.com raw packets from HTML to text. Still need to look for "html2text" and find out it's path in the autoconf scripts in order to integrate this properly. 2007-09-16 18:31 tvrusso * src/interface_gui.c: Fix misplaced #endif /* HAVE_DB */ that was breaking the gui for networked AGWPE. 2007-09-04 13:09 we7u * src/db.c: Changing the new variable "i" to "ii" to make it easier to search for in the sources, plus getting rid of the declaration for the case where we're not using an SQL database (to get rid of a compiler warning). 2007-08-31 05:20 gstueve * src/map_geo.c: Add subroutine to release memory consistently for exit points. 2007-08-28 16:16 we7u * scripts/PigLatin.pl: Updated one comment. 2007-08-28 15:32 we7u * scripts/PigLatin.pl: Initial commit. 2007-08-24 06:44 gstueve * src/igate.c: Push active groups through the gateway between RF<->INet. 2007-08-24 06:42 gstueve * src/: messages.c, messages.h: Export group_active for use in igate of group transmission list. 2007-08-22 08:42 gstueve * src/alert.c: Make sure to test against initialized data. 2007-08-20 20:10 chicoreus * src/db.c, src/db_gis.c, src/db_gis.h, src/interface.c, src/interface_gui.c, src/main.c, symbols/symbols.dat: Cleaning up db_gis code. Some cleanup of error messages. Moved some debugging messages into debug_level & 1. Altered simpleStation table structure to add three more columns: alter table simpleStation add column origin varchar(9) not null default ''; alter table simpleStation add column record_type varchar(1); alter table simpleStation add column node_path varchar(56); These seem necessary for recreating DataRow records out of simpleStation database records. Added more testing and handling of data that is to be written to database records. Still needs better sanitizing. Tested saving DataRow records derived from internet feeds to MySQL (old), and Postgresql(8)/Postgis records. 2007-08-20 12:22 we7u * src/main.c: Adding two casts to (int *) back in. They are required to get rid of compiler warnings with some versions of GCC. 2007-08-17 15:08 gstueve * src/: map_WMS.c, map_cache.c, map_geo.c, map_tiger.c: Make sure to free allocated memory after we are done playing with it. 2007-08-16 12:28 gstueve * src/main.c: Make sure colors are identified as Pixel not int types. 2007-08-16 12:26 gstueve * src/list_gui.c: Make sure SL_scroll is initialized for full operation. 2007-08-16 10:36 gstueve * src/map_geo.c: Make sure we return the exception data to free space when done. Don't leave it as unclaimed uggage. 2007-08-16 10:01 gstueve * src/list_gui.c: Make sure the station_list displays give back the memory after they are done playing with it. They are not expected to lose it. 2007-08-15 10:57 gstueve * src/draw_symbols.c: Pixel values are 'unsigned long' not 'int' on 64 bit machines. 2007-08-15 10:41 gstueve * src/: main.c, main.h, xastir.h: Type of colors & trail_colors is Pixel, not int. Especially on 64 bit machines. 2007-08-15 08:44 we7u * src/map_cache.c: Backing out this change as it caused this error and Xastir to blow up when a new map image was cached to disk: "glibc detected *** double free or corruption" 2007-08-14 09:41 we7u * src/util.c: Adding a minor comment. Thanks to Gerald Stueve for re-examining all this code. He's doing a WONDERFUL job of finding/fixing bugs! 2007-08-14 09:28 we7u * src/: db_gis.c, db_gis.h: Adding the RCS ID tag and tweaking the copyright statements to show correct dates and attribution for these two files. 2007-08-13 13:23 gstueve * src/main.c: Clear entire block of appshell, not just first pointer space. 2007-08-13 13:22 gstueve * src/x_spider.c: No need to have extra layer of callback, go directly to exit. 2007-08-13 12:55 gstueve * src/x_spider.c: Allow the subprocesses to cleanup and exit on interrupt. 2007-08-13 12:54 gstueve * src/rac_data.c: Make sure we aren't checking against unitialized data. 2007-08-13 09:17 tvrusso * README.MAPS: Add the answer to a frequently asked question about TIGER/Line 2006 SE shapefile zip files ("what's the difference between the Polylines and Polygons directory?"). 2007-08-11 19:00 chicoreus * src/: db_gis.c, db_gis.h: Simple schema insert added for Postgresql/postgis. Tested with Postgresql 8.2 and postgis 1.2.1. Simple station records can now be written to MySQL and Postgresql/Postgis databases, but xastir can't yet extract any data back. 2007-08-10 16:15 gstueve * src/util.c: Make sure to initialize string before testing fixed offset values. Valgrind identified the dereferences with errors. 2007-08-10 16:11 gstueve * src/map_cache.c: Valgrind again. Make sure to release memory after using it. 2007-08-10 16:09 gstueve * src/db.c: More valgrind identified errors. Make sure to initialize tested variables. 2007-08-10 15:48 gstueve * src/x_spider.c: Add clear_proc_title to clean up environment pointers. 2007-08-10 07:06 gstueve * src/x_spider.c: valgrind is our friend. Make sure not to step back too far for line end. 2007-08-09 13:12 gstueve * src/map_shp.c: Make sure to Destroy a region before overwriting the value. Identified by valgrind. 2007-08-09 07:07 gstueve * src/wx_gui.c: change to newer function - item = XmStringCreateLtoR(temp, XmFONTLIST_DEFAULT_TAG); + item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); to replace deprecated function. 2007-08-08 08:29 we7u * src/interface.c: Moving one of the SQL debug printf's inside an #ifdef block so that we won't normally see it. 2007-08-07 18:55 chicoreus * src/: db_gis.c, db_gis.h: Change to error handling in the event of an xastir coordinate for a station that doesn't translate to a valid lat/long - returns error message indicating conversion problem rather than as database problem. 2007-08-07 13:33 gstueve * src/map_pdb.c: Allow more granularity for debugging actions. Remove unneeded global definitions. 2007-08-07 10:29 chicoreus * src/interface_gui.c: Removing some unecessary debugging messages. 2007-08-07 09:24 chicoreus * src/: interface.c, interface_gui.c: Bug fix - SQL database interface definitions were always being placed as interface 0 in the interface list. 2007-08-07 09:08 we7u * src/interface.c: Adding "#ifdef HAVE_DB" around the SQL database interface type so that it doesn't appear in the list unless configure finds that we have support for it. 2007-08-07 09:05 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding the SQL Database string to the other language files. 2007-08-07 08:31 we7u * src/messages_gui.c: Commenting out an unused variable which causes a compiler warning. 2007-08-07 08:31 we7u * src/interface_gui.c: Adding "#ifdef HAVE_DB" around a couple of fprintf's. 2007-08-06 18:06 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/db.c, src/db_gis.c, src/db_gis.h, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c, src/messages_gui.c, src/util.c, src/util.h, src/xa_config.c: Further work on sql server (MySQL/Postgis) support. Began integration of sql connection management with interface UI. Able to create a connection to a MySQL database, and on starting it, save list of all current stations to a simple single table db. Code still needs substantial work before it is usable. 2007-07-30 10:13 we7u * INSTALL: Updating libgeotiff instructions for latest released version (1.2.4). 2007-07-27 08:55 we7u * README.Getting-Started: Adding another note explaining that "internal" on the Shapelib summary line is ok. 2007-07-27 08:48 we7u * README.Getting-Started, configure.ac: Getting rid of the "Building with" text on the configure summary line. Fixing one of the README's to match. 2007-07-25 08:53 we7u * INSTALL: Revising the install instructions for the optional Shapefile utilities to correspond to the current sources. 2007-07-25 08:45 we7u * src/shapelib/contrib/: dbfcat.c, dbfinfo.c, shpcat.c, shpcentrd.c, shpdxf.c, shpfix.c, shpgeo.c, shpinfo.c, shpproj.c: Adding includes necessary for warning-free compiles. 2007-07-25 08:45 we7u * src/shapelib/contrib/.cvsignore: Adding shpproj executable to CVS ignore. 2007-07-25 08:37 we7u * src/shapelib/: Makefile_shapelib_orig, shpcreate.c, shpdump.c, shprewind.c: Added shprewind.c to the "clean" target of the original Makefile. Added stdlib.h includes to some of the utilities to get a clean compile. 2007-07-25 08:10 we7u * INSTALL: Adding instructions for compiling some of the optional Shapelib utilities and contributed Shapelib utilities. 2007-07-23 09:58 we7u * src/db_gis.c: Moving the strtof test below the config.h include. 2007-07-23 08:58 tvrusso * configure.ac, src/db_gis.c: Fix up usage of strtof for systems that are so old they don't have this function. 2007-07-18 09:20 we7u * src/db.c: Correcting a spelling error in a debug statement. 2007-07-16 07:38 chicoreus * INSTALL: Fixing typo in install documentation. Patch from Jim Tittsler - jtittsler Tracker: [ 1695864 ] INSTALL typo ImageMagick->GraphicsMagick 2007-07-14 20:39 chicoreus * src/main.c: [no log message] 2007-07-14 20:37 chicoreus * src/: Makefile.am, db_gis.c, db_gis.h, lclint.script: Framework for spatial database support. Should compile, but won't do anything yet. 2007-07-14 20:33 chicoreus * acinclude.m4, configure.ac: Adding tests for MySQL, Postgresql, and Postgis for spatial database support 2007-07-09 20:03 tvrusso * README.MAPS: Fix up mistaken information about TIGER/Line data. Update pointers to geocoding files (we were still pointing users to the 2003 data, which is a poor match to recent TIGER/Line shapefiles). 2007-07-06 15:43 we7u * configure.ac: For the summary, we now refuse to display the developer section unless one of those options has been enabled. This is so normal users don't have to worry about that section. 2007-07-06 15:06 we7u * configure.ac: More additions to the summary output. 2007-07-06 14:32 we7u * configure.ac: Changing some of the summary text. 2007-07-06 12:24 we7u * src/main.c: Bumping up the size of the Help->About "Libraries Used" string. 2007-07-06 12:17 we7u * configure.ac: A few more small tweaks to the configure summary output. 2007-07-06 12:04 we7u * configure.ac: Reformatting the configure summary output. Adding wget/libcurl to the summary as well. 2007-07-02 16:43 tvrusso * configure.ac: Remove hack to use external rtree library --- differences between GRASS's rtree library and ours make it so that we can't use them interchangably. The difference is in the size of floating point variables used in the Rect structure (we use floats as did the original author, GRASS uses it modified to have doubles, which vastly increases memory usage for no real gain). This should remedy all of the Fedora users problems. Unless it doesn't. 2007-07-02 16:37 tvrusso * src/: map_shp.c, shp_hash.c, rtree/card.c, rtree/card.h, rtree/index.c, rtree/index.h, rtree/node.c, rtree/rect.c, rtree/split_l.c, rtree/split_l.h: Turns out that putting a suffix on all symbols in the rtree library was very simple and fast, so I Just Did It. This should probably fix the problem for Fedora users with GDAL installed from repository, once I remove the "external rtree" bit from configure.ac. 2007-07-02 15:08 we7u * FAQ: Adding a section to the Map Problems/Solutions question about deleting the Xastir user directory and starting over when all else fails. 2007-07-02 14:34 we7u * FAQ: Added some debugging instructions for maps not working. 2007-07-02 14:19 we7u * FAQ: Updating the version number where "APX" is quoted. 2007-07-02 12:34 we7u * FAQ: Added a question/answer about how to solve the problem: station trail not displaying. 2007-07-02 12:12 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the ALTNET box so that it is smaller and has a label. 2007-07-02 05:55 tvrusso * src/rtree/: split_l.c, split_l.h: Undo the CoverSplit->l_CoverSplit change made last week. The real issue was that some repositories have a GDAL that includes GRASS libraries including a libgrass_rtree that duplicates the rtree functionality. Xastir's rtree library is precisely the one that GRASS uses (based on public domain (i.e. uncopyrighted) software from www.superliminal.com), and this leads to a link conflict that produces an obscure and cryptic error message at link time. Renaming the CoverSplit variable was just a band-aid that was suggested for a trial run while diagnosing the problem, not a recommended fix. 2007-07-01 21:20 tvrusso * configure.ac: Add a note at the end that tells whether we're using external rtree (e.g. from GDAL) or our own internal version. 2007-07-01 21:12 tvrusso * configure.ac: Fix configure so that it checks for the presence of RTreeSearch in other libraries before it builds our own rtree library. This is necessary because some repositories have a GDAL that was built with GRASS support (against current recommendations), and that brings in an rtree library unbidden. The result of trying to link our own in unconditionally is a cryptic message about CoverSplit not being relocatable. The only testing I've done is that this doesn't break builds with GDAL that has no GRASS support. I am unable to test it in the case for which it is intended. I'll have to ask that someone with an F7 system do that. 2007-06-29 13:22 we7u * src/rtree/: split_l.c, split_l.h: Trying a rename of CoverSplit to l_CoverSplit to see if this fixes the Fedora linking problem. 2007-06-21 12:10 we7u * src/interface.c: Removing stale lockfiles when it was our own process group which created them earlier. 2007-06-20 09:25 we7u * src/map_geo.c: Adding a few comments to the code for the new transparent color linked list functions. 2007-06-20 09:18 we7u * README.MAPS: Tweaking the TRANSPARENT note to state that multiple lines may be used. 2007-06-20 09:11 we7u * WMSRadar.geo, src/map_geo.c: Commenting out debug fprintf plus adding another black and a white color as transparent colors to WMSRadar.geo. 2007-06-20 08:42 we7u * src/: main.h, map_WMS.c, map_geo.c, maps.h: First attempt at multiple TRANSPARENT support for .geo files. Not fully tested yet, but doesn't appear to fall over either. 2007-06-15 11:44 we7u * scripts/LSB-BUILD: Updating to latest rev number for release. 2007-06-10 09:53 tvrusso * scripts/get-NWSdata: Update get-NWSdata to pull down the new files instead of trying to get some old and now non-existent files. 2007-05-28 16:59 chicoreus * src/: main.c, main.h, objects.c: Disabling close polygon item on CAD menu when not in draw mode. 2007-05-28 12:53 tvrusso * src/util.c: Fix a comment about multiline length. 2007-05-28 12:51 tvrusso * src/: db.c, util.c, util.h: Make the add_comment function stop stripping leading spaces. This is to allow multiline objects with no leading text, which otherwise get broken. Add a makeMultiline function to util.c. Given arrays of lat/lon pairs, will produce a multiline string representing that array and a centroid value that can be used for creating an object. Bunch of debugging output added to extract_multipoint that I needed to help me track down why my multilines were disappearing (it was because of the leading space stripping). Nobody is calling makeMultiline yet. It could be used for transmitting CAD objects if someone wanted to hack that in. I've tested makeMultiline in an external program to generate strings, then created objects by pasting the strings into the comment box of the create object dialog. 2007-05-21 07:51 tvrusso * README.MAPS: Update the TIGER/Line information. 2007-05-09 10:36 tvrusso * config/: Makefile.am, tgr2shppoly_2006.dbfawk: Add a new DBFAWK file for the 2006 TIGER/Line data. This data has "UACU" and "URCU" fields instead of the RS_A15 and RS_A16 fields that older TIGER/Line data had. 2007-05-04 13:18 we7u * help/help-English.dat: Added a note stating that all PHG values must be specified before Xastir will transmit the values. 2007-05-02 13:58 we7u * src/interface.c: Checking the result code, providing more info on why an "open" failed. 2007-05-02 12:54 we7u * configure.ac, scripts/BUILDRPMS: Setting up for the next devel release. 2007-05-02 12:14 we7u * ChangeLog, configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for stable 1.9.0 release. 2007-04-27 09:55 tvrusso * src/db.c: Cast the time_t value to (long int) before passing to fprintf. On some systems (e.g. FreeBSD) time_t isn't a long, and using a %ld format for it generates a warning. On other systems, time_t *is* a long int and using a %d format generates a warning. So punt: cast to (long int) and use %ld. This should make all those systems shut up with their warnings. 2007-04-27 06:52 we7u * src/db.c: Changing some debug printf's from %d to %ld for printing some time variables. 2007-04-27 06:47 we7u * src/db.c: Changing some printf's to %ld instead of %d for some debug time printouts. 2007-04-27 06:45 we7u * src/db.c: Adding a missing "void" in a function header. 2007-04-27 06:44 we7u * src/database.h: Adding a missing "void" in a function declaration. 2007-04-20 10:03 we7u * FAQ: Added some debugging instructions for the missing "xastir.rgb" file and/or other files upon Xastir startup. 2007-04-16 11:17 tvrusso * src/: database.h, db.c: More debugging code to look into bug #1698474 Add a "dump_time_sorted_list" method and calls to it so we can actually view the entire time sorted list as soon as the sanity check fails. Also reduce the debugging expire time from 1 hour to 5 minutes. 2007-04-12 08:40 we7u * FAQ: Adding a link to the timing slider dialog screen capture. 2007-04-11 10:33 we7u * FAQ: Added section 4.28 describing the problem with missing labels on the Configure->Timing dialog. It also describes what the labels should be. 2007-04-09 08:20 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2007-03-31 12:49 tvrusso * src/: database.h, db.c: Add some sanity checking to the EXPIRE_DEBUG logic. I am still seeing that every few weeks my xastir run starts to have stations that should have expired 10 days ago, but still has 'em. This really screws up the ALOHA calculations. This sanity checking just goes through the entire time-sorted list and checks to see if any stations are older than the expire time, and does this immediately after the expiration is processed. The sanity checking only happens when EXPIRE_DEBUG is defined. The expire code assumes that the list is sorted by time, and stops when it finds a station newer than the expire time. If the list is somehow getting corrupted and no longer properly sorted, that would explain the behavior I'm seeing. I still haven't found the problem, but this should at least tell me if the list management has a bug or not. 2007-03-22 10:05 gstueve * scripts/fcc-get: Sort only on callsign. Don't use following fields. 2007-03-13 07:55 gstueve * scripts/fcc-get: Actually use web instead of older ftp server to get fcc data. 2007-03-13 07:32 gstueve * scripts/fcc-get: Make sure not to get rid of an old fcc data file if unable to get replacement file. 2007-03-07 21:17 tvrusso * src/: database.h, db.c: Change "check_station_remove" and "check_message_remove" to take a time_t for curr_time instead of an int. time_t's are what's passed in, so let's keep it consistent. I do not believe this has anything at all to do with the fact that my xastir instance isn't deleting stations on the 1-day cycle I ask it to --- on my system a time_t and an int are the same size, and time_t is defined as an int32, not an unsigned or anything. But it's still the right thing to do. 2007-03-06 13:58 we7u * src/map_geo.c: Getting rid of a compiler warning when we compile with ImageMagick. 2007-03-06 11:31 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c, maps.c: Changing the path to the GraphicsMagick api.h file to match what we're currently compiling against. 2007-03-06 11:30 we7u * scripts/LSB-BUILD: Forcing the use of GraphicsMagick instead of ImageMagick, per the newer command-line flags we use for Xastir's configure. 2007-02-27 15:19 gstueve * src/bulletin_gui.c: Move display update until after the new data is posted to list. 2007-02-27 13:33 gstueve * src/alert.c: Keep trying to clear out old data for new messages. 2007-02-24 14:08 gstueve * src/wx_gui.c: Make sure updating Wx Alert List doesn't crash because selected item was replaced by unselected item. 2007-02-22 08:29 we7u * INSTALL: Adding "ldconfig" invocations for GM/IM installs. 2007-02-22 08:14 we7u * INSTALL: Changing the command-line options for configuring GraphicsMagick to something a bit simpler. 2007-02-22 07:26 gstueve * src/alert.c: Compressed Wx alerts are precisely 3 elements long. 2007-02-22 07:20 gstueve * src/: alert.c, util.c: Really, really take care of NWS_ message from Thailand. Remove stale compressed weather alerts from consideration. 2007-02-21 08:47 gstueve * src/util.c: Fix error case from Thailand station sending message to NWS_ about 80th birthday anniversary of King. 2007-02-21 08:02 gstueve * src/db.c: Make conditional look like what it is (a for loop, not simple while). 2007-02-16 20:11 gstueve * src/db.c: Make sure debug_level is tested as BitWise value NOT logical value. 2007-02-16 13:01 we7u * INSTALL: Grammar error. Fixed. 2007-02-16 12:22 gstueve * src/main.c: Fixed [ 1553641 ] Zoom Error (Integer Math?). Increment by 1 for 10% zoom-out when less than zoom level 10. 2007-02-16 11:48 we7u * scripts/get-NWSdata: Updating the script to snag the latest-latest files. 2007-02-16 11:48 we7u * src/map_geo.c: Getting rid of a compiler warning having to do with the wrong size specified in an printf. 2007-02-16 11:48 we7u * INSTALL: Adding GraphicsMagick instructions. 2007-02-16 09:05 we7u * scripts/LSB-BUILD: Moving the defines for the REV and FILENAME near the top. Deleting old xastir-lsb-*.bz2 files before we start so that we don't upload old files each time. 2007-02-15 08:41 we7u * README.Getting-Started: Adding a comment about how to test audio file playing from the command-line. 2007-02-14 07:20 we7u * src/maps.c: Adding more comments. No code changes. 2007-02-13 12:22 gstueve * src/maps.c: Make sure all sides of the box are checked, not just three of them. Also make sure if an alert is not on screen clear it off. 2007-02-13 07:30 we7u * src/interface_gui.c: Changing the defaults for new internet connections to: rotate.aprs.net, port 14580, filter "m/500", reconnect enabled. 2007-02-13 05:21 gstueve * scripts/fcc-get: Update script to retrieve Canadian callsign data from new location. I had not gotten a new update from previous location since September, 2006. 2007-02-09 22:52 we7u * README.Getting-Started: Adding an entry for the new "Home" key function. 2007-02-09 22:49 we7u * src/main.c: The "Home" key now centers the map on your station's position. 2007-02-09 19:31 we7u * src/map_geo.c: Changing back to the original path for the Toposerver images. The problem was fixed on findu's end. 2007-02-09 19:04 we7u * src/map_cache.c: Commenting out one assignment (not used) which causes a compiler warning on some systems. 2007-02-09 18:24 we7u * Davis/README: Fixing an errant path in the instructions. 2007-02-08 13:02 we7u * src/map_geo.c: Hopefully a tweak that will help make online Toporama maps work again in the future. Have to wait for Gerry to look at the server configuration before we'll know for sure. 2007-02-06 12:30 we7u * src/maps.c: Casting some long int results to int's. 2007-02-06 08:24 we7u * src/maps.c: A fix for the UTM/MGRS major grid lines not appearing. 2007-02-06 06:55 we7u * scripts/inf2geo.pl: Updating the script to use GraphicsMagick's "gm" program. If not found, try ImageMagick's "identify" program. If that not found, output an error message suggesting that one or the other be installed. 2007-02-06 06:14 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing "MGRS" label to "MGRS2". When it was implemented they were calling the two available ones "MGRS-Old" and "MGRS-New". Now "MGRS-New" is called "MGRS2" and there's talk of an "MGRS3" soon... 2007-01-27 10:41 tvrusso * configure.ac: re-enable check for the X Printing Extension library. Apparently this is needed by libXm and some systems do not properly bring in the indirect dependence through the dynamic loader. It would probably be better to detect that condition than just blindly checking for Xp (which we don't use). Regardless, it should never be necessary to install development headers for libXp just to build xastir, which was what one user was confused about and which led me to remove the check in the first place. 2007-01-24 13:19 tvrusso * configure.ac: Remove probe for the X Printing Extension library. Xastir doesn't use it, and there's no point probing for it. Someone was confused into thinking they needed to install it on Ubuntu 6.10 because configure said it couldn't find the library. They don't, coz we don't use it. 2007-01-16 07:15 we7u * scripts/LSB-BUILD: We now remove /opt/Xastir/* during the build so that we get a clean tar file, plus dates have been added to the filename. 2007-01-13 19:57 we7u * src/messages_gui.c: We now check whether Lesstif is compiled in and skip doing the dynamic widget thing on the Send Message dialog if so. 2007-01-12 11:52 we7u * src/messages_gui.c: Another LSB/Lesstif tweak, plus making sure we fill in the history on Send Message dialogs brought up through the new "Show Pending Messages" menu entry. 2007-01-12 10:39 we7u * src/maps.c: Changing strcasestr to strstr for Cygwin compatibility. We don't really need case-insensitive matching there anyway. 2007-01-12 09:13 we7u * acinclude.m4: A fix for the GraphicsMagick/ImageMagick problem where GM is not on the system but Xastir tries to compile with it. 2007-01-12 08:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/messages.h, src/messages_gui.c: Adding a "Show Pending Messages" menu option to the Message menu. This one looks through the outgoing queue and brings up a Send Message dialog for each current QSO. 2007-01-09 09:33 we7u * src/messages_gui.c: Another couple of tweaks to keep Lesstif from segfaulting with the LSB compile. 2007-01-08 13:47 we7u * src/xa_config.c: Updated some comments. No code changes. 2007-01-08 13:21 we7u * src/messages_gui.c: Fixes to prevent segfaults with LSB-Xastir. It appears that Lesstif cannot currently handle removing/adding widgets to an already-realized dialog without segfaulting. Here we stick with the default one-long-input-field if we're compiling for LSB. 2007-01-05 12:20 we7u * src/db.c: Moved the code which _only_ depends on search_station_name() higher in the Station_data() function so that the dialog doesn't get drawn if not needed. 2007-01-05 12:00 we7u * scripts/LSB-BUILD-ALL: Switching back to Lesstif-0.95.0 as 0.94.4 didn't improve things. 2007-01-05 11:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/maps.c: Fixing the print properties dialog so that it only comes up if "gv" is detected. Getting rid of gv-specific options on the command-line when "gv" is not being used as a print-previewer. Adding a couple of strings to the language files. 2007-01-04 12:28 we7u * scripts/LSB-BUILD-ALL: Changing some comments. No code changes. 2007-01-04 10:12 we7u * scripts/LSB-BUILD-ALL: Switching from Lesstif-0.95.0 to 0.94.4 for a while to see if the resulting binary is more stable. 2007-01-03 11:38 we7u * symbols/Makefile.am, symbols/symbols.dat, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-NWSdata, scripts/get-gnis, scripts/get-maptools.sh, scripts/get_shapelib.sh, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am: Updating Copyright info. 2006-12-29 18:35 we7u * src/maps.c: Moving a new variable declaration above statements in the function. 2006-12-29 10:57 we7u * src/maps.c: Moving many of the error messages to pop-up dialogs for the user-instigated print and print preview functions. We also now allow a previewer other than "gv" to be used, although we're still passing gv-specific parameters to it (something more to fix). 2006-12-29 10:10 we7u * src/: maps.c, xa_config.c: Added #ifdef's for GV_PATH and LPR_PATH so that we compile ok on systems which don't have these two utilities. 2006-12-28 23:27 we7u * src/maps.c: More changes to printing. Printing direct should be functional now. 2006-12-28 22:37 we7u * src/: maps.c, maps.h, xa_config.c: Revising the new printing code a bit more. Now saves/restores the printer and previewer paths from file plus allows the user to change them. More to do yet. 2006-12-28 16:14 we7u * src/: main.c, maps.c, maps.h: A start towards having a separate dialog for printing or print previewing/printing. Not complete yet, but shows the direction I'm heading. 2006-12-20 18:51 we7u * acinclude.m4: Removing the libdb-5.0 options. 2006-12-20 16:04 we7u * acinclude.m4: Fixing the variable save/restore code for the GraphicsMagick and ImageMagick tests. 2006-12-19 22:54 we7u * scripts/get-maptools.sh: Adding checks for "wget", "gtar", "bsdtar", "tar", and "gunzip". The script will attempt to configure to the set of utilities that are available. If the proper utilities cannot be found the script will exit before downloading any files. 2006-12-19 17:38 we7u * scripts/get-maptools.sh: Searching for GNU tar before continuing with the script. 2006-12-19 13:45 tvrusso * src/map_shp.c: Remove unused variable to silence warnings. 2006-12-19 13:39 tvrusso * src/: main.c, map_shp.c, util.c, util.h: A tiny addition: make sure we always write out a valid ".prj" file to go with any of the shapefiles we create (currently, that's GPS downloads and saved APRS tracks). Doing so makes sure that tools other than Xastir that use the .prj file to determine the coordinate system of a shapefile will know what's in there. This includes OGR's projection transformation tools, the QGIS GIS data viewer, and other GIS software such as GRASS or (ugh) ESRI products. It is a cardinal sin to create GIS data that doesn't tell you what coordinate system it's in. Strike one dark stain from our souls. 2006-12-18 23:31 tvrusso * configure.ac: Switch default for rtree from no to yes. It will now build as long as shapefile support is building, unless explicitly disabled. Disabling rtree now requires "--without-rtree". 2006-12-18 13:09 we7u * xastir.spec.in: Forcing ImageMagick over GraphicsMagick, as that is what is supplied with SuSE. Also enabling rtree. 2006-12-18 13:09 we7u * xastir-min.spec.in: Forcing ImageMagick over GraphicsMagick for this package, as that's what is supplied with SuSE. 2006-12-18 11:45 we7u * acinclude.m4: Removing "/opt/lib" and "/opt/bin" for OSX search paths as these are not used by DarwinPorts/MacPorts. 2006-12-18 11:35 we7u * acinclude.m4: Simplifying the ImageMagick and GraphicsMagick tests, but adding extra search paths when configuring on OSX. Adding more libdb paths to the search paths for that library. 2006-12-18 11:30 we7u * configure.ac: Commenting out some warnings regarding ImageMagick and GraphicsMagick: This info is self-evident in the configure output now. 2006-12-16 22:55 we7u * scripts/get-maptools.sh: Taking out the hard-coded path to "tar". 2006-12-15 12:56 we7u * acinclude.m4: Adding searches for ImageMagick and GraphicsMagick in "/opt/local/bin" (OSX DarwinPorts). 2006-12-15 12:53 we7u * configure.ac: Correcting the GM/IM logic, adding comments. 2006-12-15 10:32 tvrusso * config/Makefile.am, config/stored_track.dbfawk, src/map_shp.c: Add a Label field to the dbf file created by the "Store Track" feature when shapelib is available. Add a dbfawk file so that stored tracks can be rendered properly even if they aren't in the GPS directory. Users can customize presentation of the stored track by copying the global dbfawk file to the directory with the shapefile, giving it the same basename as the shapefile, and tweaking it as needed. This should allow more convenient use of the maps created by storing tracks than the method that based rendering on the file name and directory. 2006-12-15 09:43 we7u * src/main.c: Reversing the order of the HAVE_GRAPHICSMAGICK/HAVE_IMAGEMAGICK #ifdef's. 2006-12-15 08:06 we7u * acinclude.m4: Reformatting a couple of lines. No code changes. 2006-12-14 22:02 tvrusso * src/map_shp.c: Fix of my previous fix to the GPS vs. DBFAWK issue. Somehow I managed to get it to ignore the fact that the file was in the GPS directory even when there *WAS* no dbfawk file. The problem was that I tested for the non-nullness of "sig_info" after sig_info was filled in with a default signature's pointer. Needed to put the test before that default case. 2006-12-14 13:22 we7u * configure.ac: Giving up for now on skipping the wget tests if libcurl is found. Also moved "rtree" out of the experimental category, putting it up with the other regular options (above the dashed line in the summary). 2006-12-14 12:17 we7u * scripts/LSB-BUILD: Added a comment. 2006-12-14 12:17 we7u * acinclude.m4, configure.ac: Removing the tests for "cat" and "cp". Tweaking the "wget" code a bit more (but still not skipped if libcurl is found first). 2006-12-14 12:15 we7u * src/: main.c, objects.c: Using the new copy_file() function instead of /bin/cp. 2006-12-14 12:14 we7u * src/: util.c, util.h: Added copy_file() function written by Adam Hahn, AI4QB, and contributed to the public domain. We've modified it from his initial code so any bugs are our fault. 2006-12-14 09:06 we7u * acinclude.m4: Commenting out the code which checks for the "cat" command. We don't use it anywhere in our code. 2006-12-13 21:34 we7u * acinclude.m4: Fixing some errors I introduced with the last commit. 2006-12-13 21:02 we7u * acinclude.m4: Improvements in the ImageMagick and GraphicsMagick detection. 2006-12-12 22:50 tvrusso * src/: main.c, map_shp.c: Make DBFAWK trump the gps_flag. This means that if a file is in the GPS directory and there is a DBFAWK file to go with it, the DBFAWK file controls the rendering. It is still the case that if there is NO dbfawk file, or if DBFAWK is not enabled, the hard-coded GPS stuff (i.e. fixed width and line style, color taken from file name) is used. Also, change the dbfawk file created upon GPS download to match the style that the hard-coded GPS stuff would use. 2006-12-12 22:46 we7u * acinclude.m4, configure.ac: A few tweaks to the GraphicsMagick/ImageMagick tests. 2006-12-12 19:06 we7u * acinclude.m4, configure.ac, src/objects.c, src/xa_config.c, src/xastir.h, src/maps.h, src/maps.c, src/main.c, src/map_WMS.c, src/map_geo.c, src/map_tiger.c: Changes to allow using GraphicsMagick library and "gm convert" in place of the ImageMagick library and "convert". Xastir will now prefer GraphicsMagick over ImageMagick if both are present on the system. 2006-12-12 09:57 we7u * scripts/: LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Updating some comments. 2006-12-12 08:38 we7u * scripts/LSB-BUILD: Enabling the Festival client to be compiled into LSB. This has a couple of small downsides: 1) The user will get a "cannot connect to Festival" message on start up if they haven't installed/run the festival daemon, and 2) If anything else is running on localhost TCP port 1314 Xastir may try to talk to it. The upside is that installing/running a Festival daemon will work with the LSB binary to produce speech. 2006-12-12 08:36 we7u * acinclude.m4: Removing define for FESTIVAL_PATH. We don't use this in our code, plus if we chose to later it'd make another external dependency that'd need to be solved for the LSB distribution. I believe this was originally added in case we wished to call the festival binary directly instead of doing a TCP connection to the festival daemon on port 1314. 2006-12-12 07:49 we7u * README.win32, acinclude.m4, src/wx_gui.c: Getting rid of our dependence on the "/usr/bin/finger" external executable. It's been replaced by our own TCP/IP finger code. This is used for fetching the NOAA weather text from "wxsvr.net". 2006-12-12 06:35 we7u * src/db.c: Comment correction. 2006-12-11 12:39 we7u * scripts/LSB-BUILD: Cleaning up the lsbappchk calls. 2006-12-11 12:38 we7u * LICENSE: Minor changes to comments. 2006-12-11 09:22 we7u * scripts/LSB-BUILD: A minor change to the flags for lsbappchk. 2006-12-10 20:19 tvrusso * src/main.c: Change the "display_level" value in the stuff output as a dbfawk file for downloaded gps tracks. The value that was there was absurdly low. 2006-12-08 21:02 we7u * scripts/LSB-BUILD-XPM: We don't appear to need a separate libXpm so deleting the build script for it. 2006-12-08 21:00 we7u * scripts/LSB-BUILD-ALL: Removing the libXpm build as we're picking it up automatically from somewhere else now that we've enabled the header files for it. 2006-12-08 20:56 we7u * LICENSE: Removing libXpm license as we don't appear to need to include a separate libXpm anyway. We're already picking it up from LSB or from Motif or something. 2006-12-08 13:48 we7u * scripts/LSB-BUILD-ALL: Putting the XPM build one step later. 2006-12-08 13:16 we7u * scripts/LSB-BUILD-ALL: Adding a comment about libXpm. 2006-12-08 13:14 we7u * scripts/LSB-BUILD-ALL: Adding libXpm build to the script. 2006-12-08 13:12 we7u * scripts/LSB-BUILD-XPM: An LSB build script for libXpm. 2006-12-08 13:11 we7u * scripts/LSB-BUILD: Adding libXpm instructions for the LSB build. 2006-12-08 13:10 we7u * configure.ac: Adding libXpm to the LSB build. Needed for Snapshots and Printing. 2006-12-08 13:09 we7u * LICENSE: Adding the license for libXpm. 2006-12-08 12:16 we7u * scripts/LSB-BUILD: Copying "gm" from GraphicsMagick into our LSB build. 2006-12-08 12:15 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Installing "gm" utility as well (that's where we can get to "convert" in GraphicsMagick). 2006-12-08 12:14 we7u * src/main.c: Restarting the Xastir binary no matter where it was configured to be installed. 2006-12-08 12:13 we7u * configure.ac: Setting defines for Xastir paths. We can use them in the C-code to do things like restart ourselves. 2006-12-08 12:12 we7u * acinclude.m4: Setting up to be able to do Printing and Snapshots with the LSB version. 2006-12-08 12:12 we7u * INSTALL: Documenting the depending on Xpm for Printing and Snapshots. 2006-12-08 08:04 we7u * src/wx_gui.c: Fixing up the finger code for fetching NOAA weather alert text. We now pipe STDERR to STDOUT so that we can see any errors in the dialog. The syntax is shell-specific so we perhaps need a better way to do it. The syntax used should work for SH or BASH shells, and I think Korn shell, but not for CSH? We also now use HAVE_FINGER defines to enable/disable the actual finger call in the code. 2006-12-08 06:58 we7u * LICENSE: Changing some comments. 2006-12-08 06:45 we7u * src/wx_gui.c: Using the new FINGER_PATH that we now put into config.h via acinclude.m4. 2006-12-08 06:44 we7u * acinclude.m4: Adding a search for the "finger" binary. 2006-12-07 12:22 we7u * xastir-lsb.spec.in, scripts/LSB-BUILD: Changing install location for LSB-like (non-certified) version from /opt/lsb-xastir/ to /opt/Xastir/ 2006-12-07 12:09 we7u * xastir-lsb.spec.in: Changing the install location from /opt/lsb-xastir to /opt/xastir. We don't have (and probably will never request/pay for) LSB compliance. 2006-12-07 11:58 we7u * Makefile.am, xastir-lsb.spec.in: Adding more docs to the install locations. 2006-12-07 11:49 we7u * scripts/: LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Adding a comment which states we do NOT have LSB compliance. 2006-12-07 11:48 we7u * xastir-lsb.spec.in, scripts/LSB-BUILD: Adding a comment which states that we do NOT have LSB-compliance. 2006-12-07 11:47 we7u * LICENSE: Documenting the licenses for the optional libraries that we might distribute with an Xastir statically-linked binary. 2006-12-07 11:47 we7u * COPYING.LIB.LESSTIF: Adding the license file for Lesstif, for the case where we're distributing an Xastir statically-linked binary. 2006-12-07 09:33 we7u * configure.ac, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB: More changes to the LSB Xastir build and the LSB build for the optional libraries. We now install the libraries in /opt/lsb-tmp/ and then compile Xastir statically against the libraries there, via symlinks from the /opt/lsb/include/ and /opt/lsb/lib/ directories. 2006-12-06 11:46 we7u * scripts/: LSB-BUILD, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Minor tweaks for LSB compiling. 2006-12-06 11:45 we7u * scripts/LSB-BUILD-ALL: An one-stop-shopping script to build the optional libraries under LSB before we compile Xastir under LSB. 2006-12-05 12:45 we7u * src/main.c: Correcting one comment. 2006-12-05 06:43 we7u * scripts/LSB-BUILD: Removing the gdal symlinks from the comments as we've handled them in configure.ac/acinclude.m4 instead. Xastir will look for gdal in /opt/lsb-gdal/lib and /opt/lsb-gdal/include directories. 2006-12-05 06:42 we7u * configure.ac: Removing "(Experimental)" from the LSB summary line. Changing "lsb" to "LSB" which is more proper. 2006-12-04 11:52 we7u * scripts/LSB-BUILD-GDAL: Adding a commented-out option. No effect to the code. 2006-12-04 09:51 tvrusso * src/shapelib/contrib/: doc/shpproj.txt, tests/shpproj.sh: Just noticed that I never cvs added these two files from the shapelib distribution. Since we are currently distributing the whole shapelib distribution with unmodified license, it is necessary to include all of the whole shapelib distribution. 2006-12-04 09:30 we7u * scripts/LSB-BUILD-GDAL: Initial attempt to get GDAL compiled under LSB. Not functional yet. 2006-12-04 09:29 we7u * scripts/LSB-BUILD: Added a couple of steps to create the .tar.bz2 file and transfer it to the download site. 2006-12-04 08:27 we7u * src/util.c: Enabling CURLOPT_NOSIGNAL option to libcurl if the libcurl version supports it. This prevents segfaults for the case where we get a DNS timeout when initiating a libcurl transfer. 2006-12-03 14:01 we7u * scripts/LSB-BUILD: Changes in comments for GDAL compiling under LSB. GDAL is not working yet though for LSB. 2006-12-03 13:58 we7u * configure.ac: Enabling GDAL library for LSB compile. 2006-12-03 13:54 we7u * src/util.c: Enabling another curl option if compiling w/LSB. 2006-12-03 13:50 we7u * src/track_gui.c: Adding a comment. 2006-12-01 13:47 we7u * configure.ac: Changing some of the text to GraphicsMagick when doing LSB compiles. 2006-12-01 13:47 we7u * USRadar.geo: Changing the black value to match the LSB GraphicsMagick. 2006-12-01 13:38 we7u * src/: map_geo.c, maps.c: Updating some messages to include GraphicsMagick. 2006-12-01 13:27 we7u * scripts/: LSB-BUILD-DB, LSB-BUILD: Adding Berkeley DB to the LSB build to enable map caching. 2006-12-01 12:47 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Enabling PNG in the build. It works now. 2006-12-01 12:46 we7u * scripts/LSB-BUILD: Updating the build comments. 2006-12-01 12:21 we7u * scripts/LSB-BUILD-JASPER: An LSB build script for the Jasper library, to give us jpeg-2000 support in GraphicsMagick. 2006-12-01 12:20 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Making jpeg images work for us. 2006-12-01 11:34 we7u * scripts/LSB-BUILD: Updating some comments. 2006-12-01 11:32 we7u * configure.ac: GrahicsMagick-LSB changes. 2006-12-01 09:49 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: A build script for GraphicsMagick under LSB. 2006-12-01 09:48 we7u * scripts/LSB-BUILD: Adding GrahicsMagick support. 2006-12-01 07:49 we7u * scripts/LSB-BUILD-PNG: Adding an LSB build script for the libpng library, needed for GraphicsMagick or ImageMagick. 2006-11-30 21:05 we7u * scripts/LSB-BUILD-CURL: Adding an LSB build script for libcurl. 2006-11-30 21:03 we7u * scripts/LSB-BUILD: Updating the notes. 2006-11-30 21:01 we7u * configure.ac: Enabling libcurl for LSB. 2006-11-30 13:20 we7u * scripts/LSB-BUILD: Updating the comments. 2006-11-30 13:15 we7u * scripts/LSB-BUILD: Adding pcre and dbfawk to the LSB build script. 2006-11-30 13:14 we7u * scripts/LSB-BUILD-PCRE: An LSB build script for the PCRE library. 2006-11-30 12:33 we7u * scripts/LSB-BUILD: Adding some comments. 2006-11-30 12:04 we7u * scripts/LSB-BUILD-LESSTIF: Adding a commented out command which is useful to see what will be installed without actually installing anything. 2006-11-30 12:04 we7u * scripts/LSB-BUILD: Modifying build to include geotiff and proj support. 2006-11-30 12:03 we7u * scripts/: LSB-BUILD-JPEG, LSB-BUILD-ZLIB: Adding scripts to build libjpeg and libz under LSB. Needed for geotiff support. 2006-11-30 12:02 we7u * configure.ac: LSB mods for geotiff. 2006-11-30 09:26 we7u * scripts/LSB-BUILD: Adding libproj to the mix. It is LSB-compliant. 2006-11-27 08:35 we7u * scripts/LSB-BUILD: Adding rtree to the LSB build. 2006-11-27 08:19 we7u * scripts/LSB-BUILD-LESSTIF: Changes to comments. 2006-11-27 08:18 we7u * scripts/LSB-BUILD: Updating to match my current working copy of the file. 2006-11-27 08:17 we7u * xastir-lsb.spec.in: Updating to match my current copy. 2006-11-27 08:06 we7u * src/map_geo.c: Adding an LF to one warning message. 2006-11-24 11:57 we7u * configure.ac: Adding the RPM spec file for LSB. 2006-11-24 11:51 we7u * xastir-lsb.spec.in: Inital attempt at an RPM spec file for LSB. Not complete yet. 2006-11-24 11:46 we7u * xastir-min.spec.in, xastir.spec.in: Correcting the "Source" line in the header so the version number comes out right. 2006-11-22 11:48 we7u * scripts/LSB-BUILD-LESSTIF: Updating comments. 2006-11-22 11:46 we7u * scripts/LSB-BUILD: Stripping the executables created, adding some more comments. 2006-11-22 11:30 we7u * scripts/LSB-BUILD-LESSTIF: Updating the notes at the top to show the SUCCESSFUL way of compiling Lesstif against LSB. 2006-11-22 11:27 we7u * scripts/LSB-BUILD: Updated to show latest LSB build method. 2006-11-21 07:52 we7u * scripts/LSB-BUILD: Updating the comments. 2006-11-21 07:35 we7u * scripts/LSB-BUILD-LESSTIF: Adding more comments at the top. 2006-11-20 15:37 we7u * scripts/LSB-BUILD-LESSTIF: Adding a comment, commenting out a currently-unused line, and enabling shared libs to be created. 2006-11-20 15:33 we7u * scripts/LSB-BUILD: Adding a comment plus commenting out a currently-unused line. 2006-11-20 15:17 we7u * configure.ac: Another LSB mod. 2006-11-20 14:52 we7u * scripts/: LSB-BUILD, LSB-BUILD-LESSTIF: Preliminary scripts for building LSB-compatible Lesstif and Xastir. They're not fully functional yet. 2006-11-20 14:50 we7u * scripts/fcc-get: Fixing the RCS tag. 2006-11-20 10:31 we7u * src/shapelib/Makefile.am: Updating the Copyright year. 2006-11-20 10:24 we7u * scripts/fcc-get: Changing the RAC portion of the script to match their current server configuration. 2006-11-19 14:05 tvrusso * README.win32: Another tiny update to README.win32 to bring it up-to-date with the reality of today's cygwin and sync with the Wiki HowTo:Windows page. 2006-11-19 14:00 tvrusso * README.win32: Fix up another little issue with this document. I'm doing this piecemeal, because I'm finding things as I'm editing the same information on the Wiki, and want this file to be consistent with that. 2006-11-19 13:56 tvrusso * README.win32: Fix up a little error in the "building shapelib from source" section. It referred to a "_reent" error when really it was about the error involving "__getreent". 2006-11-19 13:34 tvrusso * README.win32: Add note about preferring internal shapelib support unless the external is needed for something other than xastir. This should cut down on our "How do I get around this error message..." support questions from new Cygwin users. 2006-11-17 07:45 kg4ijb * ChangeLog: [no log message] 2006-11-17 00:53 tvrusso * scripts/get-maptools.sh: Found yet another annoying issue with libgeotiff build on ubuntu (and probably anywhere where gcc 4 is used). The problem is that the official tarball has the modification times of configure.in newer than configure, and a makefile that regenerates configure whenever it's older than configure.in --- and then runs it with no arguments. Since we need to run configure with some arguments, that completely messes everything up. Add a "touch configure" command to the commented-out part of the script that makes configure newer than configure.in and bypasses that part of the Makefile. A kludge upon a kludge upon a kludge. I missed this subtlety because when I finally tracked down the "ld -shared" issue, it was in a dirty directory -- one that had already had configure regenerated and which therefore no longer had the broken timestamps. 2006-11-16 21:31 tvrusso * scripts/get-maptools.sh: Add commented-out fix for GCC 4.x issues with libgeotiff. Not uncommenting them, because it might be wrong on some platforms that don't use GCC at all. 2006-11-16 20:13 tvrusso * scripts/get-maptools.sh: A number of small fixes to the get-maptools script: 1) Make sure $XASTIR_TMP exists before trying to download files into it 2) Fix a typo (LDCONf_FILE vs. LDCONF_FILE) 3) Update version of gdal to 1.3.2 (1.3.1 does not compile in recent GCC) 4) Build geotiff before gdal, since gdal will use the libgeotiff if it finds it. 2006-11-16 09:12 we7u * Makefile.am: Getting rid of the symlink I recently added which pointed from /usr/local/share/xastir/doc to /usr/local/doc/xastir. Near as I can tell we're fairly well FHS-compliant now with Xastir. 2006-11-15 12:11 we7u * Makefile.am: Forcing the removal of the old $prefix/share/xastir/doc directory and creating a symlink to the new location. 2006-11-15 11:49 we7u * Makefile.am, xastir-min.spec.in, xastir.spec.in: Moving the doc files to an FHS-compliant directory. For a user installing from sources they'll get installed in "/usr/local/share/doc/xastir/" instead of the old location of "/usr/local/share/xastir/doc". 2006-11-15 08:45 we7u * Makefile.am, xastir-min.spec.in, xastir.spec.in: Changing the man page directory from $prefix/man to $prefix/share/man, per FHS-2.3 and LSB-3.1 2006-11-15 07:50 we7u * xastir-min.spec.in: Changing "--without-shapelib" to "--with-internal-shapelib" to take adantage of the new shapelib library we include with Xastir. 2006-11-15 07:48 we7u * .cvsignore: Adding two derived files back in. 2006-11-15 07:47 we7u * xastir-min.spec, xastir.spec: Put these files into CVS by mistake. They are derived files. Silly me. 2006-11-15 07:08 we7u * scripts/BUILDRPMS: Changing the "minimum" description to include building with internal Shapelib. 2006-11-15 07:08 we7u * .cvsignore: Updating for current list of files. 2006-11-15 07:07 we7u * xastir-min.spec, xastir.spec: Adding the spec files that I've been using. I'm surprised that they weren't added before, but I had added them to my .cvsignore file and so didn't notice. 2006-11-14 13:30 we7u * src/shapelib/dbfopen.c: The last revision also commented out an unused variable that I forgot to mention in the cvs log. 2006-11-14 13:28 we7u * src/shapelib/: shpopen.c, shptree.c: Commenting out some variables that give off compiler warnings. 2006-11-14 13:28 we7u * src/shapelib/dbfopen.c: Casting a couple of variables to int's to get rid of compiler warnings. 2006-11-14 12:58 we7u * README.Getting-Started: Adding missing command-line options to the docs. 2006-11-14 12:42 we7u * src/xa_config.c: Changing some default settings, useful for first-time users of Xastir to see what more of the options might be plus give them a good operational starting point. 2006-11-14 12:09 kg4ijb * ChangeLog: [no log message] 2006-11-14 11:52 we7u * configure.ac: Fixing up the Shapelib config options. 2006-11-14 11:52 we7u * xastir.1: Updating the man page a bit. 2006-11-14 08:28 we7u * configure.ac: Changes to make it obvious in the configure output text and in Help->About that we're using the internal Shapelib. This change doesn't affect summary.log. 2006-11-14 07:41 we7u * src/main.c: Putting a newline in front of the Motif version string in Help->About. 2006-11-14 00:19 tvrusso * configure.ac: Fix the "-I" flag in CPPFLAGS when local shapelib is being built. As it was, the compiler would not find the local shapefil.h file unless you were building in the actual xastir source code directory, or if shapefil.h was already installed system-wide. Noticed this while attempting a fresh build on a brand new laptop, on which I'd decided to attempt the simplest possible build, with no shapelib installed. 2006-11-13 11:46 we7u * README.Getting-Started: Added notes about the private copy of Shapelib and when it might be used, the "wget" requirement for the get-NWSdata script, putting in a callsign when initially starting Xastir, and a list of various places to get Xastir help. 2006-11-13 11:43 we7u * README.win32: Mentioning the private Shapelib version and when it might be used. 2006-11-13 11:43 we7u * README.MAPS: Mentioning "wget" as a requirement for get-NWSdata. Mentioning the private install of Shapelib. 2006-11-13 11:41 we7u * INSTALL: Adding info about the alternate method of getting Shapefile support. 2006-11-13 07:10 tvrusso * README.Contributing: Fix up a mistake in the description of "build directories", and add a reference to that technique to an earlier section that advocates doing all the builds in the source directory. Build directories are such a powerful tool for developers, we should make sure we recommend it when talking about doing multiple builds. 2006-11-13 06:56 tvrusso * README.win32: Attach a date to qualify the meaning of "latest" in the ImageMagick section. 2006-11-13 06:48 tvrusso * src/Makefile.am: Add a testawk_LDADD line to src/Makefile.am so that this test program can link if shapelib is not installed. I have no idea why this didn't fail when I was testing the shapelib addition. 2006-11-13 06:25 we7u * README.win32: Updating the description for ImageMagick bug. 2006-11-13 06:24 we7u * src/: .cvsignore, shapelib/.cvsignore: Adding another couple of derived files to the .cvsignore file. 2006-11-12 17:36 we7u * src/main.c: Enabling default map on initial startup, plus if the callsign is "NOCALL", bring up the Configure->Station dialog. 2006-11-12 17:26 we7u * src/xa_config.c: Getting rid of many of the messages you get on startup when config file settings are missing. 2006-11-11 16:26 tvrusso * src/shapelib/contrib/Makefile.am: Add CVS revision information and copyright. 2006-11-11 16:11 we7u * README.MAPS: Adding attribution for the default map. 2006-11-11 15:46 tvrusso * configure.ac, src/shapelib/Makefile.am, src/shapelib/shprewind, src/shapelib/contrib/.cvsignore, src/shapelib/contrib/Makefile, src/shapelib/contrib/Makefile.am, src/shapelib/contrib/Makefile_orig: Add EXTRA_DIST and DIST_SUBDIRS lines so that the shapelib stuff is properly bundled when doing a "make dist" for release. The Makefile.am in the contrib directory does not actually build any of the contrib codes. That's another step for another moment. I just wanted to make sure that any make dist that is done is sure to bundle the entire shapelib directory in order to comply with the terms of the license. The "Makefile_orig" script in the shapelib/contrib directory could be used temporarily to build the shapelib tools. Ultimately, they could be built by the new makefile, but it's not really the goal of this exercise to do all that. In fact, at some point it might be reasonable for xastir's shapelib directory to contain only the files needed for building the library, but that will probably require modifying it to be under GPL instead of LGPL. That's just a matter of editing some license files, not any code. Also, removed the shprewind file from the shapelib directory. This is a linux binary that for some reason was in the shapelib source tarball I had. It should never have been added to xastir's CVS repository. 2006-11-11 15:01 we7u * Makefile.am: Adding a default map to the distribution. 2006-11-11 14:51 we7u * worldhi.map: Adding a default map. Map was created by Keith Sproul, WU2Z, and used with his permission. 2006-11-10 13:49 tvrusso * src/shapelib/.cvsignore: Add .cvsignore. 2006-11-10 13:49 tvrusso * src/shapelib/Makefile.in: CVS cleanup. 2006-11-10 13:48 tvrusso * configure.ac, src/Makefile.am, src/shapelib/ChangeLog, src/shapelib/LICENSE.LGPL, src/shapelib/Makefile.am, src/shapelib/Makefile.in, src/shapelib/Makefile_shapelib_orig, src/shapelib/README, src/shapelib/README.tree, src/shapelib/dbf_api.html, src/shapelib/dbfadd.c, src/shapelib/dbfcreate.c, src/shapelib/dbfdump.c, src/shapelib/dbfopen.c, src/shapelib/libtool, src/shapelib/makefile.vc, src/shapelib/makeshape.sh, src/shapelib/mkinstalldirs, src/shapelib/shapefil.h, src/shapelib/shapelib.def, src/shapelib/shapelib.html, src/shapelib/shp_api.html, src/shapelib/shpadd.c, src/shapelib/shpcreate.c, src/shapelib/shpdump.c, src/shapelib/shpopen.c, src/shapelib/shprewind, src/shapelib/shprewind.c, src/shapelib/shptest.c, src/shapelib/shptree.c, src/shapelib/shptreedump.c, src/shapelib/shputils.c, src/shapelib/stream1.out, src/shapelib/stream1.sh, src/shapelib/stream2.out, src/shapelib/stream2.sh, src/shapelib/stream3.out, src/shapelib/contrib/Makefile, src/shapelib/contrib/ShapeFileII.pas, src/shapelib/contrib/dbfcat.c, src/shapelib/contrib/dbfinfo.c, src/shapelib/contrib/makefile.vc, src/shapelib/contrib/my_nan.h, src/shapelib/contrib/shpcat.c, src/shapelib/contrib/shpcentrd.c, src/shapelib/contrib/shpdata.c, src/shapelib/contrib/shpdxf.c, src/shapelib/contrib/shpfix.c, src/shapelib/contrib/shpgeo.c, src/shapelib/contrib/shpgeo.h, src/shapelib/contrib/shpinfo.c, src/shapelib/contrib/shpproj.c, src/shapelib/contrib/shpwkb.c: Add shapelib as an internal library, and use it if we don't find an external one. Make a loud warning if we do so, because the result of this is that we'll have a bigger executable. This commit is bigger than it needs to be, because it includes all of shapelib, including the contrib directory. Added an automake-generated Makefile for this thing. Builds only a static library, and calls it "libshape.a" instead of "libshp.a" so that if we use ask to use the static one while there is also an external one installed, the linker doesn't pull in the shared library one unbidden. This stuff can be tested on a system with libshp installed by configuring with "--without-shapelib" I will be removing Makefile.in because it's not supposed to be in CVS. My mistake. 2006-11-09 14:34 kg4ijb * ChangeLog: [no log message] 2006-11-09 08:23 we7u * src/xa_config.c: Changing the default window size on initial startup. The minimum width/height are set up in main.c:create_appshell() anyway, so we can't reduce the window small enough to cause segfaults by doing this change. 2006-11-09 08:21 we7u * src/main.c: Changed one comment. No code changes. 2006-11-05 17:16 tvrusso * README.win32: Add information about problems with Cygwin ImageMagick. The notes in the README.win32 refer to "recent versions" of cygwin containing ImageMagick 5.5.7, which is very outdated. Current versions of Cygwin come with 6.0.4, and there are real problems due to that version being linked with Display Postscript support --- X.org stopped supporting that, and now ImageMagick doesn't work on Cygwin unless you find a few DLLs off the net. The paragraph I added here points the user at an article that explains the issue and shows two workarounds (installing the DLLs or building ImageMagick from source code instead). 2006-11-03 12:31 we7u * src/util.c: Adding a diff by Tapio Sokura, which a few comment changes by me. Thanks! This fixes the lower-case callsigns problem for internet paths. 2006-11-02 10:34 we7u * scripts/BUILDRPMS: Setting up for building RPM's for the current development version. 2006-11-02 08:03 we7u * configure.ac: Setting up for the next development source version number. 2006-11-02 06:43 we7u * configure.ac, scripts/BUILDRPMS, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Setting up to do the 1.8.4 release. 2006-11-01 06:57 we7u * config/language-German.sys: Updates by Rolf Bleher. Thanks! 2006-10-26 08:52 we7u * Davis/: configure.ac, src/db2APRS.c, src/defs.h: Tweaks by Bruce Bennett: "I fixed some issues brought out by the latest MySQL (5.0.x ver), added metric/english switch, rooted out some old bugs and made some improvement on debug messages." 2006-10-26 06:50 we7u * src/db.c: Fixing problems with Aloha circle units in multiple places. 2006-10-25 08:16 we7u * REGRESSION_TESTS: Lining up the line to match the rest. 2006-10-24 11:03 we7u * REGRESSION_TESTS: Adding another test which disables the /usr/include/magick/ directory before attempting a compile. This disables ImageMagick. 2006-10-24 11:02 we7u * src/map_geo.c: Adding another two ifdef's so that the code will compile in the case that we have XPM support but no ImageMagick support. 2006-10-11 14:39 we7u * src/db.c: Another patch by Jesse, KF4HZU. Thanks! 2006-10-05 09:11 we7u * src/db.c: Skipping any processing of lines from logfiles that begin with '#'. 2006-10-05 08:29 we7u * src/db.c: A fix for numeric overlays on base-91 packets by Jesse, KF4HZU. 2006-10-05 07:46 we7u * src/db.c: Some SKY bulletins came in that had "EMERGENCY" in the text. This caused Xastir to try to process the packets twice on order to get a position first and then pop up the emergency dialogs. Since there was no position in the packet this caused an infinite loop as Xastir passed the packet through the processing again and again. The fix is to NOT send a packet through the processing again, which will make it necessary for Xastir to receive two EMERGENCY packets if a position is not known yet for the station, but it will at least not cause Xastir to get in an infinite loop. We also skip storing any SKY packets now as they just take up memory and we never do anything further with the packets. 2006-09-27 12:23 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding US National Grid designator to the MGRS label. If in NAD83/WGS84 they are equivalent. 2006-09-25 06:24 we7u * src/main.c: A tweak by Dick Reichenbach, KC8OBZ, to split the status line into two lines when using a 640x480 display. Thanks! 2006-09-20 08:22 tvrusso * src/interface.c: Add comments to show where it is necessary to fix data_out_ax25 so that it isn't confused by leading white-space in commands. No code changes. The idea was to document what I know I need to do to fix the problem that Mike Fenske saw when the \r was added before MYCALL commands. The quick fix was not to add the \r if sending to an AX25 port, but the clean fix would be to make data_out_ax25 not care about leading white space. 2006-09-19 20:14 tvrusso * src/interface.c: What might be a less intrusive way of introducing that extra carriage return into the MYCALL line. The code for AX25 ports tries to decode the mycall line, and that decoding was getting confused by the leading \r. This quick "fix" simply checks to see if we're writing to an AX25 port, and if so, doesn't add the \r. A more correct way to fix this would be to fix the decoding of MYCALLs by data_out_ax25 so it doesn't get tripped up by the first \r. This is meant to be a quick hack to let both things work properly until I figure out how to desensitize data_out_ax25. 2006-09-19 19:55 tvrusso * src/interface.c: Removing carriage return I had put in before MYCALL sent to TNCs. The original intent was to do what was supposed to be an inconsequential extra carriage return when writing to the TNC to work around some garbled data issues that are happening on D700s. Unfortunately, some bit of code downstream of "output_my_aprs_data" is seeing the extra carriage return and screwing up. Bleah. Removing the "fix" until I figure out what is going on. 2006-09-19 09:12 chicoreus * src/list_gui.c: Removing double cast. 2006-09-19 08:58 chicoreus * src/: database.h, db.c, list_gui.c: Fixing bugs in previous commit. Added note about database.h being name used instead of db.h Previous commit email message bounced, changes were: 1) Converted hard coded MY_TRAIL_DIFF_COLOR to user configurable my_trail_diff_color and added to configuration ui and config file. 2) Linked station icon in station list to an onclick callback to center the map on the station. Included alternate callback to pop up station details window. Needs checking, as I think the callback needs to filter mouse events. 3) Added, but haven't yet internationalized display of area in acres when measuring distances/areas on the map. Needs to be generalised and linked to all the places display of an area might be desired. 2006-09-19 07:43 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/db.c, src/list_gui.c, src/main.c, src/main.h, src/xa_config.c: Three changes: 1) Converted hard coded MY_TRAIL_DIFF_COLOR to user configurable my_trail_diff_color and added to configuration ui and config file. 2) Linked station icon in station list to an onclick callback to center the map on the station. Included alternate callback to pop up station details window. Needs checking, as I think the callback needs to filter mouse events. 3) Added, but haven't yet internationalized display of area in acres when measuring distances/areas on the map. Needs to be generalised and linked to all the places display of an area might be desired. 2006-09-19 06:55 we7u * src/db.c: Removing the '*' after our callsign when injecting packets into the internet (our injection ID that we add). 2006-09-15 09:59 tvrusso * src/interface.c: Inexplicable fix for an equally inexplicable but very persistent problem. My Kenwood D700 complains loudly ("EH?") almost every time Xastir tries to set MYCALL before a posit. This commit adds a carriage return right before MYCALL is sent. For whatever reason, this eliminates the problem. Clearly, the d700 gets in some strange state where the first command sent after re-entering command mode is not recognized every time. Since a failure of MYCALL to be set before transmit can mean the wrong callsign (or NOCALL) being attached to a posit, this is potentially a significant fix. I will comment more on it in a follow-up email to the users mailing list. 2006-09-15 09:53 we7u * INSTALL: A tweak by Chip, N1MIE. 2006-09-10 18:03 we7u * src/db.c: Backing out the igate changes until they can be tested further. They appear to have broken most or all igating -> RF. 2006-09-08 17:35 we7u * src/: db.c, main.c, main.h, messages.c, messages_gui.c, popup_gui.c, track_gui.c: Implementing command-line flags for tracking a station and for disabling popups plus disabling Send Message dialogs on incoming messages. May need some more tweaking to get rid of all popups, but this should be a good start. 2006-09-08 11:10 we7u * src/db.c: Attempting to igate more types of packets to RF, for the cases where it is appropriate to do so. This should fix the directed query problem, at least when gating _to_ RF. Will look at the other case as well (gating->INET), which may not be broken. 2006-09-02 16:43 we7u * src/db.c: Adding parsing for RDF packets, with checking to make sure they really _are_ RDF packets this time. 2006-09-01 06:21 we7u * src/db.c: Added a date/timestamp to bearing/distance popup for emergency packets. 2006-09-01 06:05 we7u * src/db.c: Tweaking the processing of emergency packets (Mic_E packets and standard packets) so that the packet gets processed twice if the first time comes up with a 0.0 distance (which means an unknown distance). This often allows us to match our distance check ( < 280 miles ) the first time a packet is received, instead of having to wait for the 2nd occurrence of the packet. Also: We now bring up a popup with the bearing and distance to the emergency station if it passes our checks. 2006-09-01 04:46 we7u * src/db.c: Added another comment in the RDF section. 2006-09-01 04:45 we7u * src/messages_gui.c: Changing input focus to the first message box after sending each message. For D700 or D7 mode to make typing messages easier. 2006-08-31 14:36 we7u * src/: db.c, main.c, maps.c, maps.h, util.c, util.h: Writing wx alerts to file in the correct format now. Storing/restoring wx alerts from file. Fixed a bug in the weather alerts code where they wouldn't draw right away. 2006-08-31 14:27 we7u * src/wx_gui.c: Skipping NULL alert entries instead of returning when we hit the first one. This lets us see all of the active alerts. 2006-08-30 12:29 we7u * src/: db.c, main.c, main.h, messages_gui.c, xa_config.c: Logging for messages and weather alerts. Starting to add more buttons to the Send Message->Change Path dialog. 2006-08-30 12:21 we7u * src/Makefile.am: Putting the files in correct alphabetical order. 2006-08-30 04:38 we7u * src/db.c: This change implements the capability to receive messages that were sent to our other SSID's. We don't ack them. They cause a Send Message box to pop up like normal except there's a special note prepended to each message line stating which SSID the message was sent to. This allows us to catch messages sent to our other stations and respond to them if desired. We skip displaying these messages if the message originated from our station, as two message boxes for the same QSO is very confusing (and unnecessary). 2006-08-30 04:12 we7u * src/interface.c: Fixes for KISS mode when using "DIRECT PATH". 2006-08-29 15:34 we7u * src/: db.c, main.c: Adding context-sensitive Send Message To option to the mouse menu. 2006-08-29 15:26 we7u * src/messages_gui.c: Changing to APRHH and APHH as the TOCALLS which mean a HamHUD. 2006-08-29 15:24 we7u * src/view_message_gui.c: Making "Mine Only" take precedence over the range in the View->Messages dialog. 2006-08-29 07:31 we7u * src/messages_gui.c: Minor fixes to the Send Message changes. Tied the select_station_type capability into the New/Refresh Callsign button as well. 2006-08-29 05:15 we7u * src/xa_config.c: Checking for blank strings in config file, replacing with defaults where it makes sense. 2006-08-28 18:01 we7u * src/messages_gui.c: Fixing HamHUD-II detect and setting max size of messages to 20 for that device. 2006-08-28 16:23 we7u * src/messages_gui.c: Initial attempt to have the Send Message dialog automatically choose the HamHUD/D700/D7 settings based on the remote station. 2006-08-28 12:29 we7u * src/: messages.c, messages.h, messages_gui.c: Added Send Message formatting for HamHUD 20-character display. 2006-08-25 15:33 we7u * src/: db.c, messages.c, messages.h, messages_gui.c: Adding error messages to the Send Message dialog. Fixing directed queries. Adding D7A and D700 input modes to the Send Message dialog. Fixed a long message bug so 67-char messages can now be sent. 2006-08-25 15:24 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding some warning messages for the Send Message dialog. 2006-08-25 04:42 we7u * src/db.c: Changed the Capabilities display in View Incoming Data so that it shows my own outgoing ?IGATE? packets as well. 2006-08-25 04:25 we7u * src/messages_gui.c: Updated some comments. No code changes. 2006-08-24 16:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/messages_gui.c, src/view_message_gui.c: Implementing Station Capabilities and Mine Only options on Incoming Data dialog. Added Mine Only and interface selection options to View Messages dialog. 2006-08-24 16:29 we7u * src/popup_gui.c: Protecting popup functions from possible bad inputs. 2006-08-23 13:45 we7u * src/db.c: Implemented 120-second random delay before responding to an ?IGATE? query. Implemented the response for an ?APRS? query, including the 120-second random delay. 2006-08-23 08:53 we7u * src/main.c: Refuse to print out the measured angle for the case where we're doing on-screen measuring at zoom==1. Angles change at that zoom level. 2006-08-23 08:09 we7u * src/map_geo.c: Adding a comment about a future Terra/Toposerver enhancement: Crossing UTM zone boundaries, splitting the map fetch into two fetches. 2006-08-23 07:14 we7u * src/maps.c: Added more debug output from map_visible() 2006-08-23 07:14 we7u * src/map_geo.c: Separating "zstr" used in UTM->lat/long calls into zstr0 and ztr1. We were running into problems when we crossed UTM zones with a map. 2006-08-23 07:12 we7u * src/main.c: Added a method to have Xastir spit out coordinates in Xastir Coordinate System. Change a global variable at the top of main.c to a 1 to enable it. 2006-08-23 05:19 we7u * src/maps.c: Adding some debug statements. 2006-08-23 05:17 we7u * src/map_geo.c: Changing one comment. 2006-08-23 05:17 we7u * src/main.c: Moving reload_object_item() and Restore_CAD_Objects_from_file() from main() up into UpdateTime(). This is so that the image can be created and the global map corner variables updates first. Points were getting rejected on loading because these variables were not initialized yet. 2006-08-22 11:20 tvrusso * src/messages_gui.c: Fix the Send_message_change_path_destroy_shell function so it doesn't ever try to destroy a shell when the pointer is null. This was causing segfaults for me whenever a messaging dialog was closed, whether I'd accessed a change_path dialog or not. 2006-08-22 08:27 we7u * src/messages_gui.c: Closing the Change Path dialog if the Send Message dialog is closed. 2006-08-22 07:20 we7u * src/messages_gui.c: Setting the path and change path widgets so that they stretch properly with the dialog. 2006-08-22 07:12 we7u * src/messages_gui.c: Simplifying the Send Message dialog a bit more, taking the Reverse Path widgets out of that dialog. They still exist in the Change Path dialog. 2006-08-22 05:35 we7u * src/messages_gui.c: Minor adjustments to the widgets of the Send Message and Change Path dialogs. 2006-08-22 04:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages_gui.c: Swapping a couple of lines of widgets in the Send Message dialog. More tweaks to lang strings for Send Message and Change path dialogs. 2006-08-22 04:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages.h, src/messages_gui.c: Creating language file entries for new Send Message and Change Path widgets. Adding "Reverse Path:" labels to both dialogs. 2006-08-22 04:08 we7u * src/messages_gui.c: Changing reverse-path calculation to get rid of Q-construct and anything after it before reversing the path. 2006-08-21 19:35 we7u * src/messages_gui.c: A better Send Message dialog. More testing to be done yet, but so far it looks better than the old. 2006-08-21 18:01 we7u * src/: interface.c, messages.c, messages.h, messages_gui.c: The beginnings of a separate dialog for changing the path from the Send Message dialog. Mostly working as-is but not very pretty. 2006-08-21 09:18 we7u * src/messages_gui.c: Added some TODO comments to Send_Message(). 2006-08-21 06:58 we7u * src/popup.h: Cranking up max popups to 30. 2006-08-21 06:33 we7u * src/db.c: A fix for bug #1474401, where an auto-answer or some other message to us which doesn't have a message-ID ends up showing up in a Group Message dialog. This fix makes them appear in a Send Message dialog, plus we refuse to ack them which is correct behavior. 2006-08-21 04:44 we7u * src/main.c: Changing from a 1us delay to a 2ms delay inside UpdateTime(). Adding/ changing some comments. 2006-08-21 04:42 we7u * src/interface.c: Moving one debug line inside the data_lock block to make sure it doesn't get corrupted by another thread. 2006-08-19 15:19 we7u * src/interface.c: More correct fixes for truncation problem with new incoming data queue code. 2006-08-19 11:54 we7u * src/interface.c: A fix for the circular queue pointer problem. The read pointer was not getting advanced in the same manner around the queue as the write pointer, giving us an off-by-one error. 2006-08-19 10:42 we7u * src/interface.c: A temporary fix to the new queue code problem where it truncates the last character off the strings. 2006-08-18 14:52 tvrusso * src/map_shp.c: Remove commented-out ifndef of label-skipping code. It won't be needed. 2006-08-18 08:28 we7u * src/map_shp.c: Adding an #ifndef block for Tom Russo to play with. Currently commented out. If the block is enabled it will cause Xastir to draw every label for each polyline instead of skipping some based on zoom level. 2006-08-18 06:57 we7u * src/map_shp.c: Added some comments. 2006-08-18 04:07 we7u * src/: interface.c, interface.h, main.c: Shortening the delay at the end of UpdateTime() again to 10. Global variables for passing data from the read threads to main have been changed to a circular queue. This lets us queue up data from the read threads when we're busy drawing maps and such, then process it quickly when we're freed up. 2006-08-18 04:02 we7u * src/x_spider.c: Shortening delays so that we don't corrupt packets if we're fed them quickly by the pipe from Xastir. 2006-08-17 05:59 we7u * src/database.h: Renaming a function parameter so that it's not confused with a global variable name. 2006-08-17 05:47 we7u * src/db.c: Renaming a function parameter so that it won't be confused with a global variable name. 2006-08-15 03:38 we7u * src/map_shp.c: Patch for RTREE functionality with the new Shapefile speed mods. 2006-08-14 13:06 we7u * src/map_shp.c: Fixing an infinite loop condition that can happen if a Shapefile has points below -180.0 or above 180.0. 2006-08-14 12:38 we7u * src/track_gui.c: Changing from "sed --in-place" to "sed -i", perhaps more compatible across versions? 2006-08-14 12:34 we7u * src/track_gui.c: Fixing findu.com fetch trail function for base-91 packets w/no comment/course/speed/altitude. 2006-08-14 11:01 we7u * FAQ: Added another bit to the "remote restart" section. 2006-08-14 08:53 we7u * src/map_gnis.c: Reorganization to provide speedups. This one cuts about 50% of the time when zoomed in. 2006-08-14 08:52 we7u * src/map_gdal.c: Limiting to screen size instead of +/-32767. Added a comment about another possible optimization. 2006-08-14 05:24 we7u * INSTALL: Adding an invocation line for gprof that I use so I don't need to figure it out each time. 2006-08-14 05:12 we7u * src/: map_gdal.c, map_shp.c, maps.c, maps.h: Removing error-text parameter from map_visible_lat_lon() as we're not using it. Changed the order of checks in map_visible_lat_lon() to perhaps speed things up slightly based on which lines get his most often (gprof). Changed skip parameter for HandlePendingEvents in map_shp.c from 50 to 64, which is a power of 2 (perhaps faster?) and roughly the switchover point (via gprof) for lower CPU. 2006-08-11 16:58 we7u * src/: db.c, draw_symbols.c, map_gdal.c, map_shp.c, maps.c, maps.h, objects.c: Added dupe-checking for screen points to draw_vector and draw_point. Reduced the number of HandlePendingEvents calls we're doing inside the inner loop of map_shp.c. The end result is a speedup in Shapefile drawing. 2006-08-11 05:04 we7u * src/maps.h: Getting rid of stub for recompute_lat_lon() function which was deleted. 2006-08-11 05:03 we7u * src/: maps.c, util.c: Getting rid of duplicate code in the form of recompute_lat_long() and the global variables it populated. We have duplicate functionality in the f_NW_corner_longitude, f_SE_corner_longitude, f_SE_corner_latitude, and f_NW_corner_latitude global variables and the code that populates them. 2006-08-10 09:15 we7u * src/db.c: Took out a bit too much on one of the previous 2 or 3 revisions. Adding computation of screen coordinates back in for trail labels. 2006-08-10 09:09 we7u * src/: db.c, draw_symbols.c, map_gnis.c, map_shp.c, objects.c: Moving screen boundary checks into draw_nice_string() and removing them from lots of other places. 2006-08-10 09:08 we7u * src/maps.c: Adding a clip2d_screen() function for line-clipping to screen boundaries. Not used yet. 2006-08-10 06:01 we7u * src/maps.c: Added some sanity checking for dbfawk font_size variable. 2006-08-10 05:41 we7u * src/map_gdal.c: Added some comments. 2006-08-10 04:35 we7u * src/db.c: Changing to draw_point() instead of XDrawPoint for the vertice point drawing of tracklines. 2006-08-09 21:02 we7u * src/: db.c, draw_symbols.c, util.h, main.c, map_dos.c, map_gdal.c, map_gnis.c, map_shp.c, maps.c: Adding protection for the parameters of the XDraw* calls, making sure they don't go over 16 bits. 2006-08-09 07:56 we7u * src/draw_symbols.c: Changing the lu16 inline function to pass back the correct type and check against the correct max number. Added a bunch of comments elsewhere. 2006-08-09 07:03 we7u * src/draw_symbols.c: Limiting params to X11 drawing calls to 16-bit values. This should help prevent segfaults. We're actually limiting them more than we need to in most cases, but this should be ok. 2006-08-09 04:36 we7u * src/db.c: Added a debug line and comment. This one lets us play with/display aloha circles on startup if uncommented. 2006-08-09 04:35 we7u * src/draw_symbols.c: Fix for Aloha circle not getting drawn if it doesn't fit entirely on the screen. 2006-08-08 15:32 we7u * src/Makefile.am: A fix for a permissions problem that happens with compiledate.c every once in a while. This fix is by Dan Brown. 2006-08-08 15:30 we7u * src/draw_symbols.h: Checking in a header file that didn't get checked in with the other sources during the last commit. Dropped a couple of parameters from the draw_symbol() function. 2006-08-08 12:41 we7u * src/: db.c, draw_symbols.c: Fixed draw_pod_circle(), draw_bearing(), draw_phg_rng() and draw_DF_circle() so that they draw even when the symbol is off-screen. 2006-08-08 07:34 we7u * src/db.c: Fix for ambiguity box not getting disabled. 2006-08-08 06:05 we7u * src/maps.c: Added some comments about possible optimizations in the draw_point and draw_point_ll functions. Commented out the check against drawing long vectors to screen there as the clip2d* algorithms should take care of that for us. 2006-08-08 05:36 we7u * src/maps.c: Moving some of the functions to a different order that makes more sense. No real code changes. 2006-08-07 13:19 tvrusso * config/: 24kgrid.dbfawk, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsmzoddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, nwszoddmmyy.dbfawk, tgr2shp.dbfawk, tgr2shppoly.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: Fix broken dbffields variables in all dbfawk files. The dbfawk file is supposed to have semicolon-terminated statements. Unfortunately, the parser is busted and doesn't actually handle the case where the semicolons are omitted correctly. So, for example, BEGIN { dbfinfo="Blah:Diblah:Diblahdiblah"; dbffields="Blah:Diblah:Diblahdiblah" } winds up getting the newline-space at the end of the line added to dbffields, and thus in the list of names to be retrieved from the dbf file. This never matches the last field when applied to the dbf files, which have no such extra characters in the field names. This bug is masked by *how* the dbffields variables were actually set in the included dbfawk files: BEGIN { dbfinfo="Blah:Diblah:Diblahdiblah"; dbffields="Blah:Diblah:Diblahdiblah"} That is, since there was no newline between " and }, dbfawk didn't do the wrong thing. Unfortunately, many people have patterned their own dbfawk files after the ones in the config directory, and so this missing-semicolon deal got propagated (I am among those propagating it, as all my shape_web dbfawk files omitted the semicolon, but also put the brace right after the "). The problem only gets exposed when the user inserts a newline after the quote. This commit adds the semicolon (and a newline) after the dbffields closing quote. The real fix is to fix the dbfawk/awk parser so it doesn't let syntax errors like this slip through. 2006-08-07 12:56 we7u * src/maps.c: Renaming the window corner global variables. 2006-08-07 12:55 we7u * src/main.c: Renaming the window corner global variables. Updating some new global variables describing the SE corner in float and long format when necessary. 2006-08-07 12:53 we7u * src/: objects.c, xa_config.c, util.c: Renaming the window corner global variables. 2006-08-07 12:50 we7u * src/: location.c, location_gui.c, map_WMS.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c: Renaming the window corner global variables. 2006-08-07 12:49 we7u * src/: db.c, draw_symbols.c, xastir.h: Renaming the global variables describing the corners of the map window. Fixes for aloha circles and multipoing drawings so that they should appear if the symbol they're attached to is off-screen. 2006-08-07 06:49 we7u * src/draw_symbols.c: Getting rid of unused code. 2006-08-07 06:37 we7u * src/maps.c: Adding clipt(), clip2d(), clipt_long(), and clip2d_long() functions. These are implementations of the Liang/Barsky/Slater line-clipping algorithm. Modified draw_vector() and draw_vector_ll() to use them. Changing cutoff points for points/vectors to be consistent (+/-16000). 2006-08-07 06:33 we7u * src/db.c: Changing draw_trail() to use the draw_vector() function. 2006-08-07 06:27 we7u * src/: map_gdal.c, map_shp.c: Tweaking the pixel min/max cutoff numbers to make them consistent throughout the code. 2006-08-07 04:13 we7u * src/draw_symbols.c: Changed one comment. No code changes. 2006-08-04 07:35 we7u * src/maps.c: Changed draw_point() so that if it lies outside the screen we don't call the X11 draw routine. 2006-08-04 05:57 we7u * src/draw_symbols.c: A fix for dead-reckoning where the angle goes whacko at close-in zoom levels. 2006-08-04 04:42 we7u * src/db.c: Setting the precision rectangle sizes for our own station, whether transmit is enabled or not. 2006-08-04 04:17 we7u * src/track_gui.c: Using raw.cgi instead of rawposit.cgi to fetch packets from findu. This allows us to snag ALL packets from the station during the specified period instead of just posits. Weather, status, etc. 2006-08-04 03:55 we7u * src/db.c: Fixing the display of altnet's. Somewhere along the line we reversed it accidentally. 2006-08-03 16:32 we7u * src/db.c: Tweaking the NMEA decoding routines so that they pass back the number of digits after the decimal point. Changing the display for NMEA so that the number of digits changes the size of the "precision" rectangle. 2006-08-03 16:26 we7u * src/util.c: Fixing convert_lat_s2l() and convert_lon_s2l() so that they can handle from 0 to 6 characters after the decimal point for lat/long conversions. 2006-08-03 08:57 we7u * src/: db.c, objects.c: Fixing the problem where objects don't appear on the map after created. Also fixed transmission of objects so that if they have a course/speed the new position is sent out at the transmit interval. 2006-08-03 03:46 we7u * src/: database.h, db.c, draw_symbols.c, draw_symbols.h: The beginnings of the correct way of drawing the "precision" rectangles. Not all of the different types of packets are correctly sized yet, but many are. 2006-08-02 17:19 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Changing "precision" circles to rectangles, with the correct direction offset from the symbol for the different hemispheres. They are slightly too large at the moment, but at least of reasonable size. 2006-08-02 08:26 we7u * src/util.c: The chdir() call in log_data() appears to corrupt our "file" parameter. We don't appear to need the chdir() function call anyway, so have commented it out. We get passed the complete root-anchored path/filename as-is. 2006-08-02 05:30 we7u * src/db.c: Allowing the Station Chooser dialog to be closed without forcing the Station Info dialog to be closed. Commenting out the restore_position section in Station_data() as it isn't working correctly. 2006-08-02 04:58 we7u * src/objects.c: Changed/added some comments. No code changes. 2006-08-02 04:53 we7u * src/objects.c: Backing out the update of the Edit & Delete CAD Objects dialogs when allocating the first vertice of a new CAD Object. It's a bit confusing when the windows move on top of the drawing area when you do the first click, so I decided not to update then. 2006-08-02 04:47 we7u * src/objects.c: Updating the Edit and Delete CAD Objects dialogs at more places: *) When we create the first vertice on a new polygon *) When we hit either the Done or Cancel buttons on the Close Polygon dialog. 2006-08-01 07:49 we7u * src/: objects.c, util.c: Effectively removing the rounding code that was added on 6/21/2006. The rounding was not done properly to take into account overflow from seconds to minutes, or from minutes to degrees. 2006-08-01 05:49 we7u * src/popup_gui.c: Bumping up the min size for popup messages slightly. 2006-08-01 05:40 we7u * src/popup_gui.c: A start at fixing the problem where a popup message will come up too small on the screen and can't be resized. We now set a minimum size and don't fix the size, so it can be resized if necessary to read the message. 2006-07-31 06:42 we7u * src/objects.c: Fixed double-dash option for CAD objects. Update Edit/Erase CAD object dialogs if objects are changed. Use "" names if no actual label is selected. Commented out one message to STDERR during normal pre-defined objects processing, fixed up another message here to use get_user_base_dir() or get_data_base_dir() as appropriate. 2006-07-31 06:30 we7u * src/interface.c: Notifying the operator if emergency beacon mode is enabled but no transmits are actually occuring, for various reasons. 2006-07-31 06:28 we7u * src/messages.h: Cranking up max message windows from 10 to 25. 2006-07-31 06:27 we7u * src/main.c: Warning the user if ALTNET is enabled on startup (can be confusing when a new user sets this and then sees no stations). Setting a fixed beacon interval of 60 seconds if emergency beacon mode is enabled. 2006-07-31 06:25 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more strings for popup messages throughout the code, plus language strings for CAD Objects. 2006-07-25 07:53 we7u * src/util.c: A first attempt at snagging course/speed out of the previous posit if the last posit doesn't have it, for dead-reckoning purposes. It will only do this if the previous posit is still within the dead-reckoning timeout period. The goal here is to do dead-reckoning properly for stations which alternate GPGGA/GPRMC sentences (GPGGA don't have course/speed). 2006-07-24 12:04 we7u * src/draw_symbols.c: Removing dead or useless code. Reorganizing some of the tests where we determine whether to draw a particular symbol or attribute based on whether it is in the current view. 2006-07-24 12:01 we7u * src/db.c: Changing to setting flags in the station record when it's our station or object/item, then checking flags, instead of checking the "call_sign" or "origin" constantly throughout the code with string compares. Got rid of the second drawing iteration where we were drawing new stations to the screen _and_ to pixmap_final. We now draw to the screen and rely on the next full screen-update to do the rest. 2006-07-24 11:54 we7u * src/main.c: Fixing the -geometry flag so that it works for strings like: "-geometry -0-0" 2006-07-22 07:47 tvrusso * src/dbfawk.c: Possible fix for bug that prevents dbfawk files with a single field in the dbffields list from working unless a colon is added to the end of the list. This appears to be a very platform dependent bug, as I have never been able to reproduce the problem. But the fix is still valid --- the issue is that no null terminator is added to a field name unless a colon is found. This fix doesn't break anything, but I'm unable to verify that it actually fixes the problem reported, since I have never actually seen that problem in action. 2006-07-20 13:05 we7u * src/maps.c: Dump a couple of messages out from map_indexer() to STDERR. This makes it evident why Xastir is so busy when first started up in a fresh config directory, if there are a lot of maps present on the system. 2006-07-20 12:28 we7u * src/main.c: Nope, 50 was too slow, but 25 looks good so far. 2006-07-20 12:23 we7u * src/main.c: Slowing down the main UpdateTime() loop again. We seem to keep up with a 2.6 kernel with nexttime=50. Previously 10. 2006-07-19 07:40 we7u * src/: igate.c, interface.c, main.c, maps.c, messages.c, xa_config.c: Fixes to get rid of complete path in the config file for variables that need to change between different configs. If a user has specified a complete path (other than the default path), Xastir will honor it. If the default path is there, Xastir will shorten it so that multiple configs may use it. 2006-07-19 04:27 we7u * src/: database.h, db.c, list_gui.c, objects.c: Getting rid of many of the is_my_call() invocations, instead setting flag bits in the DataRow->flag variable to specify whether it's our callsign-SSID or whether it's an object/item owned by us. This gets rid of literally millions of string compares. 2006-07-17 17:41 we7u * src/db.c: Skip doing dead-reckoning if scale > 8000. Doing point-caching of last-point-drawn in draw_trail() to reduce the amount of drawing we do when it's the same screen pixel over and over (when zoomed out). 2006-07-17 17:38 we7u * src/database.h: Adding a new flag definition in preparation for a rewrite of the is_my_call() function. 2006-07-17 09:12 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c: Patch for bug 1522493 by Dan Brown, n8ysz: The caching "bad" files problem. It should whack things out of the cache if, for whatever reason, they're unusable. 2006-07-17 04:57 we7u * src/: main.c, xa_config.c, xa_config.h: More tweaks by Dan Brown, n8ysz: Cleaned up the get_user_base_dir() in xa_config.c to be more careful about returning complete paths. 2006-07-16 12:02 tvrusso * src/: color.c, map_geo.c: Clean up transparency code for .geo maps, removing debug output. This now works properly for 16 and 24 bit DirectColor/TrueColor displays. It is horribly broken for 8-bit displays, but as far as I can tell it was horribly broken *before* I started. On 8-bit displays the WMSRadar image doesn't even get displayed, transparent or not, before *and* after my changes. I was unable to figure out why. 2006-07-16 10:21 tvrusso * src/: color.c, map_geo.c: An interim commit of partial fixes to the transparency problem on .geo files. Mostly committing this to get it to a machine that has a display that isn't 24-bit for testing. Lots of cruft in here needs editing out after testing is complete. 2006-07-14 11:50 we7u * README.Getting-Started, xastir.1: Updates by Dan Brown, n8ysz. 2006-07-14 08:53 we7u * src/: main.c, xa_config.c: Additions/fixes to implement alternate Xastir config directories. Patch submitted by Dan Brown, n8ysz. 2006-07-13 05:10 we7u * scripts/get-NWSdata: Fixing up the domain names so that they all match (for consistency). 2006-07-12 10:47 we7u * scripts/get-NWSdata: Updating one NWS shapefile name to latest version. 2006-07-12 10:47 we7u * README.MAPS: Updating the text for NWS Shapefile names to match the NOAA website. 2006-07-12 07:24 we7u * src/draw_symbols.c: A fix for the bug where text-on-black obscure text above/below slightly due to the black background. We now separate the text by another pixel and the problem goes away. 2006-07-11 09:06 tvrusso * WMSRadar.geo: Tweak transparency value. For some time now, the actual "no reflection" value that's been coming in has been hex value 0x010101, not "0x000000". On 24-bit displays that means that the default file was displaying with an opaque nearly-black background instead of a transparent one. The actual no-reflection value returned by the WMS server has changed back and forth between 0x000000 and 0x010101 often in the history of the WMSRadar file and will probably need to be changed again some time in the future. It has been pretty consistently 0x010101 for several weeks now. 2006-07-11 07:38 we7u * src/db.c: Fixing incorrect timestamps for local station. This was causing track points to get expired immediately so that the station didn't show a track if being run with only a GPS interface. 2006-07-11 06:02 we7u * src/draw_symbols.c: Fixes for dead-reckoning 180 degree problem and for the DR arc being slightly off. 2006-07-11 05:18 we7u * src/draw_symbols.c: Removing dead code. 2006-07-11 05:06 we7u * src/draw_symbols.c: More efficient dead-reckoning code plus commenting out unused sections of code. 2006-07-11 04:41 we7u * src/draw_symbols.c: More tweaks to dead-reckoning. We now attempt to display the arc and the DR'ed trail if either the symbol or the DR'ed symbol are on-screen. Added an "if" clause to the DR'ed symbol drawing so it is only drawn when on-screen. Commented out old code that we're not using anymore. 2006-07-11 04:01 we7u * src/util.c: Another fix by Dan Brown, n8ysz. This one keeps the log files at or below the max logfile size. 2006-07-11 03:59 we7u * src/interface.c: Removing a duplicate include line. Thanks to Dan Brown for finding it. 2006-07-10 20:15 we7u * src/draw_symbols.c: Implenting DR arcs again. Problems near/at 180 degrees, but other than that it seems to work fine. 2006-07-10 10:24 we7u * src/db.c: Disabling the XtRemoveGrab() function call which causes warnings on some OS'es. I don't believe we actually need it. We'll find out for sure when more users try out this version. 2006-07-10 10:23 we7u * src/draw_symbols.c: Test code for re-enabling the dead-reckoning arc's. Not complete/correct yet, but it's a start. 2006-07-10 09:40 we7u * src/wx.c: Fixes by Mike Loebl, kb1mts, to add barometric pressure and humidity decoding to ARNE format. 2006-07-10 05:57 we7u * src/main.c: Fixing high CPU usage problems on FreeBSD, changing nexttime from 2ms to 10ms. Thanks to Carl Makin for this tweak. 2006-07-10 04:09 we7u * src/util.c: Fixes by Dan Brown, n8ysz, for Xastir bug 1518805: "Log files can fill up hard drive". We now limit a log file to about 2MB at which point we roll it over to a new filename and create a new empty file to write to. We keep up to 3 of these backup files plus the current log file at any given time, which makes for between 6MB and 8MB of data that we keep. 2006-07-07 09:10 we7u * README.Contributing: Added a section by Dan Brown. 2006-07-07 08:06 we7u * scripts/BUILDRPMS: Tweaking the rev number. 2006-07-06 09:23 we7u * src/main.c: Fixes by Dan Brown, n8ysz, for Xastir bugs 1515197 "segfault if XASTIR_USER_BASE no existing" and 1517761, "No error check on config dir mkdir". 2006-07-06 08:36 we7u * src/: main.c, track_gui.c: Fixes for the blank label problem on sliders with certain releases of OpenMotif. This relates to problems with using XtVaTypedArg within an XtVaCreateManagedWidget() function. Instead we now call XmStringCreateLocalized() before the call, and XmStringFree() afterwards. 2006-07-05 07:17 we7u * src/: Makefile.am, main.c: A patch to add compile time/date to the Help->About dialog, by Dan Brown, N8YSZ. 2006-06-29 10:04 we7u * src/xa_config.c: Making the igate -> RF path default be "WIDE2-1". 2006-06-27 07:25 we7u * src/igate.c: Reorganizing the logic slightly to make it easier to understand w.r.t. the gating of objects/items/stations to RF via the nws-stations.txt file. Added/updated several comments. 2006-06-23 09:03 we7u * src/db.c: Adding more comments. No code changes. 2006-06-23 08:31 we7u * src/igate.c: Changing igating->RF around so that if a station or object name is found in the nws-stations.txt file, it will get gated to RF whether or not "TCPXX" is found in the path. This allows more types of things to be gated to RF if manually specified in the nws-stations.txt file. 2006-06-22 05:42 we7u * src/db.c: Mostly changes to comments, but changed the error ellipses from black to white. Still need to draw truncation rectangles instead in some cases. 2006-06-21 07:49 we7u * src/objects.c: Tweaking the rounding in objects.c 2006-06-21 06:12 we7u * src/util.c: Changing some comments. 2006-06-21 05:41 we7u * src/: interface.c, util.c: Fixing up posits so that we round properly instead of truncating the higher resolution digits. For some-odd reason the fprintf doesn't round up properly at 0.5, so we add a 0.01 to the number so that it rounds up. 2006-06-21 04:51 we7u * src/db.c: Changing one comment. 2006-06-20 05:55 we7u * src/: database.h, db.c, draw_symbols.c: An attempt to do the error ellipses for position packets. This is most likely not the display we'll finalize on, but it's a start. We draw circles for the less-precise posits, but as Tom Russo pointed out they should probably be rectangles. Also, the GPGGA/GPRMC/GPGLL code needs some work w.r.t. these. 2006-06-19 14:47 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Making sure we don't try to do dead-reckoning on stations that have position ambiguity enabled. 2006-06-19 11:58 we7u * README: Adding notes for OpenSuSE 10.1 2006-06-16 13:29 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: More ambiguity fixes. 2006-06-16 12:58 we7u * src/: database.h, db.c: Correcting the spelling of "ellipse". 2006-06-16 12:08 we7u * src/draw_symbols.c: Changes to a few comments. 2006-06-16 12:06 we7u * src/: database.h, db.c, draw_symbols.c, draw_symbols.h: Adding a variable for doing error_ellipses around posits. Not in use yet. Changed the position ambiguity around so that it is correct and the symbol position inside the rectangle is correct. Still need to fix up the grid-square code in the draw_ambiguity function though. 2006-06-15 14:28 we7u * src/draw_symbols.c: Fixing up some of the ambiguity rectangle stuff. All but the grid squares look ok now, but the smallest rectangle ends up with the symbol placed off-center, which still needs to be fixed. 2006-06-15 12:46 we7u * src/draw_symbols.c: Changing from stippled ambiguity rectangles to solid lines. 2006-06-15 07:33 we7u * src/draw_symbols.c: Changing ambiguity rectangles from filled to unfilled, plus drawing lines from symbol to each corner of rectangle so we know which symbol is being drawn with the ambiguity. 2006-06-14 13:55 we7u * src/database.h: Doesn't make much sense to add the new parameter to the station database at this time when code doesn't use it. It would only take up memory. Commenting it out for now until we get to using it. 2006-06-14 13:50 we7u * src/database.h: Preliminary addition of an error_elipse storage area for the station record. Not actually used in the code yet as we're still discussing how it should best be used/displayed. 2006-06-14 07:17 gstueve * src/util.c: Only check VHF porion of path. Still need to process 2nd portion for proper behavior. 2006-06-14 07:13 gstueve * src/util.c: Only change lower case characters to uppper, don't bother to rewrite upper. 2006-06-14 07:10 gstueve * src/util.c: Fix spelling in comment. 2006-06-12 09:17 we7u * FAQ: Added "socat" to the FAQ. 2006-06-08 14:04 we7u * src/: db.c, objects.c: Changed some comments to show the last GPROF percentages for the heavy-hitters. No code changes here. 2006-06-07 07:18 we7u * config/tnc-startup.d700: Changed the comments at the top. Added note about Alinco's. 2006-06-07 07:03 tvrusso * FAQ: Update pointer to latest version of the FAQ. The URLs that were here were very outdated. 2006-06-06 12:22 we7u * src/db.c: Some packets with an extra digit in the latitude end up going through the compressed packet decode routine. This fix causes those packets to be rejected from that routine. 2006-06-05 15:01 we7u * Davis/src/db2APRS.c: Davis mods by Clay Jackson, n7qnm. Added some MySQL error checking, set it up so it would always get the 'latest' records, and generally improved the error handling (things like 0 or >100 pct humidity, pressure below 26 or above 31, and so on). 2006-06-05 12:20 we7u * scripts/get-NWSdata: Tweaking the script so that it only fetches files we don't already have. 2006-06-05 12:19 we7u * configure.ac: Bumping revision for devel to 1.8.3. 2006-06-05 11:50 we7u * configure.ac, scripts/BUILDRPMS, scripts/do_xastir_release_dev: Updating to 1.8.2 to get ready for stable release. 2006-06-05 11:43 we7u * scripts/do_xastir_release_stable: Updating default version number. 2006-06-05 10:14 we7u * README.MAPS: Added a section describing how to create your own Shapefile maps with Xastir. Added a section describing CAD Object polygons. 2006-06-05 09:46 we7u * scripts/fcc-get: Updating to match newer "sort" function's syntax. 2006-06-02 09:43 we7u * config/language-German.sys: Updates by DK7IN. Thanks! 2006-06-02 08:35 we7u * scripts/get-NWSdata: Updating to latest NOAA filenames. 2006-06-01 10:05 we7u * README.MAPS: Fixing the path for gpx2shape so that people look for it in the scripts directory. 2006-06-01 10:04 we7u * scripts/Makefile.am: Adding gpx2shape to the build. 2006-06-01 10:04 we7u * scripts/gpx2shape: A nice contribution by James Washer. Convert GPX files to Shapefiles. 2006-06-01 09:35 we7u * README.MAPS: Added a blurb about National Geographic's Topo, TPO/TPG files, mapXchange, gpsbabel, and gpx2shape.pl. 2006-06-01 07:17 we7u * README.MAPS: A bit added by Kyle Kienapfel regarding the Canada topo file. Thanks! 2006-05-31 13:39 we7u * src/igate.c: Disallowing igating of general queries in either direction. Directed queries still get gated as appropriate. 2006-05-31 13:36 we7u * src/db.c: Added some comments. 2006-05-31 12:57 we7u * src/: db.c, wx.c: Fixing the backwards conversions for wind speed for Peet Bros. Ultimeter-II weather stations. The correct units are km/h if the sentence begins with '#', and mph if the sentence begins with '*'. 2006-05-31 12:30 we7u * src/wx.c: Changes to comments/added some comments. 2006-05-31 11:39 we7u * src/wx.c: Zeroing the first two digits on wind speed for Peet Bros 2k as per the docs. 2006-05-31 11:25 we7u * src/wx.c: Changing a few variables to make the code more consistent. Instead of pointing back to the original data to check for ">7", we look at the first character of our substring temp_data1[0]. 2006-05-31 11:09 we7u * src/wx.c: Fixes for Peet weather stations, negative value decoding. 2006-05-30 13:06 we7u * src/map_gnis.c: Fixes to make Xastir handle the type of GNIS files found at: which have shorter lines than the ones at: 2006-05-30 11:50 we7u * src/interface.c: Really complicated fix for Xastir dropping the last character of a packet. A fix for the last fix I put in. 2006-05-30 09:07 we7u * src/db.c: Changed one comment. 2006-05-30 08:18 we7u * src/: database.h, db.c, interface.c, main.c: A bug fix for KISS or AGWPE ports. The AX.25 header increases in size when it gets converted to TAPR2-style headers. If there were enough digipeaters in the path then the complete packet can get truncated on the tail-end. This patch fixes it by allocating a separate buffer that is quite large for each packet before the header decoding function. 2006-05-17 12:28 we7u * src/db.c: Fixing the reply-ack problem during messaging. It was an off-by-one error. Our ack_string looked like "}5o" instead of "5o", which made the comparison fail. 2006-05-13 09:27 we7u * src/Makefile.am: Adding rpl_malloc.h to the build. 2006-05-12 13:32 tvrusso * FAQ: Add command for converting Root files to new scheme. Of course, if someone could check this file out to see the commands, they've already done the conversion... 2006-05-12 13:05 we7u * scripts/do_xastir_release_dev: Fixing a typo. 2006-05-12 13:03 we7u * install-xastir: Updating to the latest SourceForge CVS server names. 2006-05-12 13:00 we7u * scripts/: do_xastir_release_dev, do_xastir_release_stable: Updating to correspond to latest CVS server names. 2006-05-12 12:44 we7u * FAQ, README.CVS, README.win32: Updating the CVS instructions to correspond to the changes implemented today on SourceForge. 2006-05-12 12:44 we7u * config/tnc-startup.d700: Adding "HEADERLN off", which we appear to have missed at some point. 2006-05-04 08:01 we7u * README.win32: Added a note about what to call COM1/COM2 in Cygwin. 2006-04-29 10:19 tvrusso * symbols/symbols.dat: Change \V symbol (VORTAC) to something that looks like what the other APRS codes use, matching the VORTAC symbol on aviation charts. 2006-04-24 12:21 we7u * src/: alert.c, awk.c, bulletin_gui.c, color.c, datum.c, db.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, macspeech.c, main.c, map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, messages.c, messages_gui.c, objects.c, rotated.c, rpl_malloc.c, shp_hash.c, snprintf.c, sound.c, testawk.c, track_gui.c, util.c, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, xastir_udp_client.c: More fixes for rpl_malloc, plus made the callouts for config.h more consistent. 2006-04-24 10:20 we7u * src/: Makefile.am, festival.c, rotated.c, util.c, util.h: Separating out the rpl_malloc code so that it can be used in other programs like testawk. 2006-04-24 10:19 we7u * src/: rpl_malloc.c, rpl_malloc.h: Separating out the rpl_malloc stuff so that it can be used in other programs like testawk. 2006-04-21 14:01 we7u * src/db.c: Correcting spelling in one comment. 2006-04-21 13:51 we7u * src/db.c: This change clears the transmitted message so it won't get transmitted again after a REJ packet, and gets rid of a printf to STDERR for each REJ. 2006-04-21 12:58 we7u * src/db.c: Added support for REJ packets, including igating of same. Yet to be tested. 2006-04-21 12:57 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added a "*REJECT*" string for REJ packets. 2006-04-20 09:47 we7u * README.win32: A tweak by Wes Johnston for getting bootstrap.sh to run properly. 2006-04-20 08:05 we7u * src/wx.c: Reverting back to the code for version 1.54, as the rounding for negative numbers wasn't done correctly and caused more harm than good. 2006-04-20 07:22 we7u * symbols/: alert.xbm, flood.xbm, red_flag.xbm, snow.xbm, tornado.xbm, wind.xbm, winter_wx.xbm, wntr_strm.xbm: Thanks to Jason Winningham, kg4wsv, for these weather alert pics that stack up much more nicely than the originals, while leaving more of the map below visible. 2006-04-10 07:31 we7u * scripts/get-maptools.sh: Script to get/install several of the map libraries, written by Dan Brown, N8YSZ. 2006-04-05 09:13 we7u * scripts/Makefile.am: Adding two of the newer scripts into the Makefile. 2006-04-05 09:09 we7u * README.win32: A tweak by Joe Cotton to get the finger command working in Xastir/Cygwin. 2006-03-16 18:32 tvrusso * INSTALL: Put the word "shapelib" closer to the place where we explain how to install it, so it is more quickly found by a search with "less" or "grep". 2006-03-16 00:03 tvrusso * README.MAPS: Fixx mispleling. 2006-03-16 00:02 tvrusso * README.MAPS: Added a little commentary about the mrsiddecode program. 2006-03-13 17:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/objects.c: Shortening "Area" to "A" for CAD objects. Also shortening the unit descriptions. 2006-03-13 17:32 we7u * src/db.c: Refusing to do the emergency popups until/unless we have a position for a station. It's hard to help someone if we don't know where they are at. This keeps Xastir from annoying the crap out of people every 30 minutes if a posit for that station isn't coming in, but a packet with certain keywords _is_ coming in regularly. 2006-03-10 12:56 we7u * INSTALL: Added another note about libtiff-3.8.0 2006-03-10 12:45 we7u * INSTALL: Adding solution text regarding the libgdal/libgeotiff GTIFProj4ToLatLong problem. 2006-03-10 12:28 tvrusso * README.MAPS: Fix a handful of mispleellings and mistales. 2006-03-10 12:09 tvrusso * README.MAPS: Rearrange some of the discussion of how to manipulate randomly mutilated GeoTIFF files. 2006-03-10 08:16 we7u * README.MAPS: Adding a section about using gdal_translate to convert crappy geoTIFF's to usable ones. Thanks to Tom Russo for the info on how to do this. 2006-03-10 08:15 we7u * INSTALL: Slightly changing some wording in the gdal section. Nothing of importance. 2006-03-09 12:47 we7u * INSTALL: Updating various library revision numbers. Added a note about a possible geoTIFF conflict when installing GDAL. 2006-03-09 12:46 we7u * src/map_tif.c: Making sure that Proj.4 error messages appear only under the correct circumstances. 2006-03-08 18:43 we7u * src/db.c: Initial implementation of a distance check for warnings/alerts. Default is set to 280 miles or kilometers (whichever mode you are set in), and the check defaults to ON, meaning it will check each time whether the station is within that distance. This version has no user controls for the new functionality implemented yet. 2006-03-07 18:44 we7u * src/wx.c: Fixing the rounding for some of the values that can be negative, coming from weather stations. 2006-03-07 16:41 we7u * FAQ, README.Getting-Started, README.win32: Updating/Adding instructions for snagging NWS files via new script. 2006-03-07 09:56 we7u * README.MAPS: Adding filename patterns to the NWS file descriptions. 2006-03-07 09:56 we7u * scripts/get-NWSdata: Adding the fire weather zones to the mix. 2006-03-07 09:05 we7u * README.MAPS: Adding a bit about the get-NWSdata script. 2006-03-07 09:04 we7u * scripts/get-NWSdata: Modified the script to do one download/unzip/delete the .zip file, then start on the next. This will keep disk space requirements down plus not have the .zip files hanging around when we're all done. 2006-03-07 08:53 we7u * scripts/get-NWSdata: A new script to fetch NWS data files used for weather alerts. Curt, WE7U and Steven, WM5Z had a hand in writing it. 2006-03-03 12:31 we7u * src/db.c: Checking for 8-bit characters in Mic-E packets, except for the case of 8-bit telemetry extension fields where we skip the check. 2006-03-03 08:19 we7u * src/track_gui.c: Re-enabling the popup on findu track download failure, as it doesn't appear to be the source of James Ewen's segfaults when his DNS failure occurs. It appears to be a segfault from libcurl itself. 2006-03-02 14:53 we7u * README.win32: Added a note about compiling libproj into gdal statically in order to install on Cygwin. 2006-03-01 10:37 we7u * config/tnc-startup.thd7: Commenting out the hbaud line and adding a comment about it. 2006-03-01 08:30 we7u * README.Contributing: Added a note about core files appearing where you least expect them. 2006-03-01 08:02 we7u * src/track_gui.c: Adding comments near another popup message that could conceivably cause segfaults: The "Success" message from fetching a findu trail. This particular popup has worked properly for me with no segfaults so far. We may need to investigate whether multiple threads writing to X11 at the same time can cause segfaults. I believe I've seen this in other cases, but my memory may be faulty on this matter. 2006-02-28 11:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c, src/maps.h, src/xa_config.c: Checking in mods by Dalen Kruse, KC0OVU, which implement a timing slider for snapshots with a range from 1 to 30 minutes. 2006-02-28 00:01 we7u * src/track_gui.c: Getting rid of the GUI stuff in fetch findu trail: It happens in a separate thread now and we can't write to the GUI from two threads at once due to possible segfaults. 2006-02-27 13:02 we7u * src/wx.c: A fix for negative values being interpreted incorrectly due to varying sizes of INT on different systems. 2006-02-27 11:40 we7u * config/tnc-startup.thd7: Changing HBAUD to 9600 so that it matches the default serial port speed. 2006-02-24 19:01 tvrusso * src/db.c: Fix appallingly stupid mistake in passing arguments to XtVaSetValues. I coulda *sworn* I had just copied what was already there, but apparently not. This fixes the problem where the Incoming Data scrolled text widget was not scrolling to the bottom of the incoming data as new stuff was added. 2006-02-24 10:38 tvrusso * src/db.c: Complete refactor of how the "packet_data_string" stuff is updated and displayed. We no longer do "memmove" to cycle old data out of the array, but rather use a two-dimensional array of strings treated as a ring. Data is shifted out of the Display Incoming Data dialog box using XmReplaceText calls. I have tested this out in several ways and it appears to function precisely as the old one was intended to do. This *might* be the solution to the sporadic segfaults we've been seeing and the less harmful "line too long for array" warnings. 2006-02-23 16:38 we7u * src/db.c: Add a null pointer check to delete_station_memory(). Changed an "if" to an "else" clause in insert_new_station(), which just made the code slightly simpler but didn't change any operation. Multiple comment changes. 2006-02-23 16:01 we7u * src/xa_config.c: Increasing the default for Internet Map Timeout from 90 to 120 seconds. 2006-02-23 15:59 we7u * src/util.c: Adding messages something like "Possible timeout, try increasing Internet Map Timeout" to the libcurl and wget code. 2006-02-22 08:53 chicoreus * src/maps.c: Adding grid labels for UTM major grid. All grid types and resolutions now have some kind of labeling available. 2006-02-22 08:51 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added metadata text for UTM major zones. 2006-02-19 12:50 rzg * src/dbfawk.c: Small memory leak found by valgrind; I think this should fix it. 2006-02-19 12:02 tvrusso * scripts/object2shp.pl: Bug fix. Make sure to ignore comment lines in the object file, or any other lines that don't start with semicolon. 2006-02-19 11:56 tvrusso * README.MAPS: Add explanation of how to use object2shp.pl into README.MAPS under the "Rolling your own shapefile maps" section. 2006-02-19 11:48 tvrusso * scripts/: Makefile.am, object2shp.pl: Per discussion on xastir mailing list, a script to create shapefile maps from the object.log file. This will enable quick and dirty generation of special purpose map overlays by plunking down objects, creating shapefiles, then deleting the objects. 2006-02-16 21:50 we7u * src/: database.h, db.c, list_gui.c: Changing the names of pointers so that their function is more easily recognizable. 2006-02-16 12:45 we7u * src/x_spider.c: Added more output messages in case of error which suggest killing old Xastir processes in order to remove the error. 2006-02-16 12:44 we7u * src/: db.c, messages.c: Fixing up msg_data_add() so that we can tell when we've rejected a message. Tweaked the code which invokes it so that it knows the difference between new/old/rejected messages. 2006-02-15 08:46 chicoreus * src/: maps.c, maps.h: Refinements to the calculation of latitude and longitude grid spacing. Triming the latitude and longitude strings in the grid border when zoomed out. Reduced the number of variables being passed in the functions called by draw_grid() by moving them to function calls or constants. 2006-02-14 14:00 we7u * src/db.c: Initializing struct pointers to NULL right after malloc of the struct, before we try inserting it into any linked lists. 2006-02-14 13:11 we7u * src/: database.h, db.c, gps.c, igate.c, objects.c: Converting all MAX_TNC_LINE_SIZE (was 300) to MAX_LINE_SIZE (currently 512). Just simplifying things. 2006-02-14 12:07 we7u * src/db.c: Printing out ALL of the guard bands that get corrupted, not just the first one that's noticed. 2006-02-14 11:59 we7u * src/db.c: Adding a couple more guard bands, changing them to only 10 chars each, making the error text print out which guard band was corrupted. 2006-02-14 11:34 we7u * src/db.c: Making the Incoming Data display's char array manipulation code a bit less scary. It had the potential to overflow if conditions were just right, but the conditions were extremely unlikely to occur. 2006-02-14 11:33 we7u * src/interface.c: Bumping up the sizes of some char arrays. Just because. Probably don't help much, but don't hurt either. 2006-02-14 11:32 we7u * src/main.h: Removing some unused defines. 2006-02-13 12:30 we7u * src/: db.c, interface.c, interface.h, main.c: Adding guard bands around the main station pointer variables, plus code to check for intrusion into those guard bands. This may help us to find the current segfault problem. 2006-02-12 16:13 chicoreus * help/help-English.dat: Changing the grid border help to include latitude and longitude. 2006-02-12 16:10 chicoreus * src/maps.c: First cut at an algorithmic method for determining the spacing of latitude and longitude grid lines at a scale appropriate for the current window size and map zoom. 2006-02-12 10:03 we7u * src/db.c: Correcting some debug output message text. 2006-02-11 18:10 we7u * src/db.c: Doing some more error-checking in the station record pointers. We do an abort() if we end up with dangling pointers, which should give us a core dump immediately. 2006-02-10 12:27 we7u * REGRESSION_TESTS, configure.ac: Tweaks to add more regression tests and format the output so that it's easier to read. 2006-02-10 11:13 tvrusso * README.Contributing: Add a section on using separate "build directories" to maintain specialized builds rather than building in the source tree. 2006-02-09 17:08 we7u * src/maps.c: Fixes for the map grid segfault problem. 2006-02-09 15:14 tvrusso * README.Contributing: Change commentary on how to do debugging builds. 2006-02-09 14:32 we7u * README.Contributing: Adding a debugging note from Tom Russo. 2006-02-09 13:27 tvrusso * acinclude.m4: Change XASTIR_COMPILER_FLAGS so that it doesn't insert "-g -O2" unconditionally. That is unnecessary since we call AC_PROG_CC, which *conditionally* inserts "-g -O2" into CFLAGS if the user hasn't specified CFLAGS on the configure line. This should allow users to build specialized debugging versions such as ./configure CFLAGS="-O -g -fno-inline" and not have configure stick a "-O2" in unbidden. 2006-02-09 12:41 we7u * src/maps.c: A temporary fix to skip computing the UTM/MGRS grid if we run into a problem, before we segfault. 2006-02-09 12:14 we7u * src/maps.c: Adding some comments. 2006-02-09 12:12 we7u * src/maps.c: Again splitting the minor UTM grid stuff into separate functions. 2006-02-09 11:40 we7u * src/maps.c: Reorganizing the draw_grid() function. Breaking it up into smaller pieces. 2006-02-08 07:11 we7u * src/main.c: Checking for proper status of unlink in pid_file_check(). 2006-02-08 06:28 we7u * src/main.c: Removing some code that doesn't get used in the RINO download section of the switch. 2006-02-06 18:37 we7u * src/maps.c: Commenting out unnecessary code. 2006-02-06 18:33 we7u * INSTALL, README.Getting-Started, UPGRADE, update-xastir: Clarifying the use of SUID root a bit. Removing that command from update-xastir so that the default will be to create a core file. 2006-02-06 13:35 we7u * src/maps.c: Some fixes for segfaults and divide-by-zero faults in the draw_grid() function. At least one more segfault path remains in this body of code. 2006-02-06 09:03 we7u * README.Contributing: Adding more info to the debugger info. 2006-02-06 08:21 we7u * src/db.c: Tweaking Mic-E decoding logic to properly decode overlay characters. 2006-02-03 10:09 chicoreus * src/util.h: Missing an extern 2006-02-03 09:47 chicoreus * src/: maps.c, util.c, util.h: Adding MGRS to labeled grid border. 2006-02-03 09:46 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing grid metadata text to allow MGRS support. 2006-02-02 14:02 we7u * src/maps.c: Extending some char arrays so that they're long enough to hold the terminator. 2006-02-02 10:58 chicoreus * src/: main.c, maps.c, util.c, xastir.h: Added degree and minutes symbols to lat/long grid border labels by adding constants for convert_xastir_to_UTM() to produce strings containing these symbols. Truncation of trailing zeroes on UTM grid labels, with number of zeroes removed depending on utm_grid_spacing_m. Changed following feedback from use of printed maps during a GPSAR training. Added internationalization for lat/long and UTM grid border metadata. Added metadata on top border for labeled lat/long grids. Latitude drawn on both left and right borders. Put the xastir coordinate to MGRS conversion into a function that extracts the components of the MGRS string separately, then made convert_xastir_to_MGRS_str() a wrapper around this function in prepration for labeling the MGRS grid. 2006-02-02 09:57 we7u * README.Contributing: Adding info about core dumps and how to bring up a debugger. 2006-02-02 08:49 we7u * README.Getting-Started, src/main.c: Reversing the meaning of the "-t" command-line flag: The segfault handler is now turned off by default (meaning we'll dump core instead). The "-t" flag turns on the internal segfault handler now instead of disabling it. 2006-02-02 08:04 we7u * configure.ac: Commenting out the code that removed the "-g" GCC option. As Tom pointed out, it was a bad idea. 2006-02-02 07:29 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added internationalization strings for metadata line for top border of map when map grid border is displayed. 2006-02-02 07:10 we7u * src/util.c: A fix for the missing UTM grids with gcc-4.x problem. 2006-02-02 07:10 we7u * src/maps.c: Changing one debug output line. 2006-02-01 08:42 we7u * acinclude.m4: Patching the search list for Berkely DB library by adding 4.3 and 4.4 search paths. 2006-02-01 08:24 chicoreus * src/maps.c: Added border labels for latitude and longitude grid. 2006-01-31 10:32 chicoreus * src/maps.c: More tuning of labeled border for UTM grid. Added Zone number and letter in all four corners when two zones are shown. All text in border changed to black with border color outline. For two zones, northings for one zone appear on the left side of the screen northings for the other on the right. The left zone is labeled in black, the right zone labeled in blue. Minor fixes to turn off display of labels where they run off the screen. 2006-01-30 07:31 tvrusso * configure.ac, src/maps.c: "roundf", recently used in maps.c, is a newer extension that is not present in systems that still have old C compilers. Insert a check for roundf, and a workaround for systems that don't support it. 2006-01-28 11:21 we7u * bootstrap.sh: Fixing the file test syntax to use Bourne syntax instead of Bash. 2006-01-27 20:36 chicoreus * src/maps.c: Minor changes and bug fixes to the UTM grid border labeling code. Includes rounding of the grid labels to correctly label 10,000 m, 1,000m, and 100m grids, not just the 100m grid. 2006-01-27 15:40 chicoreus * src/: maps.c, rotated.c: Added code to RotatedTextItem in rotated.c library to handle special case of rotation of text 90 degrees counter clockwise. In this case, text is rotated by directly transposing x and y coordinates, rather than by applying a sine and cosine transformation to rotate the text, something that produces an italic appearance to the rotated text (making it harder to read, especially when printed). This change is to support more legible text on the labeled UTM grid on the border of the map, especially for producing maps to be printed. Also made minor changes to border label code in maps.c to make quick and dirty improvements to appearance. 2006-01-27 08:30 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Since the three bootstrap.sh scripts are the same anyway, run the one from one directory up instead so that we don't have to keep rev'ing all three of them when a change is needed. Like, duh! 2006-01-27 08:14 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Updating for Solaris. 2006-01-27 08:10 we7u * bootstrap.sh: Removing the comment marks that I shouldn't have committed to CVS. 2006-01-27 08:05 we7u * bootstrap.sh: Updating for automake system directories on Solaris. 2006-01-27 06:57 we7u * README: Updating the SuSE 10 notes to mention libcurl-dev as well. 2006-01-26 14:51 we7u * Davis/src/Makefile.am: Installing the compiled db2APRS into the bin directory. 2006-01-26 12:57 we7u * scripts/BUILDRPMS: Getting rid of some shell warnings. 2006-01-26 12:39 we7u * Makefile.am, scripts/BUILDRPMS: Adding LaCrosse directory into the build. 2006-01-26 11:06 we7u * Davis/.cvsignore, LaCrosse/.cvsignore: Updating the list of files that CVS should skip. 2006-01-26 08:59 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Updating bootstrap.sh for separate weather apps so they are the same as the main Xastir bootstrap.sh 2006-01-26 07:55 n0vh * LaCrosse/: weatherdump.sql, src/Makefile.am: SQL file of open2300 database 2006-01-26 07:44 we7u * Davis/: .cvsignore, src/.cvsignore: Adding .cvsignore files for the Davis directories to reduce the amount of "noise" that cvs status returns. 2006-01-26 07:42 we7u * LaCrosse/: .cvsignore, src/.cvsignore: Adding .cvsignore files for these two new directories so that cvs status doesn't return too many unneeded lines. 2006-01-26 07:38 n0vh * LaCrosse/src/open2300db2APRS.c: Fixed an issue with SIGPWR on non-Linux systems 2006-01-26 07:38 n0vh * LaCrosse/configure.ac: Minor updates to compile on non-linux systems 2006-01-25 15:11 n0vh * LaCrosse/README: Minor correction to directory in BUILD section 2006-01-25 14:46 n0vh * LaCrosse/README: Changed to make it more relavent to open2300db2APRS 2006-01-25 12:34 n0vh * LaCrosse/src/open2300db2APRS.c.bak: Not needed. 2006-01-25 12:26 we7u * LaCrosse/src/open2300db2APRS.c: Fixing a warning given by gcc-4. clen must be a socklen_t instead of an int. 2006-01-25 11:52 n0vh * LaCrosse/src/: Makefile, Makefile.in, open2300db2APRS, open2300db2APRS.o: Removed files that should be in CVS 2006-01-25 11:50 n0vh * LaCrosse/Makefile.am: Put back this needed file 2006-01-25 11:49 n0vh * LaCrosse/: Makefile, Makefile.am, Makefile.in, aclocal.m4, config.h, config.h.in, config.log, config.status, configure, stamp-h1: Removed files that should be there 2006-01-25 11:36 n0vh * LaCrosse/: AUTHORS, COPYING, ChangeLog, INSTALL, Makefile, Makefile.am, Makefile.in, NEWS, README, aclocal.m4, bootstrap.sh, config.h, config.h.in, config.log, config.status, configure, configure.ac, stamp-h1, src/Makefile, src/Makefile.am, src/Makefile.in, src/defs.h, src/open2300db2APRS, src/open2300db2APRS.c, src/open2300db2APRS.c.bak, src/open2300db2APRS.o: Support for LaCrosse WX-23xx weather station support 2006-01-25 11:33 n0vh * config/: language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Update for future LaCrosse 23xx weather station support. 2006-01-25 11:32 n0vh * config/language-Dutch.sys: Updated with future LaCrosse 23xx stuff. 2006-01-25 08:46 chicoreus * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added missing "MAPFONT008|Border Labels||" to support user selectable font for drawing labels on the UTM tickmarks on the labled border. 2006-01-23 21:46 we7u * src/: maps.c, maps.h: Fixing up some function prototypes to get rid of some compiler warnings. 2006-01-23 15:47 chicoreus * config/language-English.sys, src/db.c, src/main.c, src/maps.c, src/xa_config.c, src/xastir.h: Drawing fonts with an outline on the border results in text that is very difficult to read on a printout. Added a user selectable font for drawing labels on the UTM tickmarks on the labled border. 2006-01-23 12:41 we7u * src/map_tif.c: Getting rid of dependencies on cpl_csv.h, which contains a private (not public) interface. 2006-01-23 12:02 we7u * src/: main.c, main.h: Testing for old/new kernel based on number of signals available. We then use this to decide whether to set "OLD_PTHREADS", which enables or disables the SIGUSR1 handler in the code. Old kernels only has 32 signals, therefore Linux Pthreads used SIGUSR1 and SIGUSR2 in their implementation. We use SIGUSR1 for our Snapshot-on-demand function, therefore we must disable this code if we're running older Pthreads on Linux. 2006-01-23 12:00 we7u * configure.ac, src/util.c: Testing for deprecated/new pthread functions, modifying code to correspond based on what's found. 2006-01-20 13:15 we7u * src/x_spider.c: Another small tweak for Linux Standard Base 3.0 compliance. 2006-01-20 09:58 we7u * README: Tweaked the SuSE 10 notes regarding a bootstrap.sh warning. 2006-01-20 08:52 we7u * README, bootstrap.sh: Formatting changes to bootstrap.sh. Added a section to README which details getting rid of an SuSE-10 warning when running bootstrap.sh. 2006-01-19 12:43 we7u * README: Adding a note about SuSE 10.0 and problems with AX.25 kernel mode. 2006-01-19 12:24 we7u * bootstrap.sh: Fixing a problem in Automake 1.9 (on SuSE 10 at least) where the mkinstalldir script doesn't get copied over by Automake. We have to copy it over ourselves after we invoke Automake. 2006-01-19 09:20 we7u * REGRESSION_TESTS: Updated the format a bit. 2006-01-19 09:17 we7u * src/db.c: A fix for another killer packet. This one had to do with a while loop overrunning an ack_string variable. Changed to xastir_snprintf() functions there and it solved the immediate problem. 2006-01-18 14:40 we7u * src/map_tif.c: Commenting out an include because it causes an error on Cygwin. Of course it causes a warning under gcc-4.0 on Linux when it's commented out... 2006-01-18 12:13 we7u * REGRESSION_TESTS: Updating the tests for LSB and to make them more convenient to run. 2006-01-18 09:10 we7u * FAQ: Adding some VNC configuration info. 2006-01-18 08:50 we7u * INSTALL: Updating/re-ordering the list of configure options. 2006-01-18 08:49 we7u * src/map_tif.c: Getting rid of some gcc-4.0 compiler warnings. 2006-01-18 08:49 we7u * Davis/src/db2APRS.c: Getting rid of a gcc-4.0 compiler warning about signedness. 2006-01-18 08:48 we7u * Davis/bootstrap.sh: Making the script parallel the main Xastir bootstrap script. 2006-01-18 07:31 we7u * src/interface_gui.c: Mods to comply with maximum baud rates allowed under LSB. 2006-01-18 07:11 we7u * acinclude.m4, configure.ac, src/util.c: Initial tweaks to help get Xastir compiled under Linux Standard Base 3.0 (LSB 3.0). Have more work to do to get there, but this is a good start. 2006-01-18 07:00 we7u * src/: main.c, map_cache.c: A fix for the X11 fault caused when the DB Library header/library versions don't match. The code should now just disable map caching and keep right on going. 2006-01-18 06:48 we7u * src/x_spider.c: Changing one declaration to get rid of one gcc4.0 warning. 2006-01-17 13:06 we7u * src/alert.c, src/awk.c, src/bulletin_gui.c, src/color.c, src/datum.c, src/db.c, src/dbfawk.c, src/draw_symbols.c, src/fcc_data.c, src/festival.c, src/geo-client.c, src/geo-find.c, src/geocoder_gui.c, src/gps.c, src/hashtable.c, src/hashtable_itr.c, src/hostname.c, src/igate.c, src/interface.c, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/lang.c, src/list_gui.c, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/map_cache.c, src/Makefile.am, src/map_WMS.c, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/messages.c, src/messages_gui.c, src/objects.c, src/popup_gui.c, src/rac_data.c, src/rotated.c, src/shp_hash.c, src/snprintf.c, src/sound.c, src/testawk.c, src/track_gui.c, src/util.c, src/view_message_gui.c, src/wx.c, src/wx_gui.c, src/x_spider.c, src/xa_config.c, src/xastir_udp_client.c, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Makefile.am, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-gnis, scripts/get_shapelib.sh, scripts/inf2geo.pl, scripts/ozi2geo.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh: Updating copyright info. 2006-01-17 13:03 we7u * symbols/Makefile.am, symbols/symbols.dat, config/24kgrid.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, config/Makefile.am, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, callpass/Makefile.am, callpass/callpass.c, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, src/alert.h, src/awk.h, src/bulletin_gui.h, src/color.h, src/database.h, src/datum.h, src/dbfawk.h, src/draw_symbols.h, src/fcc_data.h, src/festival.h, src/geo.h, src/gps.h, src/hashtable.h, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.h, src/igate.h, src/interface.h, src/io.h, src/lang.h, src/leak_detection.h, src/list_gui.h, src/main.h, src/map_cache.h, src/maps.h, src/messages.h, src/objects.h, src/popup.h, src/rac_data.h, src/rotated.h, src/shp_hash.h, src/snprintf.h, src/symbols.h, src/track_gui.h, src/util.h, src/wx.h, src/x_spider.h, src/xa_config.h, src/xastir.h: Updating copyright info. 2006-01-17 12:10 we7u * scripts/BUILDRPMS: Correcting bugs that crept in. 2006-01-17 11:58 we7u * scripts/BUILDRPMS: Updating script for latest SuSE RPM build. 2006-01-17 11:47 we7u * INSTALL, README: Updating notes to call out latest packages. Adding SuSE 10.0 instructions to README. 2006-01-16 10:21 we7u * scripts/BUILDRPMS: Updating script for latest release numbers. 2006-01-16 09:12 we7u * configure.ac: Bumping version to 1.8.1 for new mods. 2006-01-16 09:04 we7u * configure.ac, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.8.0 release. 2006-01-13 07:34 we7u * bootstrap.sh: Changing the prompts a bit. We now see a countdown to completion. 2006-01-12 16:06 tvrusso * README.MAPS: Fix error in command line for sorting the EN.dat file from FCC. 2006-01-12 08:58 we7u * config/language-German.sys: Another update from Rolf. 2006-01-12 07:25 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2006-01-11 12:28 we7u * src/db.c: Processing/decoding the altitude extension on more packet types. Altitude wasn't being decoded for some weather and grid packets. It is now. 2006-01-11 12:27 we7u * help/help-English.dat: Adding some notes about lack of altitude in compressed-mode posits. 2006-01-11 07:43 we7u * src/db.c: Fixing a decoding bug w.r.t. lower-case N/S/E/W in a couple of types of packets. 2006-01-10 09:03 francais1 * config/language-French.sys: More updates from Jacques Chion, with some tweaks and translation of GPSS* strings. 2006-01-09 14:10 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM. Thanks! 2006-01-06 18:45 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing a bug on the GPS Status dialog. It wasn't reporting the correct status for WAAS. Corrected that and added more possibilities for status. 2006-01-03 13:59 chicoreus * src/db.c: Minor bugfix: Range Scale and Scale bar were drawn displaced when border was on and grid was off (even though border is only shown when grid is on). 2006-01-02 13:34 we7u * src/db.c: Fixing segfault that occurs in extract_multipoints() when data == NULL. 2005-12-31 18:38 chicoreus * help/help-English.dat: Added Documentation of Map/Enable Map Border. 2005-12-31 07:13 chicoreus * src/maps.c: Bug fixes in the labeling of utm zones, northing lines, and easting lines when the grid is labeled. When grid is finely spaced on the screen, only alternate lines are labeled. Grid and zones are labeled correctly and reasonably most of the time when more than one lettered zone row appears on the screen. Still has some problems, but works for most places. 2005-12-29 13:11 we7u * INSTALL: Added instructions for updating /etc/ld.so.conf.d/ directory for those systems that use this alternate method. Courtesy of Dale, KB9JJA. Thanks! 2005-12-20 18:01 chicoreus * src/: main.c, objects.c: Performance tuning: Moved call to redraw_symbols out of CAD_vertice_allocate to prevent repeated redrawing on each vertex of each cad object loaded from a file at startup. 2005-12-20 10:24 chicoreus * src/maps.c: In trying to work out what draw_grid is doing, added some documentation to the utm_grid structures. Added a test inside draw_grid so that the utm grid labeling code is only running for utm_grid.zone elements that contain rows and columns. 2005-12-19 10:18 chicoreus * src/maps.c: Minor bugfix and additional comments on code for labeling UTM grid. Changed format to include leading zeroes for easting and northing. 2005-12-19 09:40 chicoreus * README.MAPS: Added brief discussion of gdalinfo and gdal_translate for handling geotiff files that aren't in byte form or contain multiple bands. 2005-12-16 14:13 chicoreus * src/maps.c: Added the ability to draw a 1 pixel outline in a different color to rotated text in draw_rotated_label_text_common() and some of its wrappers. 2005-12-16 14:09 chicoreus * src/xa_config.c: Making draw_labeled_grid_border persistent between restarts. 2005-12-15 14:10 chicoreus * src/: db.c, main.c, main.h, maps.c: First cut at adding a labeled border to the map shown on the screen for printing. This can be used, for example, to print maps with a labeled UTM grid for a SAR task team showing the area they are to search. Metadata about the map is displayed in the top border, coordinates of grid lines are displayed on the bottom and right borders (to make it easier for people to correctly read and report UTM coordinates in the form zone easting northing. The labeled border is displayed when both the grid and the border are enabled. There are still problems and missing features. The rotated font on the right border is not the pretty font used on the rest of the border. The border and grid labels are only drawn for a UTM grid, not for a Lat/Lon grid. Zone designators are not properly displayed when more than one zone is visible on the screen. When grid lines are closely spaced, the grid labels overlap on the screen. 2005-12-15 10:31 we7u * README.win32: Fixing a typo. 2005-12-15 10:24 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: First rough cut at adding a labeled border to a map to allow the printing of arbitrary maps with a labeled grid (that can, for example, be printed and given to SAR task teams). If the map grid is enabled, and the border is enabled, a white border is drawn as part of the grid and labels for each grid line are added in this border. Metadata describing the map are also added in the border. This is a first rough cut with several problems. It is only implemented for a UTM grid, not for a Lat/Long grid. The rotated numbers do not use the same clean font as the non-rotated numbers. The labels in the border are not clearly distinguishable when the grid is tightly spaced on the screen. The zone labels do not work properly when more than one zone is on the screen. The choice of labeling the bottom border and the right border with the UTM grid line easting and northings is deliberate to help people to correctly read the map and report UTM coordinates in the form: zone easting northing. 2005-12-13 14:11 we7u * config/Makefile.am: Correcting the name of the dbfawk file that we want automatically removed. I forgot the underline first time around. 2005-12-13 07:54 we7u * src/objects.c: Tweaking a debug statement so we don't get a segfault if we hit a null pointer. 2005-12-12 18:50 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added localization strings for map display of CAD object metadata. Added update of CAD objects on toggle of display of metadata. 2005-12-12 14:56 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/main.c, src/main.h, src/objects.c, src/objects.h: Adding more user interface elements to CAD Object display 1) Clarifying user side handling of raw_probability as a percent 2) Allow user to set CAD boundary line type 3) Allow user to toggle on and off display of CAD Polygons, Label, Area, and probability. 2005-12-11 10:20 we7u * src/main.c: Fixing the Station->Configure submenu. Wasn't working on Lesstif but was fine on OpenMotif. Should work on both now. 2005-12-07 18:55 chicoreus * help/help-English.dat: Edited CAD object text to reflect the movement of the CAD object functions from the mouse menu to the toolbar and the View and Map menus. Added some text for Probability Circle Objects. 2005-12-07 17:04 we7u * src/interface.c: Only twiddle DTR on HSP ports if global transmit is enabled. 2005-12-07 17:02 we7u * src/objects.c: Very minor formatting change. No code changes. 2005-12-07 12:40 we7u * config/Makefile.am: Automating the deletion of the nwsfzddmmyy.dbfawk file from the /usr/local/share/xastir/config directory during install. We don't use it anymore and it causes problems if present. 2005-12-07 10:38 we7u * src/interface.c: Patch by Paul Morris, modified slightly by me, to make objects work for the case when global transmits have been disabled. 2005-12-07 09:32 tvrusso * config/: Makefile.am, nwsfz_ddmmyy.dbfawk: Remove unnecessary (and problematic) nwsfz_ddmmyy.dbfawk file. 2005-12-07 08:09 we7u * src/map_gdal.c: Moving some struct typedef's and nested functions out of the main function so that it will compile with latest MacOSX GCC compiler. 2005-12-06 22:41 we7u * src/map_shp.c: Made code more correct by changing alert->title to modified_title in a couple of places. modified_title is a copy of alert->title so the real-world effects of this change are little to none. Tweaked some comments in the area as well. 2005-12-06 19:04 tvrusso * config/nwsmzddmmyy.dbfawk: Fix incorrect key generation for mzddmmyy.shp file. The key produced by the dbfawk rule must match the key that comes from the NWS alert. These will generally be "XX_Zyyy". The "ID" field of the mzddmmyy.dbf record is of form "XXZyyy", and prior to this commit it was used directly as the key, thereby never matching any alerts. This fix inserts the _ character after the first to characters of the ID field to produce a usable key. 2005-12-06 13:35 we7u * src/map_shp.c: Added more debugging text for dbfawk and wx alerts. 2005-12-06 12:53 we7u * src/maps.c: Correcting some comments. 2005-12-06 12:50 we7u * src/maps.c: Adding a bit more text to one wx alert debug message. 2005-12-06 12:26 we7u * src/interface.c: Moving a nested function so that it is no longer nested. This is necessary in order to compile on MacOSX with their latest GCC compiler. 2005-12-06 11:34 we7u * src/util.c: Changing a nested function to non-nested in order to enable compiling with the latest MacOSX compiler. 2005-12-04 19:05 we7u * src/: main.c, xastir.h, festival.c: Adding a "Test" button to the Configure->Speech dialog for testing the speech subsystem and for adjusting the audio levels (by an external program). 2005-12-01 11:32 we7u * update-xastir: Changing the "make" step so that it doesn't run as root. 2005-12-01 09:22 we7u * src/map_gdal.c: Commenting out and include that we're currently not using. 2005-11-29 22:36 we7u * src/map_pdb.c: Implementing the same sorts of map interruption capability for PocketAPRS maps that we just did for the other types of maps. 2005-11-28 19:16 we7u * src/: map_WMS.c, map_gdal.c, map_geo.c, map_shp.c, map_tif.c, map_tiger.c: Adding more map interrupt code, to make it easier/faster to interrupt map drawing by panning or zooming. 2005-11-28 12:51 we7u * src/map_shp.c: Adding capability to interrupt map drawing and start over in the inner loops of the GNIS and DOS map drawing functions. This makes panning or zooming cause an interrupt much quicker while drawing maps, allowing Xastir to restart the redraw process sooner. 2005-11-28 12:43 we7u * src/: map_dos.c, map_gnis.c: Adding capability to interrupt map drawing and start over in the inner loops of the GNIS and DOS map drawing functions. This makes panning or zooming cause an interrupt much quicker while drawing maps, allowing Xastir to restart the redraw process sooner. 2005-11-23 14:37 we7u * scripts/do_xastir_release_stable: Adding another admin script so that it won't get lost. 2005-11-23 14:32 we7u * scripts/do_xastir_release_dev: Adding another couple of admin scripts so they won't ever get lost. 2005-11-23 14:28 we7u * scripts/STABLE: Adding another admin script to the repository so that it won't get lost. 2005-11-23 14:27 we7u * scripts/BUILDRPMS: Adding the RPM Build script so that it will be available as an example to others. 2005-11-23 11:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/map_cache.c: Disabling map caching if dblib header/library mismatch, to help prevent segfaults. Also doing a popup now when this condition is found as Xastir starts up. 2005-11-23 11:33 we7u * NWS-TEST.log: Changed some comments. 2005-11-23 11:33 we7u * README.MAPS: Added a blurb about how to test weather alert functionality. 2005-11-22 14:31 we7u * NWS-TEST.log: Added some more notes. 2005-11-22 12:49 we7u * NWS-TEST.log: Moved one OR alert over to the coast and made it blue, to stand out more against the other alerts. 2005-11-22 12:35 we7u * NWS-TEST.log: Moving all of the tests to the Northwest region so we don't have to look all over the country for them. 2005-11-22 11:57 we7u * NWS-TEST.log: Changing the colors for adjacent alerts, making it easier to differentiate between them. 2005-11-22 10:41 we7u * NWS-TEST.log: Adding a file which can be used to test out the weather alert functionality. 2005-11-18 16:36 we7u * src/map_shp.c: Fix for RED_FLAG weather alerts. 2005-11-18 12:00 we7u * src/main.c: Making more menus detachable. Splitting the toolbar buttons vertically by a few more pixels to make it look better on Cygwin. 2005-11-18 11:59 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Getting rid of a couple of unused labels, reclaiming one for the new "Draw" toolbar togglebutton. 2005-11-18 07:48 we7u * src/wx_gui.c: Changed tab to spaces. 2005-11-17 09:04 we7u * src/main.c: Adding the cad polygons list to the map->CAD Objects submenu. It still has a link in the View menu as well. 2005-11-17 08:56 we7u * src/main.c: Moving the remaining CAD Object stuff to the Map menu (from the mouse menu) 2005-11-17 07:41 we7u * src/objects.c: Changing colors of CAD Polygon labels and probability. Extending string so that it display 0.00% through 100.00% and displays the '%' sign. 2005-11-17 06:57 we7u * .cvsignore: Added make.log and xastir-min.spec 2005-11-16 22:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/objects.c, src/objects.h: Moving Draw CAD functions to main menu and toolbar. 2005-11-16 18:43 we7u * src/objects.c: Adding a cancel button to the CAD Objects detailed info dialog. Fixing the area size as listed in the same dialog. 2005-11-16 13:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing from "Erase All" to "Erase" for menu entry. 2005-11-16 13:50 we7u * src/main.c: Changing one comment. 2005-11-16 13:00 we7u * src/objects.c: Changing "Cancel" to "Close" on CAD Object list dialog. 2005-11-16 12:52 we7u * src/objects.c: Fixing CAD area labels and comments so that they get retrieved properly from file. 2005-11-16 12:19 we7u * src/main.c: Moving some items from the Map and Station menu into Configure submenus. 2005-11-16 11:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/objects.c, src/objects.h: More from Paul Morris: Allows edits of the data associated with CAD objects and moving more of the Close CAD object code into functions. It also adds localization to the delete CAD object dialog. 2005-11-16 10:08 we7u * xastir-min.spec.in, Makefile.am, configure.ac: Adding a new spec.in file which skips all of the optional libraries except for ImageMagick. 2005-11-10 14:38 gstueve * src/map_shp.c: Add test for debugging alert match to reduce noise on display. 2005-11-10 08:57 we7u * scripts/fcc-get: Yet another try to fix the Id string. 2005-11-10 08:37 we7u * scripts/fcc-get: Trying to fix Id string again. 2005-11-10 08:36 we7u * scripts/fcc-get: Fixing the RCS Id: string so that it gets populated by CVS. 2005-11-10 07:51 gstueve * src/objects.c: Use the time that was already provided. Don't bother system for it again. 2005-11-10 07:28 gstueve * src/: alert.c, alert.h, bulletin_gui.c, bulletin_gui.h, database.h, db.c, main.c, messages.c, messages.h, popup.h, popup_gui.c: Use the time that we already have from UpdateTime and not keep asking the system for it over and over again. 2005-11-10 06:59 gstueve * scripts/fcc-get: Remove the extra CR where ever possible, real OS has no need for such. 2005-11-09 06:03 gstueve * src/interface.c: Adjust error messages to describe problem in current function. 2005-11-08 21:57 gstueve * config/Makefile.am: Add old zone file dbf into Makefile list. 2005-11-08 21:44 gstueve * config/: Makefile.am, nwsmzoddmmyy.dbfawk: Add back in the old mz dbf definition. 2005-11-08 17:40 gstueve * src/maps.c: Add cancelled Alerts to list of mapped but don't draw on display. 2005-11-08 16:07 gstueve * config/nwszoddmmyy.dbfawk: Add old Zone file match for older dbf structure. 2005-11-08 11:15 gstueve * src/main.c: We already have a good idea of what time it is inside UpdateTime. It is NOT necessary to always be asking the system what time it is within one function and its support routines. This is not a '25 or 6 to 4' need. 2005-11-08 06:52 gstueve * src/: database.h, db.c, main.c: Make packet display logic much more efficient. Do it all in fewest moves. 2005-11-08 06:35 gstueve * src/map_gnis.c: Visual optimization. Make things easier to read. 2005-11-07 14:33 we7u * src/db.c: Changing comments about KISS variants. 2005-11-07 12:33 we7u * src/db.c: Changed one comment. 2005-11-07 09:04 we7u * src/main.c: Adding a NULL parameter to close out the parameter list for two XtVaGetValues() calls. 2005-11-07 06:14 gstueve * src/fcc_data.c: Optimize the use of substr so the function is MUCH more efficient. 2005-11-07 06:12 gstueve * config/: nwsmzddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: The newer shapefiles no longer have the additional fields, so system was not matching file structure. Make it match better. 2005-11-06 16:14 we7u * src/util.c: Fixing the remove_trailing_dash_zero() routine. It was changing "-10" into "-1" which is quite wrong. 2005-11-03 12:15 we7u * src/: db.c, interface.c: Making sure we don't transmit if the global disable or the individual interface disables are activated. 2005-11-02 11:01 we7u * src/db.c: Adding some notes about KISS and CRC's. 2005-11-02 07:40 we7u * src/xastir_udp_client.c: Changed length from int to socklen_t to get rid of warning messages for some compilers. 2005-11-01 13:32 gstueve * src/util.c: Go back to whining about dual-band TNC separator. 2005-11-01 11:21 gstueve * src/alert.c: Add debugging detail for unparsed alerts. 2005-11-01 11:18 gstueve * src/util.c: First cut to stop whining on dual-band TNC with WIDEn-m paradigm. 2005-10-26 21:58 we7u * src/interface.c: Truncating transmitted posits at the spec-specified length. Long comments can't make us transmit out-of-spec packets anymore. 2005-10-26 21:52 we7u * src/sound.c: Added a missing include that causes a problem on Solaris if missing. 2005-10-26 12:16 we7u * src/main.c: Re-enabling the messages to STDERR when SIGHUP is sent to the main process and a restart is occurring. Add comment about disabling SIGHUP handler in child processes. 2005-10-26 12:14 we7u * src/interface.c: Tweaks to assure that the global disables on the Interface menu have the correct effect. 2005-10-26 12:11 we7u * src/: hostname.c, macspeech.c, sound.c, x_spider.c: Regressing to default SIGHUP handler in child processes instead of our special restart() signal handler. 2005-10-26 12:07 we7u * REGRESSION_TESTS: Added date stamps and more comments. 2005-10-26 08:46 we7u * src/main.c: Changing the messages that appear as Xastir shuts down, putting them back under debug_level control in restart(). restart() gets called multiple times due to sending SIGHUP to the TCP/UDP servers during shutdown, and the messages were appearing multiple times if those servers were running. 2005-10-25 18:01 we7u * src/util.c: Fixing the alert expiration problem. May need to be checked when we switch out of daylight savings time again. 2005-10-25 13:08 we7u * src/main.c: Adding an include so that we can use the ComboBox widget. 2005-10-25 13:04 we7u * src/main.c: Limiting the selection box for preconfigured object filenames on the Configure->Defaults dialog to three items. 2005-10-25 12:53 we7u * src/main.c: Minor cleanups of the predefined object code: Added a few free's for XmStrings, allocated memory before an XtGetValues call. 2005-10-25 12:25 we7u * src/: util.c, util.h: Making rpl_malloc() compile in all cases and put a prototype for it in util.h to get rid of more compiler warnings. rpl_malloc() only gets used if AC_FUNC_MALLOC detetcs a version of malloc that doesn't return a valid pointer if you try to malloc zero bytes. These changes make it compile ok on FC4. 2005-10-25 08:18 we7u * src/util.c: Added some comments. 2005-10-24 20:37 we7u * REGRESSION_TESTS: Added some notes about future directions we could go to make the tests a bit more complete. 2005-10-24 20:36 we7u * FAQ: Tweaked the "restart Xastir" paragraph to keep it up-to-date. 2005-10-24 12:29 we7u * src/: main.c, main.h: Patch to allow SIGHUP to cause Xastir to restart properly. This patch also appears to carry along the original command-line parameters and environment to the new task. The xastir.pid file is correct in all cases, and in fact the main process ID doesn't change between restarts. 2005-10-24 12:27 we7u * src/macspeech.c: Spawning a separate process for sending the text to the Mac OSX speech subsystem. We also incorporate a limit of 10 processes that can be waiting for the subsystem to be freed up. If 10 processes are waiting and another speech request is made, the latter is dropped. No provision is made for the ORDER that the (up to) ten processes get access to the speech subsystem either so the order will most likely get mixed up if you're trying to send speech strings out too fast. 2005-10-24 08:52 we7u * help/help-English.dat, src/main.c, src/objects.c, src/objects.h: Another SAR patch from Paul Morris. Here's what he says: This one implements a dialog for selecting CAD objects to delete from the Erase All CAD polygon menu item along with implementing delete by name in CAD_object_delete(). It also adds some help text on prepared objects and CAD objects and changes the XmStringCreateLocalized() calls to XmStringCreateLtoR(). 2005-10-21 21:46 we7u * src/main.c: Restarting on SIGHUP a bit better. It now sends argv[] at least the first time around. Need to figure out why the 2nd time doesn't work at all. Perhaps signal handlers are getting messed up on reboot? 2005-10-21 13:28 we7u * src/objects.c: Another tweak by Paul Morris for proper handling of CAD objects. 2005-10-21 12:33 we7u * FAQ: Reworded text for SIGHUP. 2005-10-21 12:27 we7u * FAQ: Adding the SIGHUP stuff to the FAQ. 2005-10-21 12:18 we7u * README.Getting-Started: Added some more signals to the External Stimuli section. 2005-10-21 12:11 we7u * src/main.c: Adding support for SIGHUP. Xastir will save/exit/restart if a SIGHUP is received. Also enabled a #define near the top of main.c that enables the xastir.pid processing. If someone attempts to start Xastir and there's a process running with that PID, Xastir will exit. The SIGHUP support works, but the command-line parameters aren't carried through as the normal processing for them devours them out of the argv[] array. We need to save that array away or use a non-destructive method of processing the parameters. 2005-10-21 11:02 we7u * src/objects.c: Small tweak so that the code looks in the /usr/local/share/xastir/config directory for the predefined objects for now. Later we'll add the capability of overriding the system files with local user files. 2005-10-21 10:41 we7u * src/interface_gui.c: Reordering the management & positioning statements so that it doesn't appear on the screen until it gets positioned. 2005-10-21 07:27 tvrusso * src/: main.c, objects.c: Move variable declarations to tops of blocks to satisfy old-fashioned compilers that hate the modern practice of declaring variables just before their use. 2005-10-20 15:47 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing pre-defined objects labels to more descriptive words. 2005-10-20 15:02 we7u * src/main.c: Getting rid of Button1 assignment for CAD objects. This prevents us from zooming/panning/measuring while creating a CAD object. 2005-10-20 14:52 we7u * config/Makefile.am: Adding predefined files to Makefile so they'll get installed. 2005-10-20 14:52 we7u * config/: predefined_EVENT.sys, predefined_SAR.sys: Example pre-defined SAR/Event object files by Paul Morris. 2005-10-20 14:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/database.h, src/main.c, src/main.h, src/objects.c, src/objects.h, src/xa_config.c: Patch by Paul Morris, AA3SD, to tweak CAD objects functionality a bit and add pre-defined SAR/Event objects from files. 2005-10-20 13:34 we7u * src/color.c: Reformatting. No real code changes. 2005-10-20 13:12 gstueve * src/: alert.c, alert.h, wx_gui.c: Reintroduce SKYWARN addendum to Wx Messages & sort Wx Alert list. Only sort list if window is activated. 2005-10-20 13:08 gstueve * src/: map_shp.c, maps.c: Move the on_screen decision to a position where it really works. 2005-10-20 10:58 we7u * README.MAPS: Changing one sentence to make things more clear. 2005-10-20 10:57 we7u * README.MAPS: Removing an unnecessary statement. 2005-10-20 10:53 we7u * README.MAPS: Was missing a pipe symbol in the new sort command. Also use the same command for all operating systems with this tweak. 2005-10-20 10:21 we7u * README.MAPS: Fix submitted by A. Carver for FCC database sorting for Cygwin. 2005-10-20 09:35 we7u * src/interface_gui.c: Changing default path to WIDE2-2 instead of WIDE for new interfaces. 2005-10-20 05:41 gstueve * src/maps.c: Activate debugging messages from commented fprintf messages. 2005-10-20 05:35 gstueve * src/util.c: Clamp limits of map to nearest edge. Not clipping/clamping & report error. 2005-10-19 18:29 we7u * src/: map_WMS.c, map_geo.c, map_tif.c, map_tiger.c: Commenting out the XFreeColors() calls for now. Cygwin seems to be much more sensitive to these calls than Linux. 2005-10-19 13:24 we7u * src/interface.c: Disabling sending of my own posits to x_spider if transmit_disable is non-zero. 2005-10-19 13:19 we7u * src/interface.c: Cease sending packets to x_spider if loopback_only is in effect. 2005-10-19 13:19 we7u * src/objects.c: Added some comments. 2005-10-19 12:54 we7u * src/objects.c: Getting rid of "Transmitting objects/items" statusline message if transmit of those types of packets is disabled globally. 2005-10-19 12:21 we7u * src/: map_WMS.c, map_geo.c, map_tif.c, map_tiger.c: Adding XFreeColors() calls just before each XAllocColor() call. This is to keep the counters in sync that count how many times each color is allocated, hopefully preventing the can't allocate color warning messages. 2005-10-19 12:20 we7u * src/color.c: Adding a comment. No code changes. 2005-10-17 14:35 we7u * configure.ac: Bumping version number to 1.7.1 for further development. 2005-10-17 14:12 we7u * configure.ac: Bumping the release number to 1.7.0. 2005-10-17 13:46 francais1 * config/language-French.sys: Merci a Jacques Chion, F6CWO 2005-10-17 13:41 we7u * config/: language-Dutch.sys, language-English.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Fixing some typos: Missing pipe symbols at the end of strings. French language file will be fixed shortly too, along with a few more translations. Thanks to Olivier for catching these. 2005-10-17 12:16 we7u * README, help/help-English.dat: Added notes about Bob Bruninga's list of generic callsigns that should be gated to RF. 2005-10-17 11:53 we7u * help/help-English.dat: Added a What's New section for up-and-coming 1.7.0 release. Added notes regarding gating specific stations to RF and which generic callsigns that Bob Bruninga recommends doing that with. 2005-10-17 11:51 we7u * README.win32: Reformatting the list of languages available. 2005-10-17 11:50 we7u * README.Getting-Started: Changing the revision number in an example. Updating the example Xastir help text. 2005-10-17 11:49 we7u * README.Contributing: Changing a revision number in an example. 2005-10-17 11:49 we7u * README: Adding a note about a few calls that Bob Bruninga recommends always gating to RF. 2005-10-17 11:47 we7u * INSTALL: Tweaking formatting of -l language notes. 2005-10-16 10:16 we7u * config/language-German.sys: An update to the German language file by Rolf Bleher, DK7IN. Thanks! 2005-10-15 18:51 we7u * config/language-Dutch.sys: Updates by Han Sytsma. Thanks! 2005-10-15 18:50 we7u * config/language-English.sys: Fixing a typo. 2005-10-15 10:30 we7u * src/map_tif.c: Making sure the projects.h include isn't needed unless libgdal is compiled in as well. Got rid of UV define and changed invocation to "projUV" instead. 2005-10-15 09:42 we7u * src/map_tif.c: Fixing a problem caused by the new code which fixes the gdal/geotiff bug. This fix cuases the original functions to be called if gdal isn't installed. 2005-10-14 11:06 we7u * src/map_tif.c: Received permission from Frank Warmerdam to use some of his code inside Xastir, relicensing it under GPL. We use this new right to include one function in map_tif.c which allows us to keep topo maps support even when libgdal is compiled in. 2005-10-14 08:11 we7u * README.win32: Added a note about running configure from an xterm so that "gv" support will be compiled in. If run from a non-X11 window, "gv" configure test fails. 2005-10-13 13:51 francais1 * config/language-French.sys: Some more strings translated, but not all... 2005-10-13 08:39 gstueve * src/main.c: Put the full title back on the window, so we can know what machine is running the app. 2005-10-12 17:09 we7u * src/messages.c: Added code that will switch back to RF if no TX-enabled INET interfaces are up. 2005-10-12 13:09 we7u * src/messages.c: New message routing which should take care of a bug-list item: Ceasing to transmit when messaging with internet station and internet interfaces go down. Problem remaining with this code: We transmit out RF interfaces even if QSO'ing with station over internet interface. 2005-10-12 11:33 we7u * src/: locate_gui.c, main.c, messages_gui.c, track_gui.c, util.c, util.h: Fixing all of the callsign entry fields so that "-0" is truncated from the end of the string when used. 2005-10-11 16:52 we7u * src/main.c: Tweaks to convert callsign-0 to callsign for configure station dialog. 2005-10-11 10:12 we7u * src/db.c: Added a bit of debugging. No effect for normal operation. 2005-10-11 08:16 we7u * src/db.c: Slightly better igating of messages. This versions saves the message+acks away and then uses that exact string again when igating it, instead of putting together the bits and pieces at that point like the previous code. 2005-10-10 22:07 we7u * src/db.c: Another tweak to get reply-ack's propagated through an Xastir igate to RF. This one is tested and works. 2005-10-10 18:29 we7u * src/db.c: Comment changes. Also changed the fprintf() for REJ packets to only dump text to STDERR if the REJ was sent to my_callsign. 2005-10-10 12:11 we7u * src/db.c: Changed one comment. 2005-10-10 11:52 we7u * src/db.c: Added comments. fprintf() to stderr when we receive a REJ packet. We can receive those when a Kenwood radio's message buffer is full. 2005-10-10 11:48 we7u * src/messages.c: Minor tweaks w.r.t. REPLY-ACK protocol. Making sure we strip off the unneeded portion before we check the ACK. 2005-10-10 09:31 we7u * src/db.c: Fixing igating of messages to RF for messages with REPLY-ACK protocol at the end. We were originally sending our processed ACK at the end which knocked off the free-ack portion. Now we send the full five-character unprocessed REPLY-ACK. 2005-10-10 09:29 we7u * src/igate.c: Adding some comments. 2005-10-10 08:23 we7u * src/main.c: Fixing a couple of compiler problems via casting. Problems were not seen with SuSE compiler but were seen on other systems. 2005-10-07 18:16 we7u * src/objects.c: Tweaks to avoid other object/item/station names when creating SAR objects. Xastir will now add a number to the end of the typical name (starting at "2") in order to create a unique name. This makes for extremely fast placement of important mission objects without worrying about old mission objects or conflicting with other people's current missions. 2005-10-07 18:13 we7u * src/main.c: Added some comments. 2005-10-07 18:10 we7u * src/db.c: Added some comments. 2005-10-07 18:07 we7u * src/track_gui.c: Added a comment. 2005-10-07 18:05 we7u * src/list_gui.c: Added some comments. 2005-10-07 13:16 we7u * src/objects.c: Added some comments. 2005-10-07 12:49 we7u * src/objects.c: Adding fprintf() statements to help work on the SAR objects code. 2005-10-07 12:26 we7u * src/: main.c, xa_config.c, xastir.h: Checking in some work having to do with saving/restoring X/Y offsets for the main window. The code doesn't work yet so it commented out. 2005-10-07 12:25 we7u * src/objects.c: Adding some comments about future coding that needs to be done w.r.t. SAR objects. 2005-10-07 11:16 we7u * src/Makefile.am: Another minor tweak for the icon. 2005-10-07 11:15 we7u * src/Makefile.am: Adding the icon.xbm file into the Makefiles. 2005-10-06 13:50 tvrusso * src/: main.c, objects.c: Move declarations of variables to before first executable lines of code, to satisfy old-fashioned compilers (gcc 2.95, etc.) 2005-10-06 13:45 we7u * src/icon.xbm: Someone pointed out that the RF radiation wasn't symmetrical. Now it is. 2005-10-06 12:46 we7u * src/objects.c: Commenting out a debug statement. 2005-10-06 12:39 we7u * src/: main.c, objects.c, objects.h: Commenting out the wm_hints code. Adding a "Create SAR Objects" entry to the mouse menu. That last was written and contributed by Paul J. Morris, aa3sd. Thanks! 2005-10-06 12:37 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding "Create SAR Objects" right-click mouse menu. 2005-10-06 12:19 we7u * src/icon.xbm: Added radio transmissions emanating from the antenna. 2005-10-05 23:47 we7u * src/: icon.xbm, main.c: Separating out the icon into its own file. 2005-10-05 22:49 we7u * src/main.c: Casting to type "Dimension" is not proper for parameters passed to XtSetArg(). Have changed to variables of that type for parameter passing. Also cleaned up the -geometry code a bit. The windows are now sized properly per the command-line parameters. 2005-10-05 17:25 we7u * src/main.c: A better version of the -geometry code that is starting to work on Cygwin. The size is larger than specified, perhaps because it is based on char sizes instead of pixels? Anyway, this part of the code is starting to work. 2005-10-05 11:37 we7u * src/main.c: Rearranging things. No code changes. 2005-10-05 08:34 we7u * src/main.c: Another attempt at the -geometry stuff. Here we only use size_hints in one case, plus we lock down the minWidth and minHeight of the main widget when we create it (to the size we want it to appear as), but change those parameters before we map the window to the screen. This method was borrowed from the Lincity project where they do similar things. As usual, this stuff works for me on Linux/FVWM2. 2005-10-04 12:12 we7u * src/: main.c, xa_config.c: Another shot at this -geometry stuff. Moved the size_hints stuff after the window is mapped. Added an icon. 2005-10-04 09:11 we7u * src/main.c: Reducing the number of size_hints variables I'm setting. Changing XtPopup() to XMapWindow() for appshell. 2005-10-03 13:13 we7u * src/xa_config.c: Tweaking SCREEN_ZOOM to match new highest-allowed value for zoom level. 2005-10-03 13:11 we7u * src/main.c: Allow a higher zoom level for entire world, for rather small map windows. 2005-10-03 13:05 we7u * src/main.c: Attempting to recenter view when zooming out all the way. Doesn't quite work yet. 2005-10-03 12:56 we7u * src/main.c: Getting rid of the X-dimension checks in check_range() in order to make it easier to play at the +/-180 boundaries. 2005-10-03 12:51 we7u * src/main.c: A slightly better system for controlling left/right edges of map when at left/right edge of world. check_range(). 2005-10-03 11:34 we7u * src/main.c: Fixes for -geometry support and main window save/restore support. 2005-10-03 11:33 we7u * src/xa_config.c: Changing the minimum size that can be restored to for Xastir's main window. 2005-10-02 12:27 we7u * src/main.c: Adding window manager hints back in. 2005-10-01 23:26 we7u * src/: db.c, draw_symbols.c, geocoder_gui.c, interface_gui.c, list_gui.c, locate_gui.c, maps.c, xastir.h, bulletin_gui.c, main.c, messages_gui.c, objects.c, popup_gui.c, track_gui.c, view_message_gui.c, wx_gui.c: Getting rid of the Global.top widget which was unmapped. Making appshell be the top level widget. Added parsing for the -geometry command-line variable via XParseGeometry() so that we can tell when either the height/width or the x/y offsets have been specified. We then set up appshell based on that info or using the config file data if it wasn't specified on the command-line. 2005-10-01 17:46 we7u * src/main.c: Commenting out the 100x100 minimum window size parameters. 2005-09-30 13:16 we7u * src/main.c: Commenting out the code which sets min_width/min_height in the XSizeHints struct. 2005-09-30 11:25 we7u * src/main.c: Commenting out base_width and base_height parameters as they override the min_width/min_height parameters if specified. We only need one set. 2005-09-30 11:02 we7u * src/main.c: Another shot at the XSizeHints stuff (-geometry). Learning a bit more with each iteration. 2005-09-30 08:58 we7u * src/main.c: Of course some of those I commented out previously appear to matter, so here they are, enabled in the code again. 2005-09-30 08:51 we7u * src/main.c: Getting rid of a few unused variables. Commenting out sections in the geometry setting portions that appear to have no effect. 2005-09-30 07:44 tvrusso * DEBUG_LEVELS: Change statement that the highest debug level is 2047 to 4095. There is now a debug level of 2048 (ALOHA calculation and multipoint object debugging). 2005-09-30 07:27 we7u * INSTALL, help/help-English.dat: Updating the docs regarding TCP and UDP server ports. 2005-09-30 07:01 we7u * src/main.c: Changed PSize flag to USSize to indicate that the user had specified the size of the window in that one case. This gives it a higher priority. 2005-09-30 06:46 we7u * help/help-English.dat: Updating the xastir_udp_client description. 2005-09-30 05:26 we7u * src/db.c: Telemetry fix which adds it as status to the station record, submitted by Andrew Rich, vk4tec. Thanks! 2005-09-30 02:50 we7u * src/main.c: Took another look at the XSizeHints struct. Might work better now to provide proper geometry hints to window managers. 2005-09-29 12:19 we7u * src/map_tif.c: Casting to the correct type for X11 calls. 2005-09-29 12:19 we7u * src/: db.c, location.c, main.c, map_WMS.c, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tiger.c, maps.c, objects.c, popup_gui.c: Casting to the correct type in X11 calls. Adding more debug output to create_appshell() for -geometry stuff. 2005-09-29 11:00 we7u * acinclude.m4: Fix by Thorsten Lockert. Fixes a problem on MacOSX where -lgdal can have revision numbers after it. Without this fix the test compile using gdal fails. 2005-09-29 08:42 we7u * src/main.c: Added more debugging output for -geometry. 2005-09-29 07:59 we7u * src/main.c: Moving some variable declarations to the correct spot. Ended up originally putting them after a bit of functional code, but they must be at the start of a block for many compilers. 2005-09-29 07:37 we7u * src/main.c: Changing to 3rd-party packets for packets sent from UDP to the RF ports. 2005-09-28 13:21 we7u * src/main.c: Commenting out some unused variables. 2005-09-28 13:02 we7u * src/main.c: More mods for UDP->RF. This version may be working but it needs testing on a system with real RF interfaces to see if it behaves properly. 2005-09-28 09:24 we7u * src/: main.c, x_spider.c, x_spider.h: Continuing work on support for UDP server port. We're getting closer now to supporting sending of packets to RF. 2005-09-28 09:22 we7u * src/xastir_udp_client.c: Changed the help text. 2005-09-28 09:03 we7u * symbols/symbols.dat: Adding the /F, Farm Equipment, symbol, as a green tractor. Also added hash mark delimiters between each symbol definition. 2005-09-28 07:50 we7u * config/language-German.sys: Updates by Andreas Bier, dl1hrc. Thanks! 2005-09-27 08:16 we7u * src/main.c: Simplifying startup of the application in main(). Changing to XtVaOpenApplication, which supersedes the function call we were using before, and removing some explicit function calls that are handled automatically by both the old and the new function call (unnecessary code). These changes are being made to implement proper support for the "-geometry" command-line flag. 2005-09-25 19:35 we7u * src/: alert.h, database.h, db.c, draw_symbols.c, geocoder_gui.c, interface.c, main.h, maps.h, track_gui.c, util.h, Makefile.am, main.c, maps.c, util.c: Moving the Object/Item/Cad_Object code into objects.h and objects.c. 2005-09-25 19:26 we7u * src/: objects.c, objects.h: Moving nearly all of the Object/Item/CAD Object code into one header and one source file. This makes main.c quite a bit smaller. 2005-09-24 11:21 we7u * src/main.c: Proper numeric checks for Global.top size/offsets, for deciding whether to make the 2nd Xastir window (the first visible window) copy either set of parameters. 2005-09-24 11:00 we7u * src/: list_gui.c, main.c: Changing variables used in XtVaGetValues() calls to "Dimension" or "Position". Adding an out-of-range check for dimension for the case where we're attempting to discover whether the first window has had -geometry specified. 2005-09-23 17:18 we7u * src/main.c: First working version of the "-geometry" command-line flag. Will hopefully know soon if it works on all platforms we support. Let the testing begin! 2005-09-23 12:01 we7u * src/main.c: "-geometry" switch now works for sizing the application (instead of "-g"), but the X/Y offsets still don't work. 2005-09-22 19:18 tvrusso * src/main.c: Give "appshell_width" and "appshell_height" initial values of 0. This allows the contents of the xastir.cnf file's SCREEN_WIDTH and SCREEN_HEIGHT to be used if no geometry is specified in -g. As it was, if one didn't give -g then these two settings in the config file were ignored and a 100x100 window appeared on every start-up. 2005-09-22 13:32 we7u * src/main.c: A fix for Xastir hanging if the -g flag is used but only offsets are specified. 2005-09-22 13:07 we7u * src/main.c: Initial implementation of the "-g" geometry command-line flag. It supports sizing the application, but doesn't support X/Y offsets yet. That's in the works though. 2005-09-21 22:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/track_gui.c: Added success/failure popups to findu trail download. Changed max_trail_colors to a define instead of an int. Added a Change Trail Color button to the Station Info dialog. 2005-09-21 11:51 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/track_gui.c: Popping up an error if the new backgrounded fetch findu trail fails. Changing variables that the thread depends on to "static" so they'll be around when the thread needs them. 2005-09-20 17:35 tvrusso * acinclude.m4: Restructure test for gv slightly, so that AC_PATH_PROG is called first, and version is tested if gv is found. The case where gv is found, but `gv -v | cut -d ' ' -f 1` not being "gv" is in fact a sign of error that needs to be reported in a meaningful way. Turns out that when I do my normal cygwin build (which is usually done in a non-X cygwin run to save memory), the old way of probing gv found the gv executable, but because "gv -v" tries to connect to the X server and reports failure if it can't, configure was telling me that gv was found, but the build would actually happen without gv. This was quite confusing. With the new test as committed here, I still can't build with gv outside of an xterm on cygwin, but the reason actually shows up in the configure output. 2005-09-17 11:33 we7u * src/lang.h: Bumping up the size of the language buffer as we're bumping up against the limits now for some languages. 2005-09-16 16:46 we7u * src/xastir_udp_client.c: Changing some comments and the usage text. 2005-09-16 16:45 we7u * src/track_gui.c: Trying to protect the track download so that only one can be done at once. Not perfect yet as sometimes the GUI locks up. More to do. 2005-09-16 16:34 we7u * config/language-English.sys: Changing "New Call" to "New Station" for the speech strings. I think it sounds better. 2005-09-16 14:09 we7u * config/language-English.sys: Adding an 's' to the end of "Enable Server Ports". 2005-09-16 14:09 we7u * config/language-German.sys: Updates courtesy of Andreas Bier, dl1hrc. Thanks! 2005-09-16 13:18 we7u * help/help-English.dat: Tweaking the text regarding the UDP server/client. Adding more about the -identify command-line flag. 2005-09-16 13:14 we7u * src/xastir_udp_client.c: Making the output from the -identify response go to STDOUT instead of STDERR. Only makes sense so it can be piped more easily into scripts and such. 2005-09-16 13:09 we7u * src/xastir_udp_client.c: Implemented the "-identify" command-line flag. The "message" portion must have at least a single char in order for the identify query to be sent to the server. 2005-09-16 12:37 we7u * help/help-English.dat, src/x_spider.c: Now we send UDP packets out the x_spider TCP ports as well, if the packet is authenticated properly. 2005-09-16 12:26 we7u * src/x_spider.c: Adding a "-identify" option to the UDP server. It returns a UDP packet containing the callsign. 2005-09-16 11:48 we7u * src/track_gui.c: Putting the fetch_findu_trail function into a separate background thread. 2005-09-16 11:48 we7u * help/help-English.dat: Adding text about the UDP server feature and the xastir_udp_client. 2005-09-16 07:38 we7u * src/: x_spider.h, xastir_udp_client.c: Moving the default port for UDP from 2024 to 2023, as TCP and UDP can co-exist on the same port number. 2005-09-15 16:59 we7u * src/xastir_udp_client.c: Fixed the hostname lookup. You can now specify any hostname and port. 2005-09-15 12:38 we7u * src/util.c: Adding the long integer time at the beginning of the timestamp line for the log files. Makes sorting easy. 2005-09-15 11:56 we7u * src/: util.c, wx.c: Changing timestamping to add a timestamp line per packet instead of once per 30 seconds. 2005-09-15 11:47 we7u * src/: x_spider.c, xastir_udp_client.c: Adding authentication to the UDP packets. 2005-09-15 11:45 we7u * src/db.c: Allowing user-defined and telemetry packets to be gated. 2005-09-15 07:54 we7u * src/.cvsignore: Adding xastir_udp_client to the ignore list. 2005-09-15 07:52 we7u * src/: Makefile.am, x_spider.c: Renaming the UDP client from udp_client to xastir_udp_client. 2005-09-15 07:51 we7u * src/xastir_udp_client.c: Renaming this file from udp_client.c to xastir_udp_client.c, to avoid similar names for UDP clients. 2005-09-15 07:50 we7u * src/udp_client.c: Renaming this file to xastir_udp_client.c 2005-09-14 21:53 we7u * src/: interface.c, main.c, x_spider.c, x_spider.h: Adding a UDP server at port 2024. 2005-09-14 21:45 we7u * src/Makefile.am: Adding the udp client. 2005-09-14 21:44 we7u * src/udp_client.c: Initial checkin of a UDP client. Currently this is hard-coded to talk to the localhost address, but that can be fixed later. It also hangs currently if the server isn't responding. 2005-09-09 13:08 we7u * src/db.c: Fixing a typo in one of the new langcode() string callouts. 2005-09-09 12:20 we7u * src/: db.c, main.c, util.c: Replacing a bunch of hard-coded strings with langcode() strings. 2005-09-09 12:19 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more language strings to replace hard-coded strings. 2005-09-08 21:46 we7u * src/: draw_symbols.c, fcc_data.c, geocoder_gui.c, map_cache.c, rac_data.c, view_message_gui.c, xa_config.c: Adding language strings for previously hard-coded values. Changed get_long and get_int functions in xa_config.c to give better output when variables are missing or out-of-range in the config file upon Xastir startup. 2005-09-08 21:40 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more language strings for previously hard-coded English values. 2005-09-08 09:49 we7u * INSTALL: Adding a blurb about conflicts between GDAL internal libraries and external libraries that Xastir can use. 2005-09-08 09:39 tvrusso * acinclude.m4: Move -lgdal to end of LIBS line if it's found. It is possible for gdal to be using its own internal geotiff library, and this can interfere with use of an external one in xastir. Having it later in the line than geotiff can fix that. This could cause problems for systems with busted linkers that need gdal to be earlier than everything it depends on. If that happens, it might be necessary to add the contents of "gdal-config --dep-libs" to LIBS after -lgdal. 2005-09-08 08:58 we7u * src/map_tif.c: Commenting out some unnecessary includes. Adding some error messages when function calls fail. Minor reformatting w.r.t. braces to match the Xastir project standard. 2005-09-07 12:30 we7u * src/main.c: Assuring that the "System time jumped backwards 1 seconds!" message doesn't say "0 seconds!", as I've seen recently due to the way the code was originally written. 2005-09-02 18:42 we7u * acinclude.m4: More appropriate output for the case where gv is not found by configure. 2005-09-02 16:00 we7u * acinclude.m4: Adding a clause for the case where no usable "gv" is found. 2005-09-02 15:34 we7u * acinclude.m4: Another stab at trying to do the "gv" revision tests. 2005-09-02 15:34 we7u * src/maps.c: Pop up warning messages if we try to print but don't have the proper support compiled in. 2005-09-02 13:54 we7u * acinclude.m4, src/maps.c: Tweaks to hopefully determine automatically which version of "gv" is being used and change the code to correspond to the proper API. 2005-09-02 12:30 we7u * src/maps.c: Preparing for configure.ac tests that will determine the "gv" version, then we can change how we call up "gv" based on that. 2005-09-02 08:47 we7u * src/x_spider.c: Changing to a combination for the "Hello" server message, per the APRS INET conventions. 2005-09-01 10:00 we7u * README.Getting-Started: Modified the note regarding geocode files. 2005-09-01 08:08 we7u * configure.ac, src/main.c: Adding a test for sigignore() to configure.ac, and code to use it in main.c. We were getting a warning under Solaris by using signal() with SIG_IGN as the parameter. 2005-09-01 07:43 we7u * src/util.c: Adding strings.h include. Need for Solaris. 2005-08-31 21:16 we7u * config/tnc-startup.kpc3: Removing "exp on" from the file. I guess SOMEBODY doesn't think we need AEA commands in a KANTRONICS config file. The nerve! 2005-08-31 14:42 we7u * REGRESSION_TESTS: Blowing away the autom4te.cache directory at the start of each run, to make sure that we start out ultra-clean. 2005-08-31 09:59 we7u * configure.ac: Attempt to remove "-no-unused" from linking stage for Cygwin builds, as GCC links to complain about that flag during linking. 2005-08-30 14:19 we7u * acinclude.m4: Changing grep syntax so that it will work with non-GNU grep (Solaris). Getting rid of dash near the end. 2005-08-30 13:52 we7u * src/: awk.c, bulletin_gui.c, db.c, main.c, map_WMS.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c: Mucking about with the strings.h includes. 2005-08-30 13:28 kd6zwr * src/: awk.c, geo-find.c, io-common.c, map_gnis.c: protecting the strings.h with an ifdef, and casting isspace() family of macros to match man page (int). 2005-08-30 12:41 we7u * src/awk.c: Adding a strings.h include for Solaris support. 2005-08-30 11:33 we7u * src/db.c: Displaying the raw packet in a dialog for the case where we detect "EMERGENCY" in the comment field or one of the emergency-type destination callsigns in a packet. 2005-08-30 11:31 we7u * config/tnc-startup.paccomm: Commenting out a "WIDE" alias that remained. Changed it to "LOCAL" also. 2005-08-30 11:31 we7u * src/locate_gui.c: Skipping the dialog destroy call if you hit the FCC/RAC lookup or the Locate button. The dialog now has to be manually cleared by hitting the Cancel button. 2005-08-29 08:06 we7u * src/: db.c, interface.c, wx.c: Fixing warnings seen on OSX 10.4. Very minor "signedness" warnings in string functions. 2005-08-27 17:21 we7u * src/x_spider.c: Tweaking a patch provided by James Washer that will send a string out the server port on each connect. My chances were merely to the format of the string. Thanks go to James for the patch itself. 2005-08-26 14:12 tvrusso * configure.ac, src/hostname.c: Fix so that hostname.c can compile on systems that define neither sighandler_t nor sig_t. This is necessary because of the new cast to sighandler_t of the second argument of signal() that was put there to shut gcc warnings up. 2005-08-25 14:29 we7u * acinclude.m4: Getting rid of some extra restores of variables that I shouldn't have added last go-around. 2005-08-25 13:48 we7u * acinclude.m4: Summary text and summary.log were incorrect if gdal wasn't found. Fixed. 2005-08-25 08:11 we7u * src/db.c: Commenting out some debug code. 2005-08-24 21:27 we7u * src/xa_config.c: Simplifying the get_long() and get_int() code per discussions with Tom Russo. Also attempting to get rid of some compiler warnings that we see with FreeBSD. 2005-08-24 10:58 we7u * src/main.c: Switching the state of trap_segfault variable to make more sense. 2005-08-24 09:50 we7u * src/main.c: Change in text suggested by James Washer. Also added the -t option to the command-flag help text. 2005-08-24 09:07 we7u * src/xa_config.c: Removing some ill-advised casts to time_t's. Was trying to get rid of warnings that appear on FreeBSD, but this was the wrong approach and didn't fix the problem. 2005-08-23 21:08 tvrusso * configure.ac, src/hostname.c: Change logic for deciding when to use a sigjmp_buf vs. a jmp_buf. The code that was originally here would only work if sigjmp_buf was a #define, but on some systems it's a typedef. The new code works for both. 2005-08-23 19:53 we7u * src/: awk.c, bulletin_gui.c, map_gdal.c, maps.c: Fixing up function headers to be ANSI-C compliant. 2005-08-23 16:25 we7u * INSTALL: Tweaking the GDAL install instructions a bit more. 2005-08-23 16:04 we7u * INSTALL: Updating the GDAL install instructions. 2005-08-23 14:38 we7u * configure.ac: Changing the summary format slightly. No code changes. 2005-08-23 14:23 we7u * configure.ac: Drawing a line in the configure summary between the normal and the more unusual parameters. 2005-08-23 14:18 we7u * configure.ac: Changing some text on the summary output. No code changes. 2005-08-23 13:52 tvrusso * acinclude.m4: Add configure-time check for usability of -Wno-unused-parameter. Older compilers (not newer as was indicated in the comments) don't like that and need -Wno-unused instead. Return -W to the CFLAGS, and use whatever -Wno-unused* works. 2005-08-23 12:39 we7u * src/interface.c: Added a new time_t variable that we can use to call ctime() with, in order to avoid a compiler warning. 2005-08-23 12:38 we7u * src/xa_config.c: Changing a bunch of pointer casts from "long *" to "time_t *" to avoid compiler warnings. 2005-08-23 12:36 we7u * src/util.c: Casting some time_t's to long's to avoid compiler warnings. 2005-08-23 12:35 we7u * src/main.c: Casting a time_t to an unsigned long to remove a compiler warning. Fixing up a function header to make it ANSI-C compliant. 2005-08-23 12:32 we7u * src/db.c: Casting some time_t's to long's to get rid of warnings. 2005-08-23 12:32 we7u * src/alert.c: Casting some time_t's to unsigned long's to get rid of warnings. 2005-08-23 12:30 we7u * acinclude.m4: Taking some of the new compiler flags back out as one of them isn't recognized on some versions of GCC, and the other causes too many warnings without it. Hopefully we can add the "-W" back in at a later date once we figure out how to get rid of the "unused parameter" warnings on a case-by-case basis. 2005-08-22 16:02 we7u * src/io-mmap.c: Cleaning up compiler warnings. 2005-08-22 15:21 we7u * acinclude.m4: Adding "-W" and "-Wno-unused_parameter" compiler flags. Still a clean compile with SuSE Linux 9.0. No errors, no warnings. 2005-08-22 11:45 we7u * src/: db.c, interface.c, interface.h: Added is_local_interface() and is_network_interface() functions. Changed packet_data_add() to use them, and to changes it functionality so that packets transmitted to local interfaces would be visible in the incoming data dialog. 2005-08-22 11:37 we7u * src/: shp_hash.c, shp_hash.h: Fixing up prototypes and function headers so that they are ANSI-C compatible. 2005-08-22 11:36 we7u * src/rtree/: card.c, gammavol.c, index.c, index.h, node.c, rect.c: Fixing up prototypes and function headers so they are ANSI-C compatible. 2005-08-22 11:35 we7u * REGRESSION_TESTS: Tweaking to match new format for summary.log file (we only want to show the first line now). 2005-08-19 18:53 we7u * src/: database.h, db.c, map_cache.c, map_cache.h, map_shp.c, maps.c, testawk.c: Fixing up function and prototype definitions so they are ansi-C standard and will pass the new compiler tests that were just added. 2005-08-19 18:40 we7u * acinclude.m4: Adding more strict compiler checking. 2005-08-19 18:27 we7u * INSTALL: Adding notes about malloc debugging. 2005-08-19 14:31 we7u * src/draw_symbols.c: Adding/changing some comments. 2005-08-19 14:26 we7u * src/draw_symbols.c: Real fix for memory leak in the font metrics code. Don't know why we need a '1' parameter for this system call, but with a '0' we end up with a leak. 2005-08-19 13:32 we7u * src/draw_symbols.c: Fix for big memory leak. 2005-08-19 11:33 tvrusso * configure.ac, src/hostname.c: Add probe for sighandler_t definition, and code to work around it being missing. 2005-08-18 16:54 we7u * src/interface.c: Fooled myself. Last fixes weren't fixes but stopped the compile. Will rework that fix later. 2005-08-18 16:51 we7u * src/interface.c: Putting a few casts in to get rid of "-pedantic" warnings. 2005-08-18 16:21 we7u * src/map_cache.c: Getting rid of three more "-pedantic" warnings. 2005-08-18 16:09 we7u * src/interface.c: More tweaks so that the "-pedantic" compiler flag will show fewer warnings. 2005-08-18 15:56 we7u * src/: hostname.c, shp_hash.c: Fixing up minor warnings that the "-pedantic" compiler flag revealed. 2005-08-18 15:27 we7u * src/: alert.c, db.c: Getting rid of another couple of warnings that the "-pedantic" compiler flag revealed. Very minor stuff. 2005-08-18 15:11 we7u * src/hashtable_private.h: Removing the semicolon at the end of a function that "-pedantic" compiler flag caught. 2005-08-18 14:49 tvrusso * acinclude.m4, src/testawk.c: Make use of LIBS in the gdal probe without gdal-config match the usage with gdal-config fix bogon in awk_rule table in testawk.c 2005-08-18 14:43 we7u * src/messages_gui.c: Casting to an "int" in order to get around a compiler warning that we get if we turn on stricter checking. 2005-08-18 14:42 we7u * src/main.c: Adding a missing initializer. 2005-08-18 14:00 we7u * src/: leak_detection.h, util.h: Tweaks by Tom Russo to make the new include arrangement work on FreeBSD. Evidently I broke that platform with my most recent include file changes. 2005-08-18 08:28 we7u * src/view_message_gui.c: Moving the dmalloc code to a separate header file. 2005-08-18 08:27 we7u * src/util.c: Messing with the hash iterator free's again. Moving dmalloc code to a separate header file. 2005-08-18 08:26 we7u * src/: map_gdal.c, maps.c, wx_gui.c: Messing with the hash iterator free's again. 2005-08-18 08:26 we7u * src/leak_detection.h: Here's where the malloc and dmalloc code was moved to. The order in which this is done with respect to the libgc code is critical, therefore it has all been moved to this one header file so the order can be closely guarded. 2005-08-18 08:24 we7u * src/interface_gui.c: Removing the dmalloc code. 2005-08-18 08:23 we7u * src/: hashtable_private.h, hashtable_itr.c: Removing the xastir.h include. 2005-08-18 08:22 we7u * src/hashtable.c: Moving a comment. 2005-08-18 08:22 we7u * src/db.c: Removing dmalloc ifdef's. 2005-08-18 08:21 we7u * src/alert.c: Getting rid of dmalloc ifdef's. We use libgc to do similar things. Messing with the iterator ifdef's again. 2005-08-17 13:16 we7u * src/util.c: Skipping the free() of the hashtable iterator in all cases. 2005-08-17 13:13 we7u * src/maps.c: Moving alert-related code to debug level 2. Skipping hash iterator free() calls for now as they cause segfaults if libgc is compiled in. 2005-08-17 13:11 we7u * src/db.c: Changing debug_level to 2 for wx_alert-related code. 2005-08-17 13:10 we7u * src/alert.c: Added some debug statements. Skipping hash iterator free() as it causes segfaults. 2005-08-17 12:13 we7u * src/util.c: Adding leak_detector.h include. Simplifying add_tactical_to_hash() function. 2005-08-17 12:12 we7u * src/: map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, messages.c, messages_gui.c, popup_gui.c, rac_data.c, rotated.c, shp_hash.c, snprintf.c, sound.c, testawk.c, track_gui.c, util.h, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, x_spider.h, xa_config.c, xastir.h: Adding leak_detector.h include. 2005-08-17 12:11 we7u * src/main.c: Adding leak_detector.h include. Changing memory leak check to every 60 seconds (from 5 minutes). 2005-08-17 12:08 we7u * src/: awk.c, bulletin_gui.c, color.c, datum.c, db.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface.h, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, macspeech.c: Adding leak_detector.h include. 2005-08-17 12:06 we7u * src/alert.c: Adding leak_detector.h include. Simplifying the add_wx_alert_to_hash function. 2005-08-17 12:04 we7u * src/Makefile.am: Adding the leak_detector.h file. 2005-08-17 12:02 we7u * src/leak_detection.h: Moving the LIBGC defines/includes into a new header file. The order in which these are used in a C module is important, as is the order that the thread includes are done. This will help assure that the order remains consistent so that the memory leak detection will work. 2005-08-17 11:59 we7u * INSTALL: Tweaking the libgc instructions. 2005-08-15 17:47 we7u * src/util.c: Separating out the pointers so we can better keep track of them, assuring that we're not overwriting anything we shouldn't. Freeing some malloc'ed space for the case where hash inserts fail. 2005-08-15 17:45 we7u * src/shp_hash.c: Freeing some malloc'ed space for the case where hash inserts fail. 2005-08-15 17:44 we7u * src/map_gdal.c: Freeing some malloc'ed space for the cases where hash inserts fail. 2005-08-15 17:44 we7u * src/alert.c: Changing a memcpy to an xastir_snprintf call in order to assure that the string is terminated. Added some debugging set_dangerous/clear_dangerous calls. 2005-08-15 17:42 we7u * src/main.c: Making the RINO download timeout slider always visible in the timing dialog, but insensitive if gpsman is not compiled in. 2005-08-15 13:01 we7u * configure.ac: Adding a very short summary of the configure tests and results to summary.log. This should aid in debugging as we can more quickly see what passed/failed on a particular user's machine. 2005-08-14 23:43 we7u * src/map_shp.c: Committing Tom Russo's fix to remove colon chars in track->shapefile save routine. Seems Cygwin doesn't like colons in filenames. 2005-08-13 09:43 we7u * README.win32: Fixing a couple of typos. 2005-08-12 22:21 we7u * src/main.c: Moving one define to the top of the file. This one contains some copyright dates and appears in the Help dialog, so must be updated periodically. This new location for it is much better than having it hidden in the middle of the file. 2005-08-12 22:07 we7u * src/util.c: Adding spaces around the "==" in the #if statement added today. 2005-08-12 20:17 we7u * acinclude.m4, configure.ac: Taking out the new MALLOC test added today as AC_FUNC_MALLOC already does what we need. 2005-08-12 14:37 we7u * acinclude.m4, configure.ac, src/util.c: Adding rpl_malloc() function in util.c, and the associated hooks into acinclude.m4 and configure.ac to get it called. This is to replace malloc() for those cases where malloc() doesn't behave properly. 2005-08-12 14:36 we7u * INSTALL: Adding a note about libgc's extra memory usage. 2005-08-12 13:41 we7u * config/language-Portuguese.sys: Shortening the Portuguese version of "Enable Weather Alerts" string. 2005-08-12 12:37 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added a Reset button to the Change Debug Level dialog. 2005-08-12 12:36 we7u * src/: alert.c, main.c, map_gdal.c, maps.c, util.c, wx_gui.c: Added a reset button to the Change Debug Level dialog. Made the Enable WX Alerts menu item be grey'ed out if Shapelib not installed. Added debug statements multiple places. Put #ifndef's around a bunch of free(iterator) statements for the case when libgc is configured into the compile (else segfaults occur). 2005-08-12 12:27 we7u * config/: language-Dutch.sys, language-English.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Removing "Counties" from the Enable Weather Alerts text. 2005-08-12 08:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Adding a custom zoom option to the right-click zoom levels menu. 2005-08-11 13:40 we7u * src/main.c: Moving the Center & Zoom dialog to the Maps menu. 2005-08-11 12:46 we7u * REGRESSION_TESTS: Added a default configure/compile at the end, both to test this case and to get the codebase back to normal for the system it's run on. 2005-08-11 12:20 we7u * REGRESSION_TESTS: Removed a couple of el-stupido test cases. Nice'ed everything. 2005-08-10 18:37 we7u * configure.ac: Adding warnings so that library dependencies are obvious. Adding code so that missing dependencies cause dependent libraries to be skipped. 2005-08-10 18:35 we7u * INSTALL: Added an ASCII-art drawing showing the library dependencies. 2005-08-10 14:06 we7u * configure.ac: Adding another configure warning for missing library. 2005-08-10 12:00 we7u * REGRESSION_TESTS: Adding tests for ALL libraries minus one, each in turn. 2005-08-10 11:58 we7u * configure.ac: Forcing use_rtree to OFF and issuing a warning if Shapelib is not being used. 2005-08-10 11:39 we7u * src/: main.c, shp_hash.c: Fixing the code for the case where rtree has been requested buy Shapelib is not compiled in. It makes no sense to do this, but at least it will compile for this case now. 2005-08-10 11:38 we7u * src/track_gui.c: Tweaking the Fetch Findu Trail function so that it matches what findu is capable of for the trail duration. Changed the start time and duration time max values to #defines at the top of the file so we can change it more easily next time around. 2005-08-09 08:57 tvrusso * acinclude.m4: Fix for broken fix of broken fix of probe for gdal. After I fixed the multiply-included -lgdal issue and made sure that I'd separated out -Ls from -ls, I never made sure that the -l got into LIBS. I was counting on AC_CHECK_LIB to do that, but it only does so if you don't provide an ACTION-IF-FOUND. 2005-08-08 20:53 tvrusso * acinclude.m4: Add ugly hack to work around gdal-config's idiosyncratic merging of LDFLAGS and LIBS data with the single "gdal-config --libs" command. Other programs with -config scripts have --ldflags and --libs to keep the stuff separate. 2005-08-08 20:18 tvrusso * acinclude.m4: Fix broken attempt to replace old flags into variables after failing test. 2005-08-08 14:12 francais1 * config/language-French.sys: Incorporated most changes from Jacques Chion 2005-08-08 12:27 we7u * src/track_gui.c: Adding a debug statement. 2005-08-06 11:11 tvrusso * acinclude.m4: Fix up AC_CHECK_GDAL so it uses LIBS instead of LDFLAGS. This makes it more consistent with other usages. gdal-config --libs actuall returns both LDFLAGS and LIBS type information, and using its output for LDFLAGS winds up putting the -lgdal flag very early in the link line. This could be a problem on some systems. 2005-08-06 11:05 tvrusso * acinclude.m4: Fix dumb mistake in the section that handles the "gdal-config not found" condition. 2005-08-06 11:01 tvrusso * acinclude.m4, configure.ac: Make probe for gdal use gdal-config if it can be found. If gdal-config is in the user's path, use it to get LDFLAGS and CPPFLAGS to help the probe for gdal.h and libgdal.a. Otherwise, use the current settings of LDFLAGS and CPPFLAGS and hope they're found. In doing this, I think I see that the probe XASTIR_CHECK_IMAGEMAGICK has a few bugs in it. 2005-08-06 00:14 tvrusso * src/db.c: Fix new emergency processing in decode_ax25_line so that it only attempts to work on valid packets. This was causing segfaults at strcmp(my_callsign,call_sign) when connecting to an internet server (upon receiving the # javAPRServ line), because call_sign was NULL. 2005-08-05 18:14 we7u * REGRESSION_TESTS: Making the output a bit easier to understand. 2005-08-04 20:13 we7u * src/draw_symbols.c: Using font metrics to determine size of font. We then use that to determine the size for the black rectangle underneath the font. 2005-08-04 12:34 we7u * src/: db.c, draw_symbols.h, draw_symbols.c: Drawing a line between the waypoint symbol and the station that originated it. Per the spec. 2005-08-03 18:52 we7u * symbols/symbols.dat: Updating a symbol or three. 2005-08-03 13:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h: Have implemented an EMERGENCY BEACON transmit capability. Look for it under the "Help" menu (appropriate, no?). 2005-08-03 12:15 we7u * REGRESSION_TESTS: More minor cleanups. No real changes. 2005-08-03 12:01 we7u * src/db.c: Added emergency beacon decode for the string "EMERGENCY" anywhere in the packet, plus the strings: ALARM ALERT WARNING WXALARM EM If seen in the TO: field of the packet. This matches the decoding provided by APRS+SA for this feature. 2005-08-02 13:22 we7u * REGRESSION_TESTS: Small tweaks to improve the output and give us info while it is running instead of all the output at the end. 2005-08-01 21:40 we7u * REGRESSION_TESTS: Changing the order of the individual flag tests to match the summary output order from "configure". 2005-08-01 21:18 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Taking "RELAY" out of the digipeat? label. 2005-08-01 21:16 we7u * REGRESSION_TESTS: Fiximg the grep at the end. 2005-08-01 19:33 we7u * REGRESSION_TESTS: Initial checkin. A "dumb" script the way it is currently written, but it could be made much more intelligent over time, and extended to perform more tests. 2005-08-01 19:29 we7u * symbols/symbols.dat: Changing the symbols to be more spec-compliant. The spec keeps changing on us. Added an SUV symbol. Moved the Shelter symbol to the secondary table. Changed the background on the Storm Watch symbol to orange instead of red. Still need to do the waypoint symbol so it is a red circle and have a line going between it and the mobile transmitting it, plus need to change "No Sym Yet" to a circle with a slash through it, per the latest spec addendum. It would be worth taking a look at all the symbols to verify compliance. 2005-08-01 19:26 we7u * src/map_geo.c: Getting rid of a compiler warning (unused variable) when ImageMagick isn't compiled in. 2005-08-01 15:08 tvrusso * src/map_shp.c: Move declaration of draw_filled out of WITH_DBFAWK ifdef. 2005-08-01 14:34 we7u * src/main.c: Updating the year on the Help->About copyright notice. 2005-08-01 12:43 we7u * configure.ac, help/help-English.dat: Bumping version to 1.6.1 for further development. 2005-08-01 11:11 we7u * help/help-English.dat: Updating the what's new section for 1.6.0. 2005-08-01 10:54 we7u * README.Contributing, README.Getting-Started, configure.ac, help/help-English.dat: Bumping the version to 1.6.0. 2005-07-30 23:19 we7u * src/: bulletin_gui.c, db.c, interface_gui.c, maps.h, locate_gui.c, location_gui.c, main.c, map_gnis.c, messages_gui.c, wx_gui.c: Adding new capability to the Map Feature Search function: Now returns a chooser dialog that allows seeing up to the first fifty matches for the search, then centering the map on any of them. Also tweaked array sizes throughout the code used for sending parameters to X11 calls. 2005-07-29 12:32 we7u * src/: locate_gui.c, map_gnis.c, maps.h: Changing locate_place() to gnis_locate_place() because it is too similar to the function Locate_place(). Added some comments w.r.t. putting in a chooser option for the Locate Map Feature function. 2005-07-29 12:31 we7u * src/db.c: Changing some comments. No code changes. 2005-07-29 12:29 we7u * src/xa_config.c: Calling the new remove_all_spaces() function on one variable read in from the config file. 2005-07-29 12:29 we7u * src/: util.c, util.h: Added a "remove_all_spaces" function. 2005-07-28 13:41 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tif.c, src/xa_config.c: Implementing the XOR function for combining USGS DRG colors with underlying map colors. Changed some labels with respect to this new function. 2005-07-26 12:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the DRG Color Filtering labels to the correct color names. 2005-07-26 12:39 tvrusso * src/map_gdal.c: Fix extern declaration of draw_shapefile_map 2005-07-26 12:32 tvrusso * src/main.c: Add a comment. 2005-07-26 12:16 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/maps.c, src/maps.h: Implement auto detection of USGS DRG topo maps (the ones actually from USGS, with proper GeoTIFF tags). Changed map driver interface to take a struct of map flags instead of a single "draw_filled" integer. Changed map properties to support setting of Yes/No/Auto for a given map's "USGS DRG" field. If Yes, the color map is assumed to be USGS's and the color settings in Map->Configure USGS DRG are used. If No, all colors in the colormap are displayed. If Auto, the tiff's Image Description tag is queried and if it begins with "USGS DRG GeoTIFF" then it's as if the setting was Yes, and if it doesn't (or the tag does not exist) then it is as if the setting was No. Added rowcol to map properties dialog to handle the extra buttons without widening the window. Cleaned up the code in main.c that locates the filename in a map properties line. It was being done by hardcoding the offset in 8 places to 31. Moved the magic number to a preprocessor symbol so it only needs to be changed once now. There has got to be a cleaner way still, but that's enough for now. Changed all map drivers to support the new map_data_flags struct instead of the int draw_filled. Changed language files. Not sure I got all of them right. 2005-07-25 10:00 tvrusso * src/xa_config.c: Change DRG_COLORS settings so that they default to ON if a config file is read in that doesn't contain the settings. This will make sure that users who upgrade don't get surprised by having all their topo maps disappear upon upgrading. 2005-07-23 19:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tif.c, src/xa_config.c, src/xastir.h: Added a Configure USGS DRG dialog. Allows turning on/off various drawing colors on geoTIFF images. 2005-07-22 18:27 we7u * src/map_tif.c: Added a couple of defines at the top that control whether we display an entire topo map or just the contours, and which color we display them in. 2005-07-22 12:42 we7u * src/util.c: Cleaning up the curl code a bit more: Removed unnecssary includes and moved the one remaining include up to the top of the file. 2005-07-21 23:17 we7u * config/language-Dutch.sys: Translating one label. 2005-07-21 23:08 we7u * src/: track_gui.c, map_WMS.c, map_geo.c, map_tiger.c, maps.c, util.c, util.h: Consolidating all of the libcurl and wget functionality into util.c:fetch_remote_file(). This should make the code much easier to maintain and extend. 2005-07-21 21:33 we7u * INSTALL: Adding some instructions provided by Tom Russo for specifying an unusual location of libdb to configure. 2005-07-21 13:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/geocoder_gui.c: Correcting the "Find Address" label in several spots. 2005-07-21 12:53 we7u * INSTALL: Adding a list of libraries for a full-up Xastir compile on SuSE 9.0 to aid people in deciding which libraries might be needed. 2005-07-20 19:19 we7u * src/: map_cache.c, map_cache.h, main.c: Added a run-time check for matching versions in db.h and libdb.so. 2005-07-20 19:12 we7u * src/track_gui.c: Fixing the duration hours slider so that it can't be any larger than the start hours slider. 2005-07-20 11:50 we7u * INSTALL: Adding some text having to do with using the optional Berkeley DB Library for map caching. 2005-07-20 11:49 we7u * acinclude.m4: Adding some comments to the XASTIR_BERKELEY_DB_CHK_LIB function. Things we need to add/figure out in order to assure that the Berkeley DB Library can be successfully used with Xastir. 2005-07-19 22:13 we7u * help/help-English.dat: Added an example of how to use the Fetch trail from Findu timing sliders. 2005-07-19 22:09 we7u * src/: main.h, db.c, xa_config.c: Implementing user-configurable digipeater callsigns. Users will now be able to edit the comma-delimited string in their xastir.cnf file. There are no GUI tie-ins for editing the string at this point. 2005-07-19 21:43 we7u * help/help-English.dat: Adding some more detail about the Map Chooser->Properties dialog. Adding some new text about the user-configurable relay digipeater callsigns which will be committed to CVS shortly. 2005-07-19 21:41 we7u * configure.ac: Reordering the summary.log and Help->About library strings plus adding the few that were missing. 2005-07-19 21:38 we7u * README.MAPS: Minor tweak to one comment. Nothing substantial. 2005-07-19 12:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing up the displayed string for Beam Heading objects, "Bearing:" string. 2005-07-18 11:12 tvrusso * src/draw_symbols.c: Fix for broken DF directional lines when zoomed in tight. Restricts range of lines to something close to the screen, rather than the full range allowed by the DF object's NRQ (or the default of 512 nautical miles. 2005-07-16 23:19 we7u * src/interface_gui.c: Allowing the passcode to be longer (up to 20 chars). Useful in a few instances, and similar to what's allowed currently in the AGWPE code. 2005-07-16 23:17 we7u * src/x_spider.c: Adding a #define and some #ifdef's that allow compiling the code in either standalone daemon mode or called-function mode. 2005-07-15 09:30 we7u * src/main.c: Adding spaces to the help text. 2005-07-15 09:18 we7u * xastir.spec.in: Re-ordering the docs alphabetically. No real change. 2005-07-13 12:37 we7u * src/util.c: Adding some comments. Preparatory to redoing some code. 2005-07-12 19:44 tvrusso * config/tgr2shppoly.dbfawk: Make polygon boundaries the same color as fill. Now that boundaries are no longer stippled the same way as the fill, the black boundaries are too glaring. 2005-07-12 16:06 tvrusso * src/map_shp.c: Reset stipple style to solid when drawing boundaries of polygons with dbfawk. They were getting drawin in the stipple pattern used for fill, which made for fuzzy boundaries. 2005-07-11 12:25 we7u * configure.ac: Fixing the Geotiff summary line so that it says "no" if libproj isn't found. It was blank until now in this case. 2005-07-11 12:24 we7u * src/map_geo.c: Moving one line so that this will compile ok without warnings if no ImageMagick. 2005-07-11 10:50 we7u * src/xastir.h: If ImageMagick is not found, util.c compile will fail without this change. 2005-07-11 07:55 tvrusso * src/main.c: Put use of map_cache_fetch_disable into the same ifdef as the definition of that variable, so that people who aren't using map caching can link. 2005-07-10 10:56 tvrusso * FAQ: Change question 5.4 to actually have "5.4" in its title. 2005-07-10 08:37 tvrusso * scripts/Xastir_tigerpoly.py: Add -d flag to the Usage error message. 2005-07-10 08:36 tvrusso * scripts/Xastir_tigerpoly.py: Add "-d" option to this script to allow dissolution of common boundaries between polygons with the same Landmark designation. This is done by scanning all PolyChainLink records, checking that both left and right polygon have associated AreaLandmark records, and that both AreaLandmark records point to the same Land record. If they do, then the two polygons are dissolved into one. The option is not the default. Using this option makes the output shapefile be topologically inequivalent to the original TIGER/Line data, and as such they are suitable only for display. Distributing data produced in this manner should be done with a prominient disclaimer pointing out that the shapefiles are for display purposes, not serious GIS use. Dissolving polygons in this way makes the TIGER data look much nicer (but still pretty ugly) in xastir -- large landmarks no longer have many copies of the labels, and no longer have ugly internal dashed boundaries that mean nothing. 2005-07-08 20:30 we7u * src/dbfawk.c: A fix for the emacs temp-file bug that is invoked by temp file symlinks of the form ".*.dbfawk" while editing dbfawk files. The code will now ignore anything but regular files, and ignores directories and files that have a leading period. 2005-07-08 20:27 we7u * src/: main.c, map_WMS.c, map_cache.c, map_cache.h, map_geo.c, map_tiger.c: Enabling the reload maps (without cache) option on the Map menu, with the back-end code in place to implement it. A few tweaks to the map_cache_del() function to return with error code under certain conditions. 2005-07-08 13:19 we7u * src/main.c: Comment changes only. 2005-07-08 12:24 we7u * src/main.c: Changed some comments. 2005-07-08 00:07 we7u * src/main.c: Implemented "Flush Entire Map Cache" function. 2005-07-07 19:22 we7u * src/xastir.h: Renaming tigermap_timeout to net_map_timeout. 2005-07-07 19:21 we7u * src/: map_geo.c, main.c, map_WMS.c, map_tiger.c, util.c, xa_config.c: Moving the tigermap slider to the file->configure->timing dialog. Changing it's label so that it is obvious it is for all internet map downloads, not just Tigermaps. Changing the tigermap_timeout global variable to net_map_timeout to more fully reflect its use. 2005-07-07 18:52 we7u * help/help-English.dat: Updating map caching lingo. Adding more special .GEO file keywords and updating some that were there to match the latest code. 2005-07-07 18:49 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding some strings for map caching controls. Tweaking another string having to do with the map download timeout slider. 2005-07-07 18:47 we7u * README.MAPS: Updating the lingo w.r.t. map caching. 2005-07-07 18:46 we7u * INSTALL: Minor comment change. 2005-07-06 22:38 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c, util.c: Making the curl timeouts track with the tigermap_timeout global variable. Previously they were set to a fixed 30 second timeout. Not enough for slow links. 2005-07-06 20:38 tvrusso * config/tgr2shppoly.dbfawk: Make intermittent water polygons a pale stippled fill. 2005-07-06 18:25 we7u * src/map_geo.c: Added some comments. Made one fprintf only active in debug mode. 2005-07-06 13:35 tvrusso * scripts/Xastir_tigerpoly.py: While trying to understand why my TIGER polygon maps have so many identically-named small polygons, I discovered an error in the Xastir_tigerpoly.py script that was propagated from the original GDAL tigerpoly.py script. The TIGER/Line format has a "Type I" record that links complete chains (Type 1) to "GT-Polygons" through the "POLYIDL" and "POLYIDR" attributes. But according to the TIGER/Line documentation, a Type I record that contains identical POLYIDL and POLYIDR attributes is a line that is internal to a polygon, and should not be included in its boundary. The original tigerpoly.py script from which Xastir_tigerpoly.py was derived simply added all lines with either POLYIDL or POLYIDR to the boundary of polygon POLYID. That means that these internal points were not only incorrectly added to the boundary of POLYID, they were added twice. A simple test to throw away such "PolyChainLink" data (in the OGR parlance, "Type I record" in the TIGER parlance) removes this incorrect assembly of polygon boundaries. This does *not* fix the issue of there being lots of tiny, identically-named polygons in a given area (that's just how the data is), but it DOES correct the "Error in computing fill/hole ring" warnings I've been getting since forever, every time these TIGER/Line-converted polygon shapefiles are loaded. It also fixes the problem I had trying to import these polygon shapefiles into GRASS, which noticed and griped angrily about the topological incorrectness of the data. Unfortunately, taking advantage of this fix would require regenerating all the TIGER polygon shapefiles that are up on xastir.tamu.edu --- probably not worth the effort. But should there be a new round of corrected TIGER data that gets processed, the script is now producing (more) topologically correct shapefiles. It might be a good idea to feed this back to Frank Warmerdam, on whose tigerpoly.py script Xastir_tigerpoly.py was based. 2005-07-06 12:58 we7u * src/: main.h, map_geo.c, map_tiger.c: Adding a parameter to the draw_tiger_map() function, to be used for future implementation in the tiger code for a "refresh map w/o cache" option. 2005-07-06 12:28 we7u * src/: main.h, map_WMS.c, map_geo.c: Added caching for all types of internet maps, disabled by adding a "REFRESH" tag to the .geo file. 2005-07-06 12:27 we7u * src/map_cache.c: Added some bulletproofing and some more debug messages. 2005-07-06 12:26 we7u * src/map_tiger.c: Changed one debug message. 2005-07-06 08:27 we7u * src/map_tiger.c: Adding some comments. 2005-07-06 08:25 we7u * src/map_tif.c: Changing a printf into an fprintf. 2005-07-06 08:22 we7u * src/: hostname.c, main.c, messages.c, sound.c, x_spider.c: Changing some printf's to fprintf's, snprintf's to xastir_snprintf's. Adding timestamp to x_spider messages which are sent to the console. 2005-07-01 15:23 we7u * INSTALL, README.Getting-Started, configure.ac: Adding a "--without-map-cache" flag to configure. Updating docs to match. 2005-06-30 17:12 we7u * src/map_tiger.c: Fixing a compile problem that occurs if ImageMagick isn't installed. 2005-06-30 17:11 we7u * src/map_gdal.c: Removing "static" from the function returns of functions defined inside functions. Evidently the latest GCC enforces that restriction. 2005-06-30 17:09 we7u * README.MAPS, FAQ, README.win32, help/help-English.dat, help/help-German.dat, help/help-Portuguese.dat: Cleaning up some docs w.r.t. Terraserver info. Adding a few more FAQ entries that come up from time to time. 2005-06-30 13:29 we7u * FAQ: Adding a bit about the Terraserver zone-crossing problem. 2005-06-30 13:16 we7u * Makefile.am, terraserver-reflectivity.geo, terraserver-topo.geo, terraserver-urban.geo, terraserver.geo, toposerver.geo, src/map_geo.c: Changed the name of toposerver.geo to terraserver-topo.geo. Added more options for terraserver so that we can use all four options available currently. Put a bit more debugging code and parameter checking code into map_geo.c. 2005-06-29 09:29 we7u * src/map_gdal.c: Putting draw_shapefile_map() between ifdef's, as it isn't defined in some cases (if shapelib isn't available). 2005-06-25 17:46 tvrusso * FAQ: Just copy a FAQ heading into the TOC. 2005-06-25 17:30 tvrusso * src/maps.c: Undo bonehead commit by KM5VY (me). I had mistakenly thought that "draw_filled" was a new map index parameter, and tried to get the index_retrieve_from_file function to set defaults for shapefiles differently. This was an error, as draw_filled has always existed. There is no way to "fix up" the index when running with new code -- the user is simply going to have to go through the map properties and turn Auto on if he/she wants filled shapefiles to respect the dbfawk file's settings. The reason I thought the commit was right was that I was testing it on an index that had been passed through awk to remove the draw_filled variable. It then inserted reasonable defaults, but that's not the point. It's unfortunate that a user with an existing batch of filled shapefiles and dbfawk enabled will wind up surprised that they stopped being filled, but that's the way it is. 2005-06-25 09:02 we7u * src/util.c: A fix for digipeating: valid_path() was adding an asterisk on to the end of wideN-n/traceN-n digi's that had n!=N. This caused unused digi's that were earlier in the path to be skipped in the relay_digipeat() code. For instance a path of "wide1-1,wide2-2" was working, but a path of "wide1-1,wide2-1" was being changed into "wide1-1,wide2-1*", and the wide1-1 digi would be skipped. 2005-06-24 16:09 we7u * src/db.c: Length of temp variable was too short to handle max header length. 2005-06-23 22:55 we7u * src/map_cache.c: Adding a bunch of segfault debug code in order to find a problem that one user is having with map caching of tigermaps. 2005-06-23 13:26 we7u * AUTHORS: Adding Dan Brown to the list. 2005-06-23 13:14 we7u * AUTHORS: Adding Alan Crosswell to the list. 2005-06-23 13:10 we7u * AUTHORS: Adding Tom Russo to the list. 2005-06-23 12:27 we7u * AUTHORS: Adding Derrick to the list. 2005-06-23 09:07 tvrusso * src/maps.c: Fix migration of pre-"auto fill" map_index.sys to new format. 2005-06-22 22:47 tvrusso * src/map_shp.c: Fix broken handling of "auto" shapefile filling. There was a test of "draw_filled" to see if it was set to "auto", but if it was, then draw_filled was changed to whatever the dbfawk file "filled" value was. Since that was always 0 or 1, it meant that every shape after the first one would not have "draw_filled" set to auto anymore, and the entire shapefile would be filled with whatever that first shape's value was (on or off). 2005-06-22 12:47 we7u * src/map_shp.c: Fixing up the default polygon fill condition for when dbfawk file is not present (just a comment change) or for when dbfawk support is not compiled into Xastir, for the case where "Auto" fill is selected. 2005-06-22 12:30 we7u * README.MAPS, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_shp.c, src/maps.c, src/maps.h: Implementing an "Auto" function in the Map Properties dialog for polygon fills. "Auto" will cause a dbfawk file to be used, if it is present. The "Yes" (On) and "No" (Off) filled options that existed before will now override a dbfawk file, so you can use a Shapefile map in three different ways now from the Map Properties dialog. I use this "No" option for instance to make the NOAA Counties Shapefile into a vector map so I can overlay it on top of a raster map, use the "Yes" function to use it as a base map of the U.S., or use the "Auto" function to get all the advanced per-object coloring possible from the dbfawk file, including county names, border colors, etc. The default setting for new Shapefiles will be "Auto". Default for all other types of maps will be "No" or "Off". 2005-06-21 18:15 we7u * src/db.c: Updating some comments. 2005-06-21 18:12 we7u * src/map_tiger.c: Adding set/clear_dangerous() calls to aid in debugging segfaults. 2005-06-21 18:10 we7u * src/: util.c, util.h, map_gdal.c: Moving set_dangerous() and clear_dangerous to util.c/util.h and making them globally available. These routines set/clear a string which gets dumped out upon segfault. A debugging tool mostly. 2005-06-21 13:13 we7u * src/db.c: Moved check for zero unused digipeater fields in relay_digipeat() function down a few lines in the code, to AFTER where we reposition past the destination callsign. 2005-06-21 12:43 we7u * src/util.c: Adding checks for used-up WIDEn-N/TRACEn-N digipeater slots and for maximum total digipeats to the check_unproto_path() function. Max digipeats is only allowed to be as high as MAX_WIDES + 1, no more. For instance, if MAX_WIDES is 4, then "WIDE1-1,WIDE4-4" is legal, "WIDE1-1,WIDE,WIDE4-4", "WIDE5-5", or "WIDE,WIDE,WIDE,WIDE,WIDE,WIDE" are not. 2005-06-21 08:18 we7u * config/nwsc_ddmmyy.dbfawk: Changing back to filled and black border for the counties. It just makes too excellent of a base map at present as-is. Will tweak back to non-filled once the Xastir code is changed to allow overriding that parameter in Map Properties. 2005-06-21 08:09 we7u * config/nwsc_ddmmyy.dbfawk: Reducing the line width for the county borders. 2005-06-21 08:05 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Changing to non-filled. Will soon try to tweak Xastir code so that the filled option can be chosen in the map properties and override the dbfawk setting, so at least the counties file can be selectively chosen to be filled. It makes a good base map sometimes. 2005-06-20 13:34 we7u * src/map_cache.c: A tweak by Dan Brown to help eliminate segfaults in Tigermap caching. 2005-06-20 08:05 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Changing default fill color to dark grey instead of purple. 2005-06-17 07:35 we7u * WMSRadar.geo: Changing a comment. 2005-06-14 14:01 we7u * src/interface.c: Commenting out a debug fprintf statement. 2005-06-14 12:59 we7u * src/: interface.c, interface.h: Adding a #define in interface.h called CONVERSE_MODE. This can be set to "k" or "conv" via different defines to account for different TNC command sets. 2005-06-14 12:39 we7u * src/interface.c: Changed some comments. 2005-06-13 19:45 we7u * config/: Makefile.am, tnc-startup.tnc2: Adding a TAPR-2 style startup file. This one is mostly a copy of the tnc-startup.paccomm file for the moment, but will probably diverge from it over time. 2005-06-10 09:55 tvrusso * src/db.c: Add additional check on wx stations to aloha calculations. APRSDos only checks the symbol for "_", we were only checking if there's any WX data. I was finding that some stations with _ symbols were not being classed as wx stations, apparently because their last posit had no weather or something. Add "_" to the test. 2005-06-09 18:19 we7u * DEBUG_LEVELS: Adding Multipoint to the 2048 level description. Naming the function in main.c that must be changed if more levels are added. 2005-06-08 22:08 tvrusso * DEBUG_LEVELS, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/db.c, src/main.c: Several improvements of ALOHA reporting, as discussed on xastir-dev 1) Change #ifdef DEBUG_ALOHA to a debug level test (2048) 2) Add periodic display of ALOHA range in status line 3) Add a "View->ALOHA Statistics" menu option. Pops up a dialog with ALOHA range, number of stations in ALOHA circle, count of various types of stations, and age of ALOHA calculation. 2005-06-08 09:00 we7u * FAQ: Adding a bit about how to turn off the aloha circle display. 2005-06-08 08:45 we7u * src/main.c: Calculating the Aloha circle even if the feature is turned off. This means that if the feature is turned back on again the circle will be accurate. The processing occurs so seldom anyway that it's not much of a hit. 2005-06-07 22:33 tvrusso * src/map_tiger.c: Fix initialization of local_filename[0] so that gcc 2.95 can compile this file. 2005-06-07 22:16 tvrusso * src/db.c: Fix mistake in logic of aloha_distance() that was letting some oddly configured mobiles to slip through the cracks (those with trackpoints and no speed). 2005-06-07 13:04 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the aloha circle string to "Display" instead of "Disable". 2005-06-07 13:01 we7u * src/: db.c, main.c: Fixing some minor errors in the aloha toggle code. Changing the name of the toggle and callback to be more consistent with the rest of the code. 2005-06-07 12:54 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Adding an option to disable the Aloha Circle. This option is not saved to the config file, by choice. It's intended that the Aloha circle be on the map for the default case so that people might make use of it. The toggle has been added for those rare cases where the Aloha Circle needs to be removed from the screen. 2005-06-07 09:25 we7u * src/map_tiger.c: Reorganization by Dan Brown, n8ysz. This is in preparation for another way-cool feature that Dan is working on. Stay tuned! 2005-06-07 05:33 tvrusso * src/draw_symbols.h: Declare draw_aloha_circle to suppress compilation warnings. 2005-06-06 23:06 tvrusso * src/database.h: Put an ifdef around a struct element only used for debugging. This should cut down on memory use during ALOHA calculation when not debugging. 2005-06-06 22:54 tvrusso * FAQ, src/database.h, src/db.c, src/draw_symbols.c, src/main.c: Feature request 1043058 Add function to display ALOHA circles on the map. ALOHA radius calculated according to Bob Bruninga's alohacir.txt file, and private communications. 2005-06-02 08:27 we7u * README.win32: Adding a note about shutting down applications before updating files. 2005-06-01 13:11 we7u * scripts/Makefile.am: Adding get_shapelib.sh to list of scripts to install. 2005-06-01 13:06 we7u * INSTALL, README.win32: Adding notes about the xastir/scripts/get_shapelib.sh script. 2005-06-01 13:04 we7u * scripts/get_shapelib.sh: Script to get/install Shapelib by Dan Brown, n8ysz. Thanks! 2005-06-01 12:24 we7u * INSTALL, README.win32, src/db.c, src/gps.c: Adding some notes about building Shapelib that Dan Brown came up with. Tweaking the GPS GPGGA and GPRMC comments in the sources. 2005-05-31 19:48 tvrusso * README.MAPS: Remove statement that is no longer true. 2005-05-31 15:25 tvrusso * src/map_tif.c: Make lat/lon rasters subject to same kinds of scan-line-skipping optimizations as UTM rasters have always had. The trick was to realize that "scale_y" has units of "hundredths of seconds per pixel" and that PixelScale in lat/long rasters has the units of "degrees per pixel". 2005-05-31 12:32 we7u * WMSRadar.geo, src/main.h, src/map_WMS.c, src/map_geo.c, src/maps.h: Implementing TRANSPARENT keyword for WMS maps and changing WMSradar.geo to correspond. 2005-05-25 12:12 gstueve * src/alert.c: Fix spelling in comment. 2005-05-25 11:42 we7u * WMSRadar.geo, src/map_WMS.c: Moving the VERSION tag into the .geo file. Some servers are picky about this, so it can't be hard-coded. 2005-05-24 12:49 we7u * src/map_WMS.c: Adding/changing some comments. 2005-05-24 12:21 we7u * src/map_WMS.c: Moving more of the WMS parameters into the .geo file instead of hard-coding them. 2005-05-24 12:20 we7u * WMSRadar.geo: Moving more of the parameters into the .geo file instead of hard-coding them. 2005-05-24 07:23 we7u * WMSRadar.geo: Getting rid of the county outlines in the downloaded image. 2005-05-23 13:16 we7u * src/map_WMS.c: Corected some comments. Turned off debug output. 2005-05-23 12:59 we7u * WMSRadar.geo, src/map_WMS.c: Moving more of the parameters into the .geo file instead of hard-coded (allows more options to be specified via the .geo files). Tweaked the scaling so that the vertical scaling is correct now. 2005-05-23 12:30 we7u * src/util.c: Tweaking the lat/long string conversion routines so they'll handle more input formats. 2005-05-20 07:33 we7u * src/map_WMS.c: Small tweaks to the URL generation for WMS servers. Map registration is not correct yet. 2005-05-19 08:43 we7u * src/.cvsignore: Adding "xastir" as well so that we won't see that in the CVS status listings. It's obviously a derived file. 2005-05-19 08:26 we7u * .cvsignore, callpass/.cvsignore, config/.cvsignore, help/.cvsignore, m4/.cvsignore, scripts/.cvsignore, src/.cvsignore, src/rtree/.cvsignore, symbols/.cvsignore: Adding more lines to the .cvsignore files in order to clean up CVS status listings. 2005-05-19 08:01 we7u * Makefile.am, WMSRadar.geo, src/Makefile.am, src/main.h, src/map_WMS.c, src/map_geo.c: Adding initial support for WMS map formats. This is not complete yet, but the functionality is enough to give a taste for what is possible in the near future. Registration is still a bit off plus we need to add methods for the user to specify layers desired, specifying WMS servers from the GUI, etc. 2005-05-18 12:24 we7u * src/gps.c: Modified parsing of GPGGA and GPRMC NMEA sentences to handle more variations in the sentence structure. 2005-05-18 12:23 we7u * src/db.c: Changing some comments and debug statements having to do with GPGGA and GPRMC NMEA sentence parsing. 2005-05-18 09:41 we7u * src/gps.c: Tweak to the GPGGA parsing to allow a '3' for GPS fix quality. 2005-05-17 13:41 we7u * src/util.c: I've had this patch around for a couple of weeks. It should allow matching on non-numeric SSID's for messaging now, such as "WHO-IS" and "AE5PL-EM", which are the two test cases that broke messaging earlier. It has not been fully tested on RF yet, but appears to work when directly on the internet feeds. 2005-05-09 10:09 we7u * configure.ac, help/help-English.dat: Setting up for further CVS development of Xastir. Changing rev to 1.5.1 to differentiate it from the 1.5.0 stable release. Added a new "What's New in Xastir BETA" section to the help-English.dat file. 2005-05-09 09:34 we7u * README.Contributing, README.Getting-Started, configure.ac, help/help-English.dat: Updating for soon to be done 1.5.0 release. 2005-05-09 09:32 we7u * src/db.c: Spelling fix in comment. No code changes. 2005-05-06 13:59 we7u * src/awk.c: Another tweak by by John Laxson, KC0PZN. This one fixes something that I messed up when I incorporated his first patch. 2005-05-05 12:36 we7u * src/interface.c: Changed one comment. No code changes. 2005-05-05 12:23 we7u * src/awk.c: Tweak by John Laxson, KC0PZN, to speed up dbfawk on MacOSX. Thanks! 2005-05-05 12:19 we7u * README: Getting rid of version number where it's not needed. Will save us some work in the future. 2005-04-29 15:06 kd6zwr * src/interface.c: Fixes for segmentation faults on Solaris. Sending a NULL pointer to a %s argument to any of the *printf() functions (actually strlen() inside it) causes the fault. This patch intializes two vars to "" instead of NULL, {Which is OK!!} protects a function by whacking NULLs into ""s, and moves a debug printf below a NULL check. 2005-04-26 11:24 we7u * src/interface.c: If an interface goes down due to a connection being lost or inactivity, the 1st check_ports() call will bring it back up now. Previously it would wait for the 2nd check_ports() call before bringing it back up. 2005-04-25 12:44 we7u * README.MAPS: Added a paragraph about splitting large Shapefiles into tiles. 2005-04-25 12:44 we7u * README.Getting-Started: Minor changes to a couple of sentences. 2005-04-19 10:39 we7u * src/track_gui.c: Fix by David Flood, kd7myc. Turns of TrackMe button if you leave tracking on but change the call being tracked via the menus. Thanks! 2005-04-17 21:31 rzg * help/help-English.dat: Updated the "what's new", shamelessly ripping parts of curt's release notes because I'm behind in keeping up with CVS. :-P 2005-04-15 10:42 we7u * xastir.spec.in: Adding a few more docs to the doc list. 2005-04-15 10:02 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Changes by Andreas Bier, DL1HRC, to allow setting a tnc2multi into KISS mode via a togglebutton on the interface dialog. We can probably extend this later to put other types of TNC's into KISS mode and/or to take them out of KISS mode when shutting down the interface. I also changed the default for new interfaces to have RELAY/WIDE1-1 digipeat turned off. 2005-04-15 09:30 we7u * README.Contributing: More info about diff's and patching. 2005-04-15 09:01 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changes by Andreas Bier, DL1HRC. Thanks! 2005-04-14 12:38 we7u * README.Getting-Started: Adding more notes about the 2nd-tier servers. 2005-04-14 11:31 we7u * Makefile.am: Adding the new doc into the Makefile structure. 2005-04-14 10:35 we7u * README.Contributing: Adding a document to assist budding developers. 2005-04-13 08:50 we7u * src/util.c: Fixing a path check problem. It wasn't verifying that the char before the '-' was a digit before applying N-n checks to the callsign. 2005-04-12 21:12 we7u * README.Getting-Started: Pointing to a list of 2nd-tier servers instead of suggesting Firenet.us. 2005-04-12 08:50 we7u * help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, src/interface.c: Changing the default path. Changing the docs to match. 2005-04-11 13:07 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys, tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: Changing from RELAY to WIDE1-1 in prompts and TNC startup files. 2005-04-11 12:51 we7u * FAQ, README.Getting-Started: Updating the path discussions to cover the new scheme (WIDE1-1 instead of RELAY). 2005-04-06 12:26 we7u * src/: db.c, util.c: Making the "RELAY" digipeat work with either RELAY or WIDE1-1, per the latest APRSSIG recommendations on how to do paths and digipeating. 2005-04-06 10:03 we7u * src/util.c: Allowing WIDE1-1 as a RELAY type of callsign per the new paradism. 2005-03-31 12:43 we7u * src/: db.c, util.c: Fixes to make the new WHO-IS server work with Xastir. 2005-03-30 09:12 we7u * src/: map_geo.c, map_tiger.c, util.c: Changing text of one type of error message. 2005-03-25 22:33 we7u * README.MAPS: Added a note about a blemish in the Haversine formula we use for distance calculation. 2005-03-25 12:53 we7u * scripts/permutations.pl: Changes to the comments/description. 2005-03-25 12:26 we7u * src/datum.h: Changing some comments. 2005-03-25 09:06 we7u * README.MAPS: Added a summary regarding our distance/angle/area calculations. 2005-03-24 12:25 we7u * src/: datum.h, main.c, util.c: Switching to Gerry-recommended Earth radii plus putting them into central defines in datum.h. That makes them easier to update in the future. 2005-03-23 22:05 we7u * src/main.c: Converting the Measure function from calculating area via planar geometry to computing it using spherical calculations. It should be much closer to reality now, particularly as one zooms out. 2005-03-23 21:57 we7u * src/util.c: Changing some comments. 2005-03-23 21:51 we7u * src/util.h: Making a couple of routines available to other modules. 2005-03-23 12:36 we7u * src/util.c: Converting the distance calculations from using the Law of Cosines for Spherical Geometry to using the Haversine Formula. This should be more accurate for shorter distances, no real change for longer distances. 2005-03-23 09:33 we7u * src/main.c: Bumping the check interval for inactivity from 1 minute to 5 minutes. This means that if we lose an internet connection we might not get it back for between 10 to 15 minutes (instead of the current 2 to 3 minutes), but it also means that server connections won't bounce up and down as much if there are few packets coming down the pipe. One packet every 5 minutes is enough to keep the connection going. 2005-03-22 15:10 we7u * src/util.c: Changed some comments. 2005-03-22 13:11 we7u * src/draw_symbols.c: Added/changed some comments. 2005-03-22 12:38 we7u * README.Getting-Started: Added an enumeration of the various ways of controlling Xastir itself. 2005-03-21 20:57 we7u * src/: database.h, db.c, draw_symbols.c: Fixes for DF objects to make the beamwidths and angles correct. Also fixed the "Unusable" beamwidth so that it still appears as a DF object in the Object->Modify dialog. 2005-03-20 16:33 tvrusso * src/testawk.c: Add initializer for pattern, add variable for label_color, and add appropriate code so that dbfawk files that set label_color can be tested. 2005-03-18 13:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/util.c, src/db.c: Fixing decoding of compressed DF beam objects/items. Fixing the display in Station Info of DF stations. 2005-03-18 12:09 we7u * src/: db.c, main.c: Fixes for varying truncation on object/item comments. We were allowing comments that were longer than 43 chars, which were truncated during later transmits by check_and_transmit_objects_items(). We now no longer allow the extra length packets to be transmitted. The spaces that were added for Pmin/Pmax are now no longer added: that was another cause for the varying truncation of the comment. Fixed the object/item transmit routines so that we can now send compressed-mode for all types. The decode routines now have to catch up. 2005-03-17 13:16 we7u * src/db.c: Better implmentation of my debug tweak that will work with more compilers. 2005-03-17 13:07 we7u * src/db.c: Removing some comments. 2005-03-17 12:30 we7u * src/draw_symbols.c: More work on dead-reckoning to position the ghost symbols and the dashed lines correctly. Have disabled the arcs for now as the positioning is not correct for them with the current code. 2005-03-17 12:28 we7u * src/util.c: Added poor-man's rounding to the places we construct the transmitted lat/long's. This helps with dead-reckoning of symbols at close-in zoom levels. 2005-03-17 12:27 we7u * src/db.c: Added a define and some ifndef's to make some debug easier. 2005-03-17 07:34 we7u * src/map_cache.c: Tweaks by Dan Brown, N8YSZ. 2005-03-17 07:21 we7u * src/database.h: Changed one comment. 2005-03-16 13:36 we7u * src/: igate.c, interface.c, interface_gui.c, location_gui.c, main.c, map_geo.c, map_gnis.c, map_shp.c, map_tif.c, maps.c, util.c, wx.c, xa_config.c: Checking the return codes for scanf/sscanf/fscanf functions. 2005-03-16 12:15 we7u * src/: alert.c, db.c: Checking the return codes of scanf/sscanf/fscanf functions. 2005-03-16 11:34 we7u * src/util.c: A workaround for an sscanf() bug that shows up on Cygwin. It wasn't parsing the lat/long properly in compress_posit(). Re-coded the routine to do everything manually. The other 60 or so places that scanf() and it's variants are used should also be checked for correct operation on Cygwin. 2005-03-15 16:50 we7u * src/util.c: Fix for incorrect compressed packets on Cygwin. Evidently the 'N' in the latitude is getting passed to the routine as an 'n', which causes the problem. The root cause of the problem is probably that the latitude variable is getting messed up sometime earlier. 2005-03-15 11:25 we7u * src/wx.c: Tweaks for Davis WX station by Clay Jackson, n7qnm. 2005-03-14 17:58 we7u * src/: database.h, db.c: Decoding weather from "Position with Timestamp no APRS messaging" packets. 2005-03-14 13:15 we7u * src/: database.h, db.c, main.c: Fixing a bug that crept in while coding some object/item stuff. Moving some comments to a more appropriate place. Commenting out the last_modified_time variable for now, as it's not actually implemented in the dead-reckoning code yet. 2005-03-13 19:11 we7u * src/: database.h, db.c, main.c: Dead-reckoning of objects and items: Working a bit better with this version. We now use the latest DR'ed position when making a change to the object/item. Moving a DR'ed object/item works. One thing that doesn't work now is trying to update the position of a moving object/item using the Modify dialog: The lat/long boxes are ignored now in favor of the DR'ed position. Also note that the on-screen DR function is a bit off in speed and direction from the more accurate function that actually moves the object along. This is yet to be fixed. 2005-03-11 22:38 we7u * src/db.c: Dead-reckoning for compressed objects/items as well. 2005-03-11 22:10 we7u * src/db.c: Better accuracy for the angle calculations for object dead-reckoning. 2005-03-11 21:19 we7u * src/db.c: Transmitting dead-reckoned object/item positions is starting to work in this version. More to do yet, but it could be useful as-is. 2005-03-11 08:45 we7u * src/db.c: Commenting out the code that moves dead-reckoned objects. Not correct yet. 2005-03-11 07:52 we7u * src/db.c: Initial version of dead-reckoning for objects. Dead-reckoned positions are transmitted now at the decaying transmit interval. Still need to do more work on this, like computing the latest dead-reckoned position and transmitting that position at the point an object/item is changed, correcting the disparity between the on-screen DR and the transmitted DR (on-screen DR appears to compute angle based on screen pixels, while the transmitted DR computes angle based on lat/long). The log file is ignored in these changes also: If Xastir crashes or is shut down, time for the DR object will be lost and it will start DR'ing at the point it was last transmitted at before shutdown. 2005-03-10 13:02 we7u * src/: database.h, db.c, main.c: Preliminary work for fixing dead-reckoning of objects/items. More to do yet, but this last_modified_time variable is needed to get started on the problem. 2005-03-08 13:05 we7u * src/main.c: Mods by Dan Brown, N8YSZ. Prevent multiple Xastir's from getting run by a single user. The prevents config files from getting corrupted. 2005-03-08 10:31 we7u * FAQ: Updates by Dan Brown and myself. 2005-03-08 09:16 tvrusso * configure.ac: Fix dummm mistake in help text for --with-rtree 2005-03-03 11:41 we7u * README.MAPS: Added the temporary Wiki location. 2005-03-03 11:39 we7u * README.MAPS: Added a note about the populated places GNIS file. 2005-03-03 09:24 we7u * README: Adding a note about n1ofz's web page and binary Xastir installation. 2005-03-02 11:47 we7u * README: Added a note about gating stations, objects, and items to RF. 2005-03-02 11:41 we7u * src/igate.c: Removing a debug printf that is used for checking out gating to RF. 2005-03-02 09:39 we7u * src/interface_gui.c: Fix for an annoying warning that X11 puts out when you add an interface in Xastir. 2005-03-02 08:56 tvrusso * src/map_tif.c: Comment out warning when a geotiff file has no PCS. Geotiffs without PCS (Projected Coordinate System) tags are assumed to be lat/lon rasters. Now that this capability is being more widely used, especially by users outside the US, this warning is just an annoyance. It was only there because it was once cause to reject a raster if it had no PCS. 2005-03-01 12:55 we7u * src/igate.c: Allowing nws-stations.txt changes to take effect right away for stations being gated to RF. If the file has been changed, the in-memory database gets updated. 2005-03-01 12:32 we7u * src/main.c: Allow re-creating of an object or item that has been killed and is still in the database. Previous code wouldn't allow that and brought up a warning popup. Now the popup happens only if a "live" object/item is in the database with the same name. 2005-03-01 12:05 we7u * src/: igate.h, db.c, igate.c: Igating of specific objects/items to RF is now possible by listing the object or item name in data/nws-stations.txt. The listing is case-insensitive. Putting a wild-card source callsign in that file doesn't get objects/items from that station igated to RF, but other packets from that callsign do get gated. Objects/items have to be specifically listed by name, as the code stands now. 2005-03-01 11:36 we7u * src/db.c: Proper RF gating of objects/items when the originating callsign is specified in the data/nws-stations.txt file. The previous code was incorrect w.r.t. object/item gating. 2005-03-01 09:09 we7u * src/: db.c, igate.c: Initial attempt at gating individual stations through to RF, if those stations are spelled out in the data/nws-stations.txt file. Wildcarding is inherent, so "we7u" will match "we7u", "we7ua", and "we7uaa" through "we7uzz". This change also means that any packets (like posits perhaps) from an NWS station that are not weather alerts will now get gated to RF. Hopefully this won't be a problem. I've left an fprintf() in the code so you'll see which new packets are gated through to RF (prints to STDERR). We'll remove that fprintf() later once we're satisfied with the new operation. 2005-02-28 09:11 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Fixing the selected stations count (on status bar) for dead-reckoned stations. They were getting counted twice, once for the non-ghosted and once for the ghosted symbol. 2005-02-26 18:04 shadow * INSTALL: update imagemagick info 2005-02-24 16:01 we7u * FAQ: Adding instructions for running more than one Xastir at once on the same machine. 2005-02-20 10:07 tvrusso * README: Bring some of the FreeBSD notes up to date. It is no longer necessary to use "gmake" instead of "make" with xastir's build on FreeBSD, and the comments about autoconf versions were very old. Also, change reference to the "current" version 1.1.x of xastir. 2005-02-18 11:38 we7u * README: Changes suggested by Dan Brown, plus another one or two added by me. Fixing mailing list and Xastir link addresses. 2005-02-17 01:14 we7u * src/util.c: Better version of the function which checks the unproto paths as they are entered by the user. This one checks for all the proper relations between the n-N numbers, and limits them to MAX_WIDES (which is set in util.h). 2005-02-16 15:20 tvrusso * src/util.c: Repair check_unproto_path to fix mistakes I'd made in last commit (atoi() on a character rather than string), and rearrange things so that some odd usages in the original code still work. I have not cleaned it up properly. Instances of changing character pointers in a conditional remain as they were in original code, and flagging "bad" paths like "WIDE1-2" results in "Path too long" error message when it should say instead "very strange path". But it will NOT reject paths like WIDE2-1 anymore, and will accept paths like WIDE7-2 (even though the first digit is essentially meaningless when used this way). This time I actually tested these fixes and they work. 2005-02-16 13:38 tvrusso * src/util.c: Simple change to stop "WIDEN-n" where N!=n being flagged as a "Bad Path" Instead, it now checks that N>=n, and only reports "NMessage Traffic window to single-line format, unless the line is long in which case it wraps. 2004-12-22 19:09 tvrusso * src/map_shp.c: Fix for a logic mistake I introduced last night. This might be the source of the unpredictable segfaults I'm seeing at random times hours apart. If not, I'll get that one pinned down ASAP. This was still a mistake, even if it's not the source of those. 2004-12-22 14:56 we7u * src/: database.h, db.c, main.c, main.h: Fixing selected station count so that it updates immediately on the status line if the number changes. Change the "stations" variable to "station_count" to make it easier to grep for in the future. 2004-12-22 14:49 we7u * src/interface_gui.c: Fixing Interface Control dialog so that it looks the same after properties have been changed. It had been missing the up/down designation per port. 2004-12-22 10:07 we7u * src/: main.c, main.h, db.c: Making the selected stations count on the status line update quickly when it changes. 2004-12-22 08:44 we7u * src/main.c: Fixing the Select All button in Map Chooser->Properties so that it doesn't toggle the selections, but actually does what its label says it'll do. 2004-12-21 23:18 we7u * src/db.c: Changes to Group Messages/Queries so that multi-line messages will show in the dialog, and so that messages that don't require ack's don't show up as unacked (highlighted) in the dialog. 2004-12-21 22:48 tvrusso * src/rtree/node.c: Clean up debugging output mistakenly committed. 2004-12-21 22:22 tvrusso * src/: main.c, map_shp.c, maps.c, maps.h, shp_hash.c, shp_hash.h, rtree/node.c: Round of RTree usage optimizations. 1) If a shapefile's bounding box is entirely contained in the current viewport, don't bother doing an RTreeSearch for visible shapes --- just read the file sequentially. Don't even bother accessing the hash table for the file. 2) Store a time stamp every time a shapefiles hash table entry is accessed. 3) Every hour, walk through the hash table and purge records that have not been accessed in 1 hour. (this needs to become a configurable time) This should improve memory usage for a few special use cases, and free up RAM wasted on shapefiles that are not really going to benefit from having the RTree fast lookup. I've not run this for long times to see how the memory usage behaves --- once the RTree is allocated and freed, the processes resident size doesn't seem to drop down, but it does make the space that was freed available for indexing a different shapefile. There are probably many ways to make this even more flexible and automatically adaptive to the users' usage patterns. This should be a good start, though. 2004-12-21 21:08 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.h, src/main.c: The ST_DIRECT stuff appears to be fixed now. This tweak makes the APRS-Direct query work properly again plus adds a selected/total stations display to the status line where there was just total stations listed before. 2004-12-21 19:23 we7u * src/db.c: Another tweak to the ST_DIRECT stuff. This tweak causes us to overwrite the saved path only if 1) the current packet is direct, 2) the ST_DIRECT path is not set, or 3) ST_DIRECT is set but nothing has been heard direct for the last hour. The end result is that we should see the most recent directly-heard path in Station Info, unless the station has not been heard direct for the last hour, in which case we may see a digipeated path or an INET path there. 2004-12-21 17:35 we7u * src/db.c: More work on fixing up the ST_DIRECT flag. 2004-12-21 12:29 we7u * src/: database.h, db.c: Attempting a fix to the ST_DIRECT bit being set incorrectly at times, for stations that straddle both RF and INET feeds. Lots of things were inter-related here, so this may not be the final fix. It should be better than the old code though. 2004-12-20 17:58 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/main.c, src/messages.c: Combining the two Interface dialogs into one dialog. Fixing the Map Chooser->Properties dialog so that it keeps the selected list each time you change something. 2004-12-20 14:14 tvrusso * src/: map_shp.c, shp_hash.c, rtree/index.c, rtree/index.h, rtree/node.c, rtree/split_l.c: Give GCC fewer things to whine about. In each case here where gcc whined about possible use of variables before initialization, code was in place that would always set that variable first. But it was all in conditionals that gcc couldn't possibly know were always true before any use of the variables. Added initializers to shut it up. 2004-12-19 21:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages_gui.c: Fixing transmit of messags so that the three illegal chars (per the spec) cannot be transmitted. We now substitute '.' for any of those three, then alert the operator that we've done so via a popup message. 2004-12-19 18:56 we7u * src/db.c: Added code to check for incorrect case in queries and notify us. This may be used to send a message back to the originator asking them to please follow the APRS spec, or the messages may be ignored. They go to STDERR currently. The same code was added to the unimplemented query sections, but commented out. 2004-12-19 00:44 we7u * src/db.c: Fixing the Station Info dialog so that it will display stations in the Station Chooser dialog +/- 20 pixels in either direction from the mouse pointer. 2004-12-18 17:08 we7u * src/x_spider.c: Adding some returns in the case of a few socket & pipe errors, to get the process to close and not waste CPU on Cygwin. 2004-12-18 13:06 tvrusso * configure.ac, src/Makefile.am: Change configure and makefiles so that if the user does not ask for rtree, the library isn't even built and the -L/-l options aren't used. Not doing this before was just laziness on my part. 2004-12-18 12:43 tvrusso * src/rtree/Makefile.in: Removing something that should not have been committed --- Makefile.in is supposed to be created by bootstrap. 2004-12-18 12:29 tvrusso * src/rtree/sources.htm: Fix up pointers to original source code location and author's web site. 2004-12-17 23:51 we7u * src/shp_hash.c: Fixing up some #ifdef's for the shapefil.h include. 2004-12-17 17:58 we7u * src/x_spider.c: Changing some error messages. 2004-12-17 04:15 tvrusso * configure.ac, src/Makefile.am, src/map_shp.c, src/maps.c, src/maps.h, src/shp_hash.c, src/shp_hash.h, src/rtree/Makefile.am, src/rtree/Makefile.in, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sources.htm, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h: Experimental "RTree" spatial indexing feature. To enable, use "--with-rtree" in configure. Current implementation is very memory intensive, but speeds up rendering of large shapefiles. Needs further work. without the "--with-rtree" option the code behaves as before, all changes are ifdef'd out. 2004-12-16 20:36 we7u * src/x_spider.c: Added a couple of test for a closed pipe or socket. Trying to solve an x_spider problem on Cygwin where we get error messages at the server's STDERR when a client disconnects. 2004-12-16 12:40 tvrusso * src/db.c: Exclude own station from "DIRECTS" reply to APRSD query. 2004-12-15 22:01 tvrusso * src/testawk.c: Minor tweaks to README.MAPS Change testawk.c to remove a feature that uses command line args as a dbfawk program literal --- this is why usages like testawk foo.dbfawk foo.bar (a likely guess at usage) lead to segfaults instead of helpful messages. Change usage string to reflect reality. I hope nobody really used that feature, but it doesn't seem likely, and it was definitely the case that the segfaults were confusing users. 2004-12-15 21:29 tvrusso * README.MAPS, src/db.c: README.MAPS: add a little explanation of how to use testawk (which has the habit of segfaulting on commandlines it doesn't understand) db.c: An attempt to make APRSD (Direct Station Query) responses not be limited to a single line when there are too many direct stations to fit on that line. I have not been able to test the db.c change yet, as I can't hear more than 5 stations directly, so I have to commit this and wait till my partner in crime in Albuquerque can get this update, rebuild xastir, and run long enough to hear a few dozen direct stations so I can query him. 2004-12-15 13:58 tvrusso * config/Makefile.am: Add 24kgrid.dbfawk to list of things to install. 2004-12-15 09:56 tvrusso * config/24kgrid.dbfawk: Adding dbfawk for the 24kgrid shapefile from geocomm.com. 2004-12-15 09:03 we7u * README.MAPS: Added a pointer to the Canadian shapefile street maps. 2004-12-14 20:30 we7u * src/map_tiger.c: Moving the "Loading..." message to below where the variable is initialized which it uses to print. 2004-12-14 13:26 we7u * README.MAPS: Making the IMAGESIZE line requirements more noticeable. 2004-12-14 12:17 we7u * src/: database.h, db.c, main.c: Adding interface numbers to the Incoming Data dialog. "sp" for packet received on the server port (port 2023), 1 or 2-digit numbers for anything else. 2004-12-14 11:39 we7u * src/interface.c: Fixing the double-header problem for packets heading out port 2023. Hopefully this is the last of it. 2004-12-14 08:01 we7u * src/interface_gui.c: Fix to prevent bringing up an interface upon changing its properties. Fix by Dan Brown, n8ysz. 2004-12-12 19:19 tvrusso * src/db.c: Change to look for message ID after *final* "{" in a message rather than first. This improves interoperability with UI-View, which will ack a malformed message like: KB7ZVA-1>APU25N,TCPIP*,qAC,KB7ZVA-1::KM5VY :{Duh{76 (the first { is technically illegal) by acking message 76, whereas prior to this commit xastir would see the message ID as "Duh{7" and do: KM5VY>APX142,TCPIP*::KB7ZVA-1 :ackDuh{7 causing UI-View to ack message 7, and assorted other nonsense. Tested only by having one instance of xastir send a malformed message to another and seeing the ack of the real message ID. 2004-12-12 14:21 tvrusso * config/tgr2shppoly.dbfawk, src/map_shp.c: Make polygon draws respect the "skip_it" step --- until now it was not possible to use the dbfawk variable "display_level" to shut off drawing specific polygons at large zooms. Don't know why I hadn't noticed that all that wasn't working. Now that they're being paid attention to, had to tweak all the display_levels in tgr2shppoly.dbfawk so things show up at reasonable levels. 2004-12-09 18:35 we7u * configure.ac: Fixing the comment so that it is accurate. 2004-12-09 18:32 we7u * configure.ac: Adding a case statement for Cygwin that will change "-O2" compiler flags to " ". This should speed up Cygwin compiling a great deal, at the expense of slightly larger, more inefficent executables. 2004-12-09 12:27 we7u * INSTALL, README.Getting-Started, configure.ac, update-xastir: Making --without-errorpopups be the default. Must add "--with-errorpopups" in order to get the previous operation now. Added some code to configure.ac to remove the "-g" compiler option, so we'll get stripped executables by default now. 2004-12-08 08:57 we7u * src/: gps.c, interface_gui.c: Disabling the time-set togglebutton when running Cygwin. 2004-12-08 06:58 we7u * src/main.c: Finally, a fix for the keyboard modifiers problem, where any modifiers enabled will mess up the mouse menus. The problem turned out to be a Motif 2.x function that doesn't work properly with modifiers. Switching to the Motif 1.x function that accomplishes the same thing fixed it. 2004-12-07 21:45 we7u * src/: map_geo.c, map_tiger.c, util.c: Conditionally compiling various libcurl calls into the code based on libcurl version. 2004-12-07 11:39 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding some currently unused options for libcurl. These are options that were added recently, so only some libcurl versions have them. They have to do with ftp and http proxying. 2004-12-07 10:48 we7u * FAQ: Changed the proxy note a bit. 2004-12-07 09:48 we7u * FAQ: Added instructions for getting through and http proxy server. 2004-12-07 09:32 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding another libcurl option so that it can read the ~/.netrc file. This is needed by those using http proxy servers so they can get through the firewall. 2004-12-07 00:05 we7u * src/: util.c, util.h: Added a new define to util.h so that the maximum WIDE/TRACE digi's can be specified. 2004-12-06 23:16 we7u * src/util.c: Fix to allow multiple specific callsigns in path without Xastir complaining about it. 2004-12-06 22:01 we7u * src/: interface.c, messages.c, view_message_gui.c: Some HP/UX fixes by Dan Brown. Another fix for transmit KISS packets, getting rid of 0x00 bytes between the KISS frames. 2004-12-05 13:46 we7u * scripts/Makefile.am: Added get-gnis to the list. 2004-12-05 13:41 we7u * scripts/get-gnis: Script to snag GNIS files from the download site. Written by Dan Brown, N8YSZ. 2004-12-05 13:20 we7u * src/: map_cache.c, map_cache.h: More good tweaks by Dan Brown, N8YSZ. 2004-12-04 10:05 we7u * README.MAPS: Added a writeup for map caching, courtesy of Dan Brown, n8ysz. 2004-12-04 08:56 we7u * FAQ: Added a bit about the MAGICK_HOME variable. 2004-12-04 08:49 we7u * FAQ: Added Festival debugging info. 2004-12-01 11:45 we7u * src/: messages.c, messages_gui.c: Added some comments. Fixed multi-line messages so that they appear correctly in the Send Message dialog. 2004-11-30 20:34 we7u * src/: database.h, db.c, messages.c: Adding the tries counter to the Send Message dialog. 2004-11-30 14:59 tvrusso * config/tgr2shppoly.dbfawk: Another really minor tweak to tiger polygon shapefile colorings. Looks like there are no easily selected (by CFCC) city boundaries in the files created by Xastir_tigerpoly.py, which makes it impossible to color them with the current dbfawk file. Gonna have to figure that out. 2004-11-30 13:23 we7u * src/db.c: Variable-length non-highlighting for the interval timer value. Lets us keep the line as short as possible yet still do the highlighting in the correct place (the message text). 2004-11-30 13:12 we7u * src/: database.h, db.c, messages.c: Displaying the message timer interval in the Send Message dialog for active messages. 2004-11-30 12:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages.c, src/messages.h, src/messages_gui.c: Updates to messenging. We can now see queued messages before they get to the transmit stage. New button added to kick the timer back to original values (to get a QSO going again). Timer value is currently sent to STDERR, but will eventually be placed into the Send Message GUI as well. 2004-11-30 10:43 tvrusso * config/tgr2shppoly.dbfawk, config/xastir.rgb, src/color.h, src/main.c: changes to coloration of shapefile tiger polygons. Matches online colors a little better now. 2004-11-29 22:56 we7u * src/: map_tiger.c, map_cache.c, map_cache.h: More map caching mods by Dan Brown, n8ysz. 2004-11-29 21:14 we7u * src/messages.c: Getting rid of extra message transmit before timeout. This causes us to transmit exactly MAX_TRIES times, instead of MAX_TRIES + 1. 2004-11-29 12:55 we7u * src/: database.h, db.c, messages.c: Adding a "CANCELLED" indicator to the Send Message box for those messages that made it to transmit from the queue but got manually cancelled by the user. 2004-11-29 11:58 we7u * src/: messages.h, messages.c: More RF-friendly decaying algorithm for messages. We start at 7 seconds and double the interval each time. Timeout occurs at about 2 hours if no ACK received. 2004-11-29 11:37 we7u * src/x_spider.c: Changing from LF to CRLF in lines sent to clients which have connected to the server port. 2004-11-28 10:03 tvrusso * acinclude.m4: Change probe for db.h to use AC_TRY_COMPILE instead of AC_CHECK_HEADER, so that we can apply the same usability test that is present in map_cache.c. 2004-11-27 18:56 we7u * src/x_spider.c: Making sure that lines sent out the server port have "\r\n" at the end. Before we just had '\r', which doesn't correspond to the way the internet servers did it. 2004-11-25 22:10 we7u * README.win32: Completing the GDAL/OGR library instructions for Cygwin. 2004-11-25 17:35 we7u * README.win32: Adding Dave Flood's comments about compiling GDAL/OGR under Cygwin. 2004-11-23 09:19 we7u * scripts/inf2geo.pl: Added usage messages if invoked without parameters. 2004-11-22 08:59 we7u * update-xastir: Adding timestamps and output to make.log for each step. 2004-11-20 22:26 we7u * acinclude.m4: A small change to hopefully make configure find the correct convert.exe on Cygwin/Windows installations. 2004-11-19 22:13 we7u * README.win32: Adding a note about documenting the system variables soas to guard against changes in the future. 2004-11-19 19:15 we7u * README.win32: Adding info at the top about CD installs that are available. 2004-11-19 18:49 we7u * src/: map_geo.c, map_tiger.c, util.c: Backing out a few libcurl options that aren't in earlier libcurl packages. 2004-11-19 11:01 we7u * README.win32: Getting the db libraries listed properly. 2004-11-19 08:26 we7u * update-xastir: Change in a comment. 2004-11-19 08:11 we7u * README.win32: Fixing the order of the Cygwin packages. 2004-11-19 07:20 we7u * update-xastir: Tweaks for Cygwin to eliminate the "sudo" keyword there. 2004-11-18 16:03 we7u * install-xastir: Changing the comments around at the end to simplify things. 2004-11-18 14:16 we7u * install-xastir: Adding more comments at the end. 2004-11-18 13:06 we7u * update-xastir: Adding a couple of command-line options to the cvs update command. 2004-11-18 12:51 we7u * install-xastir: A script to help in the initial install of Xastir via CVS. For those folks challenged by the Unix way of doing things. 2004-11-18 12:29 we7u * README.CVS, README.win32: Updating the instructions with respect to the "update-xastir" script. 2004-11-18 12:23 we7u * update-xastir: Added a comment. 2004-11-18 10:59 we7u * INSTALL, README.CVS, README.win32, UPGRADE, update-xastir: Adding an update-xastir script and tweaking updating instructions a bit. 2004-11-17 10:48 we7u * README: Added HP/UX instructions per Dan Brown, N8YSZ. Current state of HP/UX port is: Segfaults when connected to internet server, but appears to run otherwise. Not fully tested. 2004-11-17 10:28 we7u * src/main.c: Fixing up a return that shouldn't pass back a parameter. 2004-11-17 09:57 we7u * src/main.c: Checking for map interrupts and returning, just before each call to display_file(), which is the function which draws objects/tracks. 2004-11-17 09:46 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding timeouts to libcurl calls. Wget calls already have them. 2004-11-17 09:00 we7u * src/map_geo.c: If ImageMagick is not found, we now refuse to load a .geo map unless "xpm" is found in the filename. 2004-11-17 08:11 we7u * src/: maps.c, maps.h, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, map_dos.c: Setting default map layers based on the type of file. Raster map = 0, vector maps = 1000, GNIS = 99,999. 2004-11-16 14:50 we7u * configure.ac: Reversing the order of the map caching/Imagemagick checks. Just in case. We've had trouble before where if ImageMagick checks fail, they corrupt some of the settings for the other checks, unless ImageMagick is the last of the bunch. 2004-11-16 12:09 we7u * FAQ: Getting rid of "localhost" on the netcat example line. Redundant. 2004-11-16 12:04 we7u * FAQ: Updating the netcat info in the FAQ. 2004-11-16 10:15 we7u * README.win32: Tweaking the library install instructions per David Flood. 2004-11-15 21:05 we7u * src/maps.c: Prevent a segfault when Xastir is having trouble writing the map objects to file. 2004-11-15 10:05 tvrusso * acinclude.m4: Fix of fix for fix of fix of probe for db library. Amounts to removing a comment character from a critical line that I'd accidentally commented out. Without this fix, building xastir on a machine without a db library installed will fail with an error message at link stage about a missing "-ldb". That's because the configure script never reset the LIBS variable after the probe. 2004-11-15 08:52 we7u * src/map_cache.c: Moving more of the includes inside the #ifdef. Including config.h so we get a direct answer as to whether USE_MAP_CACHE is defined before we include anything else. 2004-11-15 08:22 we7u * src/map_cache.c: Moving a couple of includes below the USE_MAP_CACHE #ifdef. Makes it compile on systems that don't have the map caching enabled. 2004-11-13 17:10 tvrusso * acinclude.m4: Handful of changes to improve probe of db for map caching. 1) remove attempts to probe db version 3 libraries, coz the code that uses db actually won't work unless the version is 4 or above. 2) make the probe stop probing when it finds a library that works. Otherwise the probe keeps overwriting the "dblib" variable with "no". 3) comment out the attempt to probe for db_open if db_create isn't found. That would only work if the code that uses db_create were inside appropriate ifdefs, which was probably the case in the package from which the autoconf macro was obtained. 4) Change the comment about "FreeBSD puts this in a weird place" enough to give a reader an idea of where to look. 2004-11-13 16:54 we7u * src/map_cache.c: Moving the #ifdef below the #includes, so that we have a chance of having the USE_MAP_CACHE variable be defined. 2004-11-13 16:12 tvrusso * acinclude.m4, configure.ac: A minor tweak to add "Building with map caching.....: " to the list of things that are printed out at the end of the configuration run. 2004-11-13 06:00 tvrusso * src/map_cache.c: Move the #endif for USE_MAP_CACHE to a place where it actually takes out code that can't compile if USE_MAP_CACHE isn't defined. 2004-11-12 16:40 shadow * acinclude.m4: link against the real libdb we found; use the header path for it we found 2004-11-12 16:17 we7u * README.win32: Adding libdb and libdb-devel as necessary libs. 2004-11-12 15:50 we7u * INSTALL: Adding a blurb about libdb. 2004-11-12 11:31 we7u * README.win32: Added info about NTFS "convert.exe" getting run instead of ImageMagick's "convert.exe". Added instructions written up by Randy, KK6RW, regarding auto-starting Xastir. William McKeehan, KI4HDU, contributed to those instructions and was the inspiration for them. 2004-11-12 10:52 we7u * src/: map_cache.c, map_cache.h: Moving variables to the top of the blocks (for the BSD guys), changing the expire time for maps to 6 months instead of one hour. 2004-11-12 10:47 we7u * src/map_tiger.c: Moving the variable declaration up to the top of the block before those FreeBSD guys get on my case! 2004-11-12 10:24 we7u * acinclude.m4, src/Makefile.am: The final two pieces to enable the new feature, if the Berkeley DB libraries are installed and usable. 2004-11-12 09:17 we7u * configure.ac: Added a comment. 2004-11-12 09:10 we7u * acinclude.m4: A tweak to add "-ldb" to the LIBS line if the DB library is found. 2004-11-12 09:09 we7u * src/: map_cache.c, map_cache.h, map_tiger.c: Adding code that performs caching of tigermaps, courtesy of Dan Brown, N8YSZ. 2004-11-12 09:03 we7u * src/main.c: Preliminary work to include a new map feature. 2004-11-12 08:37 we7u * INSTALL: Adding another link for a list of internet servers, plus a link to the filtering syntax web page. Links courtesy of Rick Green. Thanks! 2004-11-11 09:19 we7u * INSTALL: Updating the GDAL instructions somewhat. 2004-11-10 11:58 we7u * src/db.h: Removing db.h. It has been renamed as database.h. 2004-11-10 11:58 shadow * acinclude.m4, configure.ac: berkeley db configure test. may need slight tweaking for which function it tests for (db_open/db_create/solmething else) 2004-11-10 11:58 we7u * src/: Makefile.am, alert.h, db.c, draw_symbols.c, util.c, util.h, wx.h, xastir.h: Renaming db.h to database.h in order to avoid a conflict with Berkeley DB include file of the same name. 2004-11-10 11:56 we7u * src/database.h: Renaming db.h to database.h, in order to avoid a potential conflict with the berkeley DB include file of the same name. 2004-11-05 15:07 we7u * src/festival.c: Closing the file descriptor for the socket at the point where the Festival connect fails. 2004-11-05 08:57 we7u * configure.ac: Bumping the development sources up to 1.4.2. Just released 1.4.1 stable. 2004-11-05 08:37 we7u * src/: igate.c, util.c: Assuring that we don't igate packets while reading tactical calls in from file. 2004-11-04 12:27 we7u * src/: db.c, igate.c, main.c: Fixing the problem where reading in a log file causes the packets to be igated to the NET. 2004-11-04 10:53 we7u * src/map_gdal.c: Free'ing the hash iterators at the correct points. 2004-11-02 12:37 we7u * src/: hashtable.c, hashtable_itr.c, hashtable_private.h: Tweaks so that the GC_MALLOC/GC_FREE defines apply to the hashtable code as well. 2004-11-02 07:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c: Making the transmit and Interface->Properties long-path warning messages different. 2004-11-02 07:19 we7u * src/util.c: Changing one variable so that it local to where it is used instead of at the top of the routine. Changed flags to be counting flags instead of booleans, so we can later use them to count digipeater types. Added some comments. 2004-11-01 12:34 we7u * src/util.c: Tweaking the path-check code so that trace,wide2-2 and wide,wide2-2 paths and similar are allowed. 2004-11-01 09:11 tvrusso * configure.ac, src/util.c: Add probe for strndup to configure.ac. Ifdef use of strndup in src/util.c. strndup is a GNU extension and not portable to non-GNU systems. strdup is portable, so is used if strndup isn't available. 2004-10-30 14:13 we7u * src/: interface.c, interface_gui.c: Adding path checks to the igate path. 2004-10-30 14:01 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding another string for igate path checking. 2004-10-30 13:23 tvrusso * README.win32: Add note to section on installing libproj and libgeotiff. Both of these libraries are now available directly through cygwin setup, simplifying the installation. 2004-10-30 12:06 we7u * src/interface.c: Adding the path check code into each posit and object/item transmit, at the spot where the unproto path is selected. This probably needs to be added to the igate path code as well. 2004-10-29 13:15 we7u * src/interface_gui.c: Another tweak by Ryan Butler, KB0JQO, to check UNPROTO paths on more types of interfaces. 2004-10-29 13:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/util.c, src/util.h: Tweaks by Ryan Butler, KB0JQO, to check the unproto paths on interfaces for excessively long paths. Performs the path checks when you hit the OK button on the Interface->Properties dialog. 2004-10-29 08:53 we7u * src/map_gdal.c: Enabling tiger polygons for normal use. Tweaked the code so that the polygon reassembly only gets done if we have "filled" enabled for that map. 2004-10-29 07:53 we7u * src/map_gdal.c: Experimentally derived at better hash sizes (twice the max size needed for any county in the state of WA). Correct code now for free'ing the landmark hash. Sped up the TLID linked list code, but still testing that to make sure the polygons are made correctly (it reverses the order that the line segments are added to the geometryCollection). 2004-10-28 22:14 we7u * src/map_gdal.c: More tweaks to the tiger code. Still not enabled for general use. 2004-10-27 10:03 we7u * src/map_gdal.c: First working version of Tiger polygon code. #ifdef'ed out of the compile at present. 2004-10-27 10:02 we7u * src/Makefile.am: Adding the hashtable files. 2004-10-27 09:58 we7u * src/: hashtable.c, hashtable.h, hashtable_itr.c, hashtable_itr.h, hashtable_private.h: Adding generic hashtable functions. 2004-10-26 23:24 we7u * src/map_gdal.c: Starting to draw some filled polygons for Tiger maps. Still not ready for prime-time so the code is still disabled by an #ifdef. 2004-10-26 22:44 we7u * src/map_gdal.c: More Tiger polygon code changes. The code is generating polygon geometries from the tiger data now, so the next step is to start drawing them. 2004-10-26 19:55 we7u * src/map_gdal.c: Implementing hash functions for the Tiger polygon code. Still #ifdef'ed out, so it won't get compiled in currently. 2004-10-23 20:38 tvrusso * README.MAPS: Mention the Xastir_tigerpoly.py script in the place where this file previously said that shapefile conversion of TIGER/Line data didn't contain polygon features. 2004-10-23 15:24 we7u * src/main.c: Fixing the segfault caused by closing the Map labels font dialag before closing xfontsel. Had to put in a couple of "xfontsel_query = 0" statements in the callbacks for the Map labels font dialog. 2004-10-22 08:25 we7u * src/map_gdal.c: Added some debug code. It's not enabled currently. 2004-10-21 19:54 we7u * src/map_gdal.c: Added much of the code needed to reconstruct the Tiger polygons. The new code is commented out right now as it's not quite complete and it really slows things down as well. Optimization will happen AFTER the code is working. 2004-10-21 12:45 we7u * src/map_gdal.c: Changed some comments. 2004-10-21 12:28 we7u * src/map_gdal.c: Changed one variable name from i to ii (easier to grep for). Added some comments. 2004-10-21 01:55 tvrusso * config/tgr2shppoly.dbfawk: Don't display name of feature if it is "None" (what some fields output by Xastir_tigerpoly.py get, a feature inherited from tigerpoly.py -- haven't figured out why). 2004-10-21 01:51 tvrusso * config/Makefile.am, config/tgr2shppoly.dbfawk, scripts/Makefile.am, scripts/Xastir_tigerpoly.py: Add python/OGR script to generate polygon shapefiles from TIGER/Line data. Add dbfawk file to make them look less ugly than if there weren't one. Putting this in CVS merely to get it out there for community hackage. 2004-10-20 21:19 we7u * src/map_gdal.c: Added some comments. 2004-10-20 14:30 we7u * src/: geo-find.c, geocoder_gui.c: Find Address works again. 2004-10-20 12:37 tvrusso * src/map_gdal.c: Fix mid-function declarations to allow compilation by gcc 2.95. 2004-10-20 09:42 we7u * src/map_gdal.c: Changes to comments only. 2004-10-20 08:37 we7u * src/map_gdal.c: More messing with water layers. Nothing major. 2004-10-19 19:17 we7u * src/map_gdal.c: Commenting out the "Loading" message. 2004-10-19 18:13 we7u * src/map_gdal.c: Shapefiles are working again in GDAL. 2004-10-19 11:36 we7u * src/map_gdal.c: More color and line tweaks. This change probably disables Shapefiles, but SDTS and TIGER/Line files display properly now. 2004-10-19 09:02 we7u * src/map_gdal.c: Moving all of the color code into the guess_vector_attributes function. Later we'll be able to convert this function into our map preferences system once that is fully defined. Added color to the SDTS files. 2004-10-19 07:45 we7u * src/map_gdal.c: Faster determination of layer name. 2004-10-18 22:22 we7u * src/map_gdal.c: Starting to support proper color scheme for SDTS-format maps. At least have contours in yellow and other layers in black now. 2004-10-18 21:08 we7u * src/map_gdal.c: Fixing OGR indexing so that the transform is invoked every time. Required for UTM/State-plane maps. 2004-10-18 13:17 we7u * src/maps.c: Changing default Shapefile translator back to Shapelib. 2004-10-18 13:09 we7u * src/map_gdal.c: Truncating the points better. Was truncating at 0 for negative values, which doesn't work. We just need to keep away from the +16000/-16000 points and greater, which invoke X11 drawing bugs. Truncating at zero creates dummy lines along our top and left window borders. 2004-10-18 12:58 we7u * src/map_gdal.c: Very weak attempt at detecting hypsography and hydropraphy SDTS files to decide to color them yellow, keyed off "HY"or "HP" anywhere in the full filename (that's why it is weak). Other SDTS maps get colored black currently. 2004-10-18 11:57 we7u * src/: bulletin_gui.c, db.c, list_gui.c, main.c, main.h, map_gdal.c, maps.c, util.c, view_message_gui.c, wx_gui.c, xa_config.c: Changing the name of a global variable. Tweaking elevation for SDTS contours so that they are in the correct units. 2004-10-18 09:39 we7u * src/map_gdal.c: Outputting the correct label on elevations now from SDTS files. Later will try to switch it to match the setting of the Enable English Units togglebutton so that we can get a consistent display. 2004-10-18 07:55 we7u * src/map_gdal.c: Added some notes. No code changes. 2004-10-15 21:25 we7u * src/map_gdal.c: Changing text from "ft" to "m" for elevation. SDTS file appear to have elevation in meters. Also changing back to yellow for the contour lines as it is highly visible whereas the white/gray is not in many cases. 2004-10-15 12:24 we7u * src/map_gdal.c: Default coloring for raw Tiger/Line maps. 2004-10-15 09:27 we7u * src/map_gdal.c: Repositioning labels slightly. Fixing segfault caused by earlier "skip" option. 2004-10-15 08:36 we7u * src/map_gdal.c: Changing to lighter colors again for contours and their labels. They need to show up on top of terraserver images. Brown doesn't cut it. Changed the contours to gray80 and the labels to white. 2004-10-15 07:56 we7u * src/map_gdal.c: Changing to brown for the contours and corresponding labels. Closer to the USGS topo map colors. 2004-10-15 07:44 we7u * src/map_gdal.c: Drawing more labels along each object. Tied to zoom level so that we reduce the quantity of labels as we zoom out. 2004-10-15 07:22 we7u * src/map_gdal.c: Setting a few hard-coded default colors from some types of map objects. Later we'll redo this so that the preferences come from a file. Re-enabled code that dumps out the layer information. Added elevation display for SDTS-format DLG contours. 2004-10-14 21:12 we7u * src/map_gdal.c: Several fixes. Spatial filtering now works properly. 2004-10-14 12:52 we7u * src/map_gdal.c: Simplified some of the code. Have SDTS contours working again, but have a problem with those files and spatial filtering yet. This version works but puts out error messages to STDERR with SDTS files. 2004-10-13 23:05 we7u * src/map_gdal.c: Sped up GDAL maps: Implemented the spatial filtering mechanism inherent in the library. We now filter using our viewport as the bounding rectangle, which really speeds things up as you zoom in. 2004-10-13 22:57 we7u * src/maps.c: Fix for draw_vector function. It now rearranges the bottom/top/left/right if it's called with things out of order, before calling map_visible. This gets fewer vectors rejected due to being off-screen/more vectors actually get drawn. 2004-10-12 08:34 we7u * src/map_gdal.c: Fixing up debug messages. Sending weather alerts off to the draw_shapefile_map function for now. 2004-10-11 19:11 we7u * src/map_gdal.c: Nicer labels for OGR plus rotation. 2004-10-11 13:12 we7u * src/map_gdal.c: Slight reformatting. No code changes. 2004-10-11 13:06 we7u * src/map_gdal.c: Labels for OGR point files as well. Untested. 2004-10-11 12:56 we7u * src/map_gdal.c: Initial labels for OGR vector maps. Not colored yet, not rotated, but better than nothing, which is what we had before! 2004-10-11 12:15 tvrusso * src/map_tif.c: Add some error messages to the "geoTIFF file not in proper format" block, so the user can see what is actually wrong with the file. 2004-10-11 09:27 we7u * scripts/: toporama250k.pl, toporama50k.pl: Tweaking one comment that gets written out to the .geo files. 2004-10-10 12:16 tvrusso * src/testawk.c: Fix mistake in font_size output --- make sure appears on correct line. 2004-10-10 12:01 tvrusso * src/testawk.c: Add "font_size" variable to those that are read and output by testawk. testawk still lags significantly behind xastir in what it reads and outputs. 2004-10-08 11:33 we7u * scripts/: toporama250k.pl, toporama50k.pl: Oops. Changing copyright to correct one. 2004-10-08 11:31 we7u * scripts/: toporama250k.pl, toporama50k.pl: Adding copyright and licensing info. 2004-10-08 11:20 we7u * scripts/: Makefile.am, toporama250k.pl, toporama50k.pl: Scripts to snag Canadian toporama map files and create .geo files for them. Created mostly from code submitted by Adi Linden, VA3ADI. 2004-10-07 19:15 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Making a few more warnings go to popups instead of STDERR. Fixing object/item code so that you can't create a new object/item that has the same name as another station/object/item in the database. 2004-10-07 14:43 we7u * src/: db.c, geocoder_gui.c: Removing some white space. 2004-10-07 10:16 we7u * src/main.c: Fixing another Xt call that should have a NULL at the end. 2004-10-07 09:29 we7u * src/main.c: Slightly better check_range() function. This one snaps the left/right of the map to the left/right of the display in most cases. Still more work to do before I'll be satisfied with the operation though. 2004-10-07 08:44 we7u * src/main.c: Tweaking check_range() so that it doesn't allow us to zoom out beyond the N/S poles. It will resize the Y scale factor so that it fits the window perfectly N/S. More work will probably be done on this function later so that we fit E/W perfectly as we zoom out as well (depending on the window's aspect ratio). 2004-10-07 08:14 shadow * src/: db.c, main.c: update calls to XrtVaGetValues to terminate with NULL 2004-10-06 22:45 we7u * src/main.c: Minor tweak to how center/zoom is calculated. Check for edge of earth now. May be more tweaks to come for this part of the code. 2004-10-06 22:17 we7u * src/main.c: Tweaking a few more minor GUI things for Map View object creation. 2004-10-06 21:44 we7u * src/main.c: Computes proper range now when creating Map View objects. 2004-10-06 20:28 we7u * src/db.c: Fixing transmit of objects/items so that they send out PHG or RNG as the first parameter in the comment field. 2004-10-06 17:15 we7u * src/main.c: Fixing the language command-line switch. Initial implementation of the code for creating Map View objects (not complete yet). 2004-10-05 22:17 shadow * src/awk.c: awk_find_sym can return NULL; don't assume src->type is valid. 2004-10-05 17:20 shadow * config/tgr2shp.dbfawk: dd missing double-quote in FENAME default case handling 2004-10-05 10:11 we7u * src/: db.c, main.c: Fixing the Move Object function so that we can only move objects that we already own. Any SSID will work. If we don't own it, we have to adopt the object first before we can move it. This keeps us from accidentally moving objects if we accidentally leave the Move function on and then click/drag on the map display. 2004-10-05 08:54 we7u * Makefile.am: Adding a new Texas radar geo file. 2004-10-05 08:54 we7u * TXRadar.geo: Adding a new geo file for Texas radar, contributed by Gerry Creager. 2004-10-04 22:12 we7u * src/db.c: Fixing a typo in extract_powergain_range() which caused it to skip parsing PHG strings. 2004-10-04 13:20 we7u * FAQ: Adding another link for the remote serial port stuff. 2004-10-04 12:58 we7u * src/db.c: Reducing the number of positions displayed in Station Info from 100 to 50. This is in order to speed up the automatic updates version of the Station Info dialog. 2004-10-04 12:25 we7u * FAQ: Adding links to the serial port redirectory programs, courtesy of Mike Fenske. 2004-10-04 10:17 we7u * src/wx.c: Fixing the 000/360 wind course problem. We should now transmit "360" when the wind direction is 0, as the APRS spec requires. 2004-10-04 10:16 we7u * README.CVS: Adding a note about the "wheel" group and sudo. 2004-10-04 09:20 we7u * FAQ: Adding info regarding connecting to remote serial ports. 2004-10-04 09:17 we7u * README.MAPS: Adding a link to the national transportation atlas map files, link provided by Derrick J Brashear. 2004-10-04 08:32 we7u * src/xa_config.c: Changing default fonts to be non-italic. A bit more readable. 2004-10-03 12:46 we7u * configure.ac: Small tweak to avoid a conflict with a similarly-named define in the GDAL library. 2004-10-03 00:04 we7u * src/testawk.c: Giving up on this file for now in terms of compiling with strict error-checking. 2004-10-02 23:17 we7u * src/interface.c: Fixing a few more problems that were found by compiling with strict error-checking. 2004-10-02 22:43 we7u * src/: interface.c, testawk.c, x_spider.c: More tweaks from compiling with stronger error-checking. 2004-10-02 22:19 we7u * src/main.c: Fixing up a few things found by running with these compile flags: "-g -O2 -pipe -Wall -pthread -Wpointer-arith -W -pedantic" 2004-10-02 21:58 we7u * src/: db.c, draw_symbols.c, geo-find.c, hostname.c, map_shp.c, map_tif.c, maps.c, util.c, wx.c, x_spider.c: Fixing up a few things found by running with these compile flags: "-g -O2 -pipe -Wall -pthread -Wpointer-arith -W -pedantic" 2004-10-02 11:08 we7u * src/: draw_symbols.c, locate_gui.c, maps.c, messages_gui.c, testawk.c, xastir.h, main.c: Tweaks to get rid of compiler warnings on 64-bit CPU's. Fixing up mostly casts to/from pointers and int's using some macros from the FreeCIV project to help us. 2004-10-01 09:19 we7u * README.CVS: Adding "sudo" instructions. 2004-09-29 09:04 tvrusso * src/map_shp.c: Repair broken stippling of filled polygons under dbfawk. Before this commit, stippling was set too early in the code and not turned off before label drawing began, rendering map labels for stippled polygons unreadable. 2004-09-29 00:10 tvrusso * README.MAPS, src/map_shp.c: Add "fill_stipple" dbfawk variable, and support for it. Now, if a dbfawk file sets filled=1, fill_style=2, and fill_stipple={0,1,2}, the filled polygons will be stippled instead of solid. fill_stipple=0 gives 13% stipple fill_stipple=1 gives 25% stipple fill_stipple=2 gives 50% stipple. "fill_style=2" corresponds to FillStippled per XSetFillStyle. 2004-09-28 14:53 gstueve * src/messages.c: Add check for DOS EOL markup. 2004-09-28 11:01 we7u * FAQ: Added a bit about NumLock/ScrollLock/CapsLock messing up Motif programs, and one way to solve it. 2004-09-28 08:40 we7u * src/db.c: Fixing Station Chooser dialog so that it expands properly. It used to increase the size of the buttons instead of increasing the size of the station window. 2004-09-27 09:49 tvrusso * FAQ: Add FAQ entries for autoconf-related FAQs. 2004-09-27 08:04 tvrusso * Makefile.am: Return "dist-bzip2" to the AUTOMAKE_OPTIONS variable. it is true that --dist-bzip2 is not a valid automake option, but the AUTOMAKE_OPTIONS variable doesn't generate --options for automake, it has an effect on the generated makefile itself. In this case, dist-bzip2 adds a dist-bzip2 target to the makefile. As far as I can tell, the folks who are having trouble with this option are not in fact using automake 1.6.3 or later. In ha2vr's case it turned out he was actually using automake 1.4, even though automake 1.9 was supposedly installed on his system. 2004-09-26 17:29 tvrusso * Makefile.am, acinclude.m4, bootstrap.sh: Per discussions on xastir mailing list: - remove "dist-bzip2" from "AUTOMAKE_OPTIONS" in Makefile.am. - Fix underquoted AC_DEFUN of AC_CHECK_GMTOFF Also, add a print statement to end of "bootstrap.sh" so it's clear when it's finished successfully. 2004-09-24 14:16 we7u * src/wx.c: Fixing the offsets and data length for the Peet Complete-mode wind speed fields. 2004-09-24 12:42 we7u * src/main.c: Commenting out some debug code. 2004-09-24 12:42 we7u * src/util.c: Removing some dead code from the compressed posit routine. 2004-09-24 12:35 we7u * src/db.c: Fixing symbol drawing so that Map View objects "range" circles aren't drawn. Fixing compressed posits so that csT bytes are always removed when decoding. Adding "Current Range:" output to Station Info dialog. 2004-09-24 12:32 we7u * src/draw_symbols.c: Reducing the size of the wind barbs as we zoom out. 2004-09-24 12:30 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added range output to Station Info dialog. Added missing tactical call string to some language files. 2004-09-24 09:49 tvrusso * src/db.h: Remove DOS line terminators. Reformat long lines. 2004-09-23 20:29 we7u * src/: db.c, main.c, main.h: This change implements decoding for Map View "eyeball" objects. 2004-09-22 13:00 we7u * src/main.c: Adding a bit more output to the "time has reversed" fprintf's. We now dump out the number of seconds we went backwards and the date/time of the event. 2004-09-22 12:25 we7u * README.CVS: Added a note about autoconf and automake. 2004-09-20 12:15 we7u * src/x_spider.c: Another tweak to allow multiple spaces between "pass" and the passcode. 2004-09-20 12:10 we7u * src/x_spider.c: Fixing user/pass login in the Server code so that both of them are position-independent. 2004-09-19 19:29 tvrusso * src/main.c: Add the base file name to the dbfawk file for downloaded GPS tracks and routes. This allows the name of the track to be displayed along with the line data when these files are used outside of the GPS directory. I forgot to add this component of the data in in my first commit. 2004-09-19 16:52 tvrusso * README.MAPS: A little cleanup of the discussion involving "gdalwarp." 2004-09-19 16:39 tvrusso * README.MAPS, src/map_tif.c: This is a patch I've been using for several months now: it allows xastir to use geotiff files that are already unprojected lat/lon maps. It simply checks the "PCS" key in the geotif file, and if it's not there then the file is assumed to be in lat/lon and can be used as is without transformation. It has no effect on maps that are not already in lat/lon, and so will be invisible to anyone who hasn't needed the ability to read in unprojected geotiff files. README.MAPS updated to explain that gdalwarp can be used to convert maps into lat/lon unprojected maps. Also added a place to find useful geotiff maps that need such conversion (FAA sectionals from aviationtoolbox.org). Tweaked the stuff on shapefile reprojection. What was there were verbose snippets from an email exchange between Curt and me. Made them a bit shorter and more to-the-point. The importing of lat/lon geotiff files is significantly slower than the importing of USGS quads, because the optimized reads that skip over scanlines based on zoom level don't work. I intended to figure out how to make them work, but never did the work. If folks start using this a lot and get me to bump it up in priority I can revisit it. 2004-09-19 15:50 tvrusso * config/Makefile.am, config/gps_wpt.dbfawk, src/main.c: config: New DBFAWK file for waypoints files downloaded through GPSMan. Now, DBFAWK- enabled xastir will display names of waypoints next to the symbol, no matter what directory they're put in. Add gps_wpt.dbfawk file to makefile. src: make xastir write out a simple dbfawk file to go along with GPSMan track and route shapefiles. Prior to this, these files would only display in the selected color if they were copied into /usr/local/share/xastir/maps/GPS, and would display in all black if they were anywhere else. Unfortunately, because we have no control over the fields created by GPSMan for these shapefiles, it is not possible to stick the color itself into the dbf file, as Alan had suggested in various comments in the code. To use these new things: for waypoints, do nothing -- the dbfawk file is generic and applies to any GPSMan waypoint file. For tracks and routes: Make sure to copy the dbfawk file when you copy the shapefile and dbf file to a maps directory. Xastir will use it. For tracks and routes downloaded prior to this patch: the dbfawk file is simple, just copy one for a map of the same color. 2004-09-18 13:30 we7u * src/map_shp.c: Fixing the "Loading" and "Indexing" messages so that they don't overrun our limited real estate on the status line. 2004-09-18 13:25 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_tif.c, map_tiger.c: Fixing the "Loading" and "Indexing" messages during map activity so that they don't overrun our limited real estate on the status line. 2004-09-17 13:44 we7u * src/interface.c: Increasing the wait time in the loop where we're connecting up network interfaces. Was 20ms, now 250ms. 2004-09-17 12:56 we7u * src/: fcc_data.c, geocoder_gui.c, locate_gui.c, location_gui.c, map_gnis.c, rac_data.c, track_gui.c: Bypassing the new configure flag with a few more popups that are user-requested. 2004-09-17 12:46 we7u * src/: main.c, popup_gui.c, xastir.h: Tweaks so that a few of the popups will continue to display in that manner (instead of heading to STDERR). 2004-09-17 12:22 we7u * INSTALL, README.Getting-Started, acinclude.m4, configure.ac, src/popup_gui.c: Implementing the "--without-errorpopups" configure flag. If invoked, popup_messages() writes to STDERR instead of causing a popup dialog to appear. 2004-09-17 10:12 tvrusso * src/main.c: Put Cygwin-specific setting of nexttime into the UpdateTime function. Remove the two Cygwin-specific usleep(2) from the end of UpdateTime. With these changes, running xastir on Cygwin under Win2K on a 2GHz machine went from taking up 90+% of the CPU to taking around 20% --- most of that in system processes, and mostly that high when X events are being processed. 2004-09-16 12:31 we7u * configure.ac: Bumping the revision to 1.4.1, as we just did a stable release at 1.4.0. 2004-09-16 07:47 we7u * src/xa_config.c: Changing default sound command from "vplay" to "play" as it is much more common. 2004-09-16 07:00 tvrusso * src/map_gnis.c: Quick, trivial commit both to make sure I'm set up right and to remove a slightly annoying error message when I'm looking at New Mexico with GNIS: Add "ruin" as a recognized gnis entry type. Ideally, this mapping of gnis entries to zoom level limits should be in metadata rather than a large if/elseif/elseif... block, but that's another issue. 2004-09-15 13:19 we7u * src/db.c: Re-ordering "if" statements to speed things up slightly. 2004-09-15 12:59 we7u * src/db.c: Another speedup (lower CPU usage). 2004-09-15 12:44 we7u * src/alert.c: Reducing CPU usage of normal_title(). 2004-09-15 12:43 we7u * src/db.h: Slowing down minimum object timing by another five seconds. Reduces how often we look through our database, keeping CPU usage down. 2004-09-15 10:08 we7u * src/db.c: Swapping two "if" statements in a loop, as the is_my_call() function appears to be faster than the boolean operations to determine whether it's an object/item. 2004-09-14 12:32 we7u * src/db.c: Making is_my_call() and check_and_transmit_objects_items() more efficient. Found during profiling that these routines were eating up CPU. 2004-09-13 19:50 we7u * INSTALL, configure.ac: Adding the "--with-profiling" flag. Updating docs to reflect it. 2004-09-13 12:56 we7u * src/map_shp.c: Changing label storage to a hash table instead of an array, to speed things up. Using the first character of the string as the hash index. Tried using lower 7 bits of first two chars, and lower 6 bits of first two chars: Profiling showed that using the first character was faster. 2004-09-13 12:54 we7u * src/rotated.c: Moving math into appropriate parts of loop to speed it up. Anything that is static through all iterations of a loop is moved outside that loop for speed. 2004-09-10 16:09 we7u * src/draw_symbols.c: Implementing a cache for the most recent five symbols used. Speeds up drawing by quite a bit (found by profiling). 2004-09-10 12:26 we7u * src/main.c: More speedups found by profiling. Checking for new gps map only once per second now, updating the stations count on the status line once per second instead of continuously. 2004-09-10 09:19 we7u * src/main.c: Adding some Cygwin-specific usleep's in UpdateTime() in order to reduce CPU usage on those systems. 2004-09-10 08:49 we7u * src/awk.c: Sped up awk_find_sym() a bit. 2004-09-10 08:37 we7u * src/rotated.c: Sped up font rotation by moving some floating-point math outside the inner loop. 2004-09-10 08:27 we7u * src/alert.c: Fixing a minor compiler warning. 2004-09-09 20:37 we7u * src/maps.c: Fixing a bug I introduced earlier today while speeding up map indexing. 2004-09-09 12:59 we7u * src/maps.c: Speeding up the maps.c:index_retrieve() function. Making it more efficient. Perhaps the next step would be to turn it into a hash lookup, but that would require changing perhaps several other routines to match. 2004-09-09 09:11 we7u * README.Getting-Started: Adding another note about callpass. 2004-09-09 08:06 we7u * INSTALL: Adding another note to the profiling section. 2004-09-08 20:43 we7u * src/alert.c: Major speedup in weather alert code, found through profiling. 2004-09-08 12:22 we7u * INSTALL: Adding a section on checking for memory leaks. 2004-09-08 10:48 we7u * INSTALL: Adding profiling instructions. 2004-09-07 14:40 we7u * FAQ: Added a bit about MacOSX USB adapters, courtesy of Jeff Wigal, WY7Q. 2004-09-07 14:06 we7u * src/util.c: Changing format for time so that Cygwin can understand more of it. Tweak courtesy of Henk de Groot. 2004-09-07 10:15 we7u * README.Getting-Started, README.win32: Tweaking the notes about GPSMan/gpsmanshp. 2004-09-07 08:39 we7u * src/festival.c: Adding some usleep() function calls for the case where we can't open a socket to Festival, so that we don't spin our wheels too fast trying to open sockets. 2004-09-06 21:06 rzg * help/help-English.dat: Done the body, just "whats new" section left. 2004-09-06 18:44 we7u * src/main.c: Fixes for the Filled and Automaps columns in Map Chooser->Properties dialog. 2004-09-04 23:24 rzg * help/help-English.dat: Updating helpfile some more, still have last 1/3rd to go over and "whats new" section to write. FIXMEs up for grabs; and if anyone otherwise wants to help let me know. 2004-09-03 08:16 we7u * src/db.c: Drawing symbol after we draw circles and other items. Trying to keep the text on top so that it is more readable. 2004-09-02 22:37 we7u * src/db.c: Moving the weather info to the top of the Station Info dialog, for the cases where we have weather info stored. The weather info is the most important info for that station in that case, so it should be readable without scrolling. Stations without weather data are unaffected by this change. 2004-09-02 20:19 we7u * src/db.c: Fixed a small bug in positionless weather decoding where it wasn't decoding course/speed fields. We now take another look for course/speed if either of them are empty. Before both of them had to be empty before we tried another type of parsing for them. Did the and->or conversion in several places in extract_weather(), so the change affects more than just positionless weather packets. 2004-09-02 13:58 we7u * config/language-Dutch.sys: Another tweak from Henk & Han. 2004-09-02 11:36 we7u * config/language-Dutch.sys: More mods by Henk. 2004-09-02 10:51 we7u * FAQ: Updating the locale-specific answers. 2004-09-02 10:45 we7u * src/main.c: Fixing the locale for numbers to "C". We require this in order to be able to write and parse our config files and .geo files properly when the LC_NUMERIC or LANG environment variables are set to something else. This affects the printf and scanf sorts of functions. 2004-09-02 07:49 we7u * src/: main.c, xa_config.c: Bumping the max timeout for tigermaps from 120 to 180 seconds since so many people are getting timeouts with it. 2004-09-01 12:34 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM, and Henk de Groot, PE1DNN. Thanks! 2004-09-01 10:51 we7u * README.Getting-Started, configure.ac: Bumping to the next release number, 1.4. 2004-09-01 08:37 we7u * config/language-Spanish.sys: A few translations by Charles Twardy. Thanks! 2004-08-31 11:56 we7u * config/language-Dutch.sys: Updates by Henk de Groot, PE1DNN. Thanks! 2004-08-31 11:05 we7u * help/help-English.dat: Minor tweaks to descriptions about object timing. 2004-08-31 10:30 francais1 * config/language-French.sys: Updated 2004-08-31 09:52 we7u * config/language-Portuguese.sys: Updates by David Quental, CT1DRB. Thanks! 2004-08-31 09:46 we7u * src/db.c: Tweak which helps to prevent parsing of weather fields out of comment data. 2004-08-31 09:08 rzg * help/help-English.dat: Updating helpfile for release, about 1/3rd done. 2004-08-31 07:40 we7u * config/language-Italian.sys: Updates by Alessandro Frigeri, IK0YUP. Thanks! 2004-08-30 08:49 we7u * src/interface.c: Adding a terminating zero to the AGWPE packets in port_read() instead of in parse_agwpe_packet(). 2004-08-30 08:28 we7u * src/interface.c: Adding a string terminator to the end of the AGWPE raw packets before we start processing them. This keeps portions of previously received packets from getting appended to our current string during our processing. 2004-08-30 07:38 we7u * README.win32: Changing to Henk de Groot's optimized Festival install instructions. 2004-08-28 15:43 we7u * README.win32: Added Festival instructions for Win32 courtesy of Tom Russo. Thanks! 2004-08-27 13:09 we7u * src/main.c: Fix for high CPU-usage when time skips backwards. This fix causes Xastir to sleep a bit in the UpdateTime() loop until time catches up again, thereby avoiding the problem. It also dumps a message out to STDERR as it goes into/out of this mode. 2004-08-27 07:44 we7u * src/map_gdal.c: Changed the gdal output on startup to show only those map formats that have been enabled in Xastir AND are supported by the GDAL library that we're compiled against. 2004-08-27 07:16 we7u * config/language-German.sys: Tweaks by Rolf Bleher, DK7IN. Thanks! 2004-08-26 18:07 shadow * configure.ac: update libgeotiff/libtiff/libproj configure tests such that 1) libproj is checked for only once 2) libtiff is used if found when testing for libgeotiff revised test from Tom Russo KM5VY and tested on MacOS X and Linux. 2004-08-26 14:03 we7u * src/db.c: Fixing the code so that snow can be parsed out of a weather report only if course/speed has already been parsed/deleted from the string. 2004-08-26 11:09 we7u * src/alert.c: Fix for high-CPU bug when malformed NWS weather alert packet is received. 2004-08-25 12:45 we7u * src/db.c: Fix for truncated lines when using AGWPE or Serial KISS TNC interfaces. 2004-08-25 12:40 we7u * src/interface.c: Changed comments. No code changes. 2004-08-25 12:39 we7u * src/main.c: Changed a comment. No code changes. 2004-08-24 18:59 we7u * scripts/: Makefile.am, kiss-off.pl: Adding a kiss-off script to take a TNC out of KISS mode. 2004-08-24 18:53 we7u * src/: main.c, db.c: Fixing the object/item comment-field bug. 2004-08-23 21:47 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/messages.c, src/messages.h, src/messages_gui.c: Changing the label on the Clear Messages button, adding a new button for deleting the outgoing messages to that station, relocating the buttons to the bottom row. 2004-08-23 12:48 we7u * README.Getting-Started: Added notes about where to look for instructions for other OS'es. 2004-08-22 11:39 we7u * src/main.c: Changed one comment. 2004-08-21 17:01 we7u * src/: db.c, util.c, util.h: More fixes for xastir_snprintf size parameter, including adding a size parameter to a few other functions that can be used to prevent overrunning strings. 2004-08-21 16:55 we7u * src/wx.c: Reformatting of code and rechecking the size parameter for xastir_snprintf function calls. 2004-08-20 23:48 we7u * src/wx_gui.c: Reformatting some code. 2004-08-20 23:35 we7u * src/: view_message_gui.c, x_spider.c: More cleanup of the size parameter for xastir_snprintf calls. 2004-08-20 23:13 we7u * src/: db.c, geocoder_gui.c, gps.c, hostname.c, igate.c, interface.c, maps.c: Cleaning up the size parameter for a bunch of xastir_snprintf calls. 2004-08-20 13:50 we7u * src/db.c: Fix for bad longitude for your own station. 2004-08-20 11:38 we7u * src/db.c: Fixing problem with truncated comment/status strings. Was setting the length in the xastir_snprintf() call to the length of the pointer instead of the length of the malloc'ed string buffer. 2004-08-20 10:27 we7u * src/maps.c: Added a comment. 2004-08-20 10:25 we7u * src/: awk.c, geo-find.c: Reformatting of geo-find.c. Added comment to both files. 2004-08-20 10:22 we7u * src/db.c: Moving ptr into the block where it is used. 2004-08-20 10:19 kd6zwr * src/db.c: Moving a declaration up to the top to allow it to be compiled. 2004-08-20 09:52 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Reducing the resolution on the snow reports, as they are only reported by inch, not by 100's of an inch. 2004-08-19 21:06 we7u * src/: alert.c, awk.c, db.c, geo-find.c, igate.c, interface.c, messages_gui.c, util.c, view_message_gui.c, wx.c, x_spider.c: More on the strcat/strcpy/strncpy reduction/elimination. I think this finishes off all the strcat/strcpy calls, and there are only 24 strncpy calls left in the code. 2004-08-19 13:10 we7u * README.Getting-Started: Attempting to answer the question: "Why must I compile from sources?" 2004-08-19 12:54 we7u * Makefile.am: Adding the new README.Getting-Started into the installation scripts. 2004-08-19 12:48 we7u * README.Getting-Started: Spellling fix. 2004-08-19 12:45 we7u * README.Getting-Started: First checkin. Fairly complete. 2004-08-19 12:38 we7u * src/: alert.c, bulletin_gui.c, db.c, dbfawk.c, gps.c, gps.h, hostname.c, hostname.h, igate.c, interface.c, interface_gui.c, location_gui.c, main.c, map_shp.c, map_tiger.c, messages_gui.c, rotated.c, view_message_gui.c, wx_gui.c: More work to eliminate strcat/strcpy/strncpy from the code. 2004-08-18 23:45 we7u * src/: map_tiger.c, maps.c, x_spider.c: More strcat/strcpy fixes. Changing to safer string-handling routines. 2004-08-18 23:38 we7u * src/: db.c, interface.c, main.c, map_dos.c, messages_gui.c, popup_gui.c, rac_data.c, sound.c, track_gui.c, xa_config.c, location_gui.c, alert.c, datum.c, draw_symbols.c, fcc_data.c, festival.c, geocoder_gui.c, gps.c, igate.c, list_gui.c, locate_gui.c, map_geo.c, map_gnis.c, messages.c, util.c, wx.c, map_shp.c: More strcat/strcpy fixes. Changing to much safer string-handling routines. 2004-08-18 23:31 we7u * src/: geo.h, gps.h, main.h, messages.h, wx.h, xastir.h: strcat/strcpy fixes. Changing to much safer string-handling routines. 2004-08-18 13:35 we7u * src/: alert.c, fcc_data.c, hostname.c, igate.c, interface_gui.c, locate_gui.c, map_geo.c, map_shp.c, maps.c, messages.c, messages_gui.c, util.c, x_spider.c: Converting more strcat() function calls to strncat(). Safer. 2004-08-17 21:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/list_gui.c, src/maps.c, src/wx.c: Changed wx_snow to be inches instead of 1/100 inch. We now ghost the weather info (mostly) separately from posit info. Got rid of "
" from track logs read in from findu.com. Fixed realloc's in maps.c so that they won't cause a memory leak if they fail. Fixed Peet Bros. complete mode decoding so that the proper wind speed is parsed. Fix by Matt Werner, kb0kqa, for the 3-hour barometric pressure reading for Peet Bros. complete mode parsing. 2004-08-17 17:17 we7u * src/main.c: Changed formatting, added comments. No code changes. 2004-08-17 09:41 we7u * src/wx.c: Fix for 3-hour barometer with Peet U2000 in complete mode. Still testing to see if this is the proper fix, but so far it looks good. 2004-08-16 17:51 we7u * src/db.c: Fixing the "Move" function so that you can drag/drop objects/items that are right on top of each other. The selection dialog will pop up so you can choose which one to move. 2004-08-14 09:43 we7u * src/main.c: Fixing object/item generation so that a space is prefixed to the comment field only in the case where multipoint polygons are present. The space is necessary in order to parse multipoint objects properly, but is not desired for other objects/items where it would limit the extent of the comment. 2004-08-12 17:26 we7u * src/map_gnis.c: Update to GNIS search code for new pipe-delimited file format that the USGS is distributing. 2004-08-12 17:25 we7u * INSTALL, README.MAPS, help/help-English.dat: Updates to the docs to match new RINO, Server Port, and other interface changes that were done recently. 2004-08-12 13:46 kd6zwr * src/x_spider.c: Moved some declarations up to the top of Server(). Inline decls cause problems on some compilers... (like my gcc 2.96 under linux). 2004-08-12 13:00 we7u * src/map_gnis.c: Updating the GNIS map code to handle the latest pipe-delimited files from the USGS. Still need to update the search code, but the display code appears to work fine now. 2004-08-12 10:03 we7u * src/interface.c: Added some debug code for tracking down errant raw packets in the AGWPE code. 2004-08-11 13:15 we7u * src/main.c: A bit of reformatting, plus sending to the x_spider server after raw packets have been converted to TAPR-2 format packets. 2004-08-11 10:40 we7u * src/: main.c, x_spider.c: Tweaks by Tom Russo for FreeBSD compatibility. Thanks! 2004-08-10 19:16 we7u * src/: hostname.c, main.h, sound.c, x_spider.c: More fun with process naming. 2004-08-10 12:59 we7u * src/x_spider.c: Added a note about future plans for process naming. 2004-08-10 12:51 we7u * src/: main.c, x_spider.c, x_spider.h: Code that changes the process name in "ps" listings for the x_spider daemon and client connections. Doesn't work on other operating systems, and doesn't work for "top" listings. 2004-08-09 11:32 we7u * src/x_spider.c: Disabling the Nagle algorithm and enabling SO_KEEPALIVE for the server port connections. 2004-08-07 11:12 we7u * src/interface.c: Modified AGWPE parsing routine and associated code. We've now turned off "monitor" mode and turned on "raw" mode in AGWPE. The "raw" packets get thrown into our standard KISS decoding routines, which gives us the possibility of supporting OpenTrac (a binary protocol) and digipeating on AGWPE ports in the future. The "monitor" mode decoding has been left for now, but later on we'll probably delete it. Also: Added output to STDERR for the AGWPE server version and for the port descriptions. 2004-08-06 12:57 we7u * src/db.c: Change to comment. No code changes. 2004-08-06 09:29 we7u * src/interface.c: Minor changes to comments and debug output messages. 2004-08-05 13:02 we7u * src/: db.c, festival.c, main.c, interface.c, sound.c, util.c, util.h: Re-wrote the agwpe parsing code. It should be more bulletproof now, but still has some debug stuff in it for NWS_ and NWS- messages. Fixed a segfault caused by one of the new strncpy() functions that I switched to in util.c:spell_it_out(). 2004-08-04 13:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the Modify Object/Item dialogs so that you must adopt an object/item that you don't own before you're allowed to delete it. Adopting or Modifying someone else's object causes you to transmit it as a live object owned by you. After that, you may delete it. If the client that previously owned it saw your live object, it'll know that you own it and that you can delete it. Without this adoption process, UI-View32 clients will hold on to an object that you're trying to kill. 2004-08-04 12:07 we7u * help/help-English.dat: Tweaking the note about AGWPE network authentication. We can use that now. 2004-08-04 11:54 we7u * src/: interface.c, interface_gui.c: Fixes for AGWPE. Network loging with authentication should work now. 2004-08-03 14:21 we7u * src/db.c: Fix to allow objects/items to get through the server port and get igated. 2004-08-03 13:04 we7u * src/util.c: Small tweak to valid_inet_name() where it is checking for the "aprsd" string. It didn't appear to be general enough to catch all possibilities. Now it should be. 2004-08-03 12:57 we7u * src/db.c: Changed one sizeof() to a strlen() for emergency messages. Fixing object/item timing intervals so that if the timing slider is reduced, the max interval is reduced for already existing objects as well. 2004-08-03 12:42 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the displayed label for the object/item timing. It's a max interval now. The actual timing is under the control of an exponential decay algorithm. 2004-07-30 16:15 we7u * src/util.c: A fix for the csT bytes on compressed posits. Turns out we need to send the spaces, and the compressed posit field is a fixed length. 2004-07-30 15:24 we7u * src/db.c: Adding some debug output. 2004-07-29 21:06 we7u * src/sound.c: Replacing strcpy function with safer ones. 2004-07-29 21:02 we7u * src/: list_gui.c, locate_gui.c, location_gui.c, map_tif.c, map_tiger.c, maps.c, messages_gui.c, rotated.c, track_gui.c, util.c, view_message_gui.c: Replacing strcpy functions with safer ones. 2004-07-29 20:57 we7u * src/: color.c, color.h, dbfawk.c, draw_symbols.c, fcc_data.c, geo-find.c, geocoder_gui.c, hostname.c, igate.c, interface_gui.c, lang.c: Getting rid of strcpy functions. Replacing them with safer functions. 2004-07-29 17:02 we7u * callpass/callpass.c: Geting rid of strcpy() function call. 2004-07-29 14:15 we7u * src/db.c: Changed some strcopy() functions to xastir_snprintf() functions. 2004-07-29 13:48 we7u * src/util.c: Reformatting to match the rest of the code. No actual code changes. 2004-07-28 22:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.h, src/xa_config.c, src/db.c, src/main.c: Adding CWOP WX station filtering toggle. Letting Xastir display wind speed when wind course is not available. 2004-07-28 12:17 we7u * src/: db.c, igate.c, x_spider.c: Fixing message igating through x_spider connects. 2004-07-28 10:48 we7u * src/x_spider.c: Fix for FreeBSD courtesy of Tom Russo. Thanks! 2004-07-26 17:08 we7u * src/: db.c, x_spider.c: Per-client authentication for the x_spider listening port. Printf's for each client connect/disconnect, and each successful authentication. Non-authenticated clients can talk to each other and the server, and can receive data from the server, but can't sent anything through the server. Igating must also be turned on to get data from authenticated clients up to the internet connections. 2004-07-26 16:57 we7u * symbols/symbols.dat: Adding the new Rocket symbol that Bob. B. just added to the spec. 2004-07-26 16:55 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kam, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Reenabling the CWID stuff. Some countries evidently require it. 2004-07-26 14:02 we7u * src/x_spider.c: Changing the authentication comments slightly for x_spider. 2004-07-26 13:59 we7u * src/x_spider.c: Adding client authentication to the x_spider server. Clients cannot send data upstream until they authenticate. Clients can still receive data without authenticating or send data to other connected clients. 2004-07-26 13:57 we7u * src/util.c: Removing unused define. 2004-07-26 12:39 we7u * config/tnc-startup.sys: Adding another CWID command that will turn off that feature for some TNC's. 2004-07-26 12:21 we7u * config/: tnc-startup.paccomm, tnc-startup.pico: Correct CWID commands for Paccomm TNC's. 2004-07-26 11:49 we7u * config/: tnc-startup.kpc2, tnc-startup.kpc3: Correct commands to turn off CWID. 2004-07-26 11:44 we7u * config/tnc-startup.kam: The correct command for turning of CWID. 2004-07-26 11:16 we7u * config/tnc-startup.kam: Turning off CWID. 2004-07-26 10:04 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Adding "CWID off" command. 2004-07-25 07:19 rzg * help/help-English.dat: Updated the list of new features. 2004-07-24 15:49 we7u * src/: db.c, igate.c, interface.c, main.c, util.c: Tweaking the server stuff so that connected clients get igated through the "master" Xastir instance if igating -> Net is enabled. 2004-07-23 09:57 we7u * src/db.c: Ignore case when comparing newly received comment/status strings with previously received ones, to decide which ones to throw into the list. With a case-sensitive compare, we were getting two instances of similar comment/status strings cluttering up our lists, when it was really the same info being presented but in a different case. 2004-07-23 09:31 we7u * src/main.c: Cygwin fixes by KJ5O. Thanks! 2004-07-22 19:31 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h, src/x_spider.c, src/xa_config.c: GUI support for the new server port. 2004-07-21 18:56 we7u * src/: Makefile.am, db.c, igate.c, interface.c, main.c, main.h, x_spider.c, x_spider.h: Adding a listener socket for multiple clients. Currently this must be enabled by uncommenting a #define near the top of main.c. Adds a listening socket at port 2023 which allows any number of clients to connect. Spawns a listener for each active client, kills them when the client disconnects. All packets received or transmitted by Xastir go to these clients, all packets sent by the clients are received by Xastir and by all of the other connected clients. "telnet localhost 2023" to test out the functionality after compiling in the server support. 2004-07-21 11:38 gstueve * src/view_message_gui.c: Add macro so someone's comment can be answered. Don't try to put too many arguments into a fixed array. 2004-07-20 11:41 we7u * src/db.c: Sorting and display of status/comment records by date/time. 2004-07-20 11:14 we7u * src/db.h: Bumping max status/comment lines per station from 10 to 20. Am testing with 50 locally to see whether bumping it up more will seriously affect memory usage. Depending on the results, may bump these numbers up even more. 2004-07-19 19:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/x_spider.c: Adding date/timestamps to Status and Comment records. 2004-07-19 14:17 we7u * src/: alert.c, alert.h, db.c, db.h: Moving a couple of define's to the .h files and increasing the number of alerts and messages that we allocate when we run out. This hopefully will help to keep the number of large allocations down plus keep the larger allocations from ending up at the very end of the heap. If we keep a small increment, we realloc() more often plus the large blocks will end up closer to the end of the heap, meaning we won't be able to reduce our memory impact much later. 2004-07-19 09:13 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Adding "HID off" where it was missed. Some TNC's may require slightly different commands for this. I don't have them to test with so I'll have to wait for users to let me know the proper commands. 2004-07-16 11:27 we7u * configure.ac, src/alert.c, src/db.c, src/main.c, src/map_gdal.c, src/xastir.h: Adding support for "libgc", which is a Boehm-Demers-Weiser garbage collection library. The advantage for us is that it can find/report memory leaks. Install it, then add "--with-libgc" to the configure line to compile it in. It will report memory leaks on the console. This patch fixes two leaks found by libgc, plus changes the increments used for relloc'ing alerts and messages. 2004-07-15 14:32 we7u * src/: awk.c, db.c, dbfawk.c, igate.c, main.c, map_gdal.c, map_shp.c, maps.c, rotated.c: Protection for malloc/calloc/realloc calls. Checking the return value for non-NULL. 2004-07-15 13:01 we7u * src/maps.c: Added some comments. 2004-07-15 12:58 we7u * src/: alert.c, db.c, igate.c, messages.c: Added/changed warning messages when realloc's fail. 2004-07-15 10:26 we7u * src/main.c: Reuven found a missing #ifdef for the RINO stuff. Thanks! 2004-07-15 10:16 we7u * src/messages.c: Reformatting to take out tabs. 2004-07-15 10:09 we7u * src/db.c: Changed some debug code that is used to test expire times for messages and stations. 2004-07-15 08:29 gstueve * src/messages.c: Make sure to look for Special groups and safety check group names. 2004-07-14 14:07 we7u * FAQ, INSTALL, acinclude.m4, configure.ac: Motif detection tweaks by Tom Russo. 2004-07-14 12:48 we7u * src/db.c: Reformatting and comment changes. No code changes. 2004-07-14 12:13 we7u * src/db.c: Better code for drawing callsign at each trackpoint. This draws the callsign at every single point. 2004-07-14 09:31 we7u * src/main.c: An attempt to fix the menu GPS Status so that it works. Still need an expiration mechanism for the data here. 2004-07-14 09:29 we7u * FAQ: Added an LDD note, inspired by Jack Twilley. 2004-07-13 14:02 we7u * src/db.c: Comment changes. 2004-07-13 12:21 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added a new button to the Station Filter dialog: "Label All Points". Doesn't actually label _ALL_ trackpoints, but labels most of them with the callsign. This is helpful to identify whose tracks belong to who. 2004-07-13 07:54 we7u * src/: alert.c, db.c, db.h, list_gui.c, main.c, main.h, messages.c, messages.h, messages_gui.c, track_gui.c, util.c: Combined MAX_CALL and MAX_CALLSIGN defines into MAX_CALLSIGN, reduced the size of it from 20 chars. Added MAX_COMMENT_LINES and MAX_STATUS_LINES, currently set to 10 each, which limit how many unique status/comment lines are saved per station. Added MAX_TACTICAL_CALL in order to separate that parameter from MAX_CALLSIGN, as the tactical call needs to be longer but didn't want to waste the memory for all callsigns by making them all long. Changed the alert memory allocation from 100 alert blocks to 25 alert blocks (finer grained malloc's). Added more comments. 2004-07-09 14:11 we7u * src/main.c: Throwing Base-91 Compressed APRS packets into our decoding instead of standard APRS packets. This keeps the resolution that the RINO's are capable of. Doesn't affect how the Object packets are transmitted: For that setting refer to the toggle on the File->Configure->Defaults dialog. 2004-07-09 10:32 we7u * src/main.c: Better timestamp for RINO-derived APRS Objects. Issues: currently sends localtime instead of UTC, plus the gpstrans files we're getting the timestamp from appear to have the download time/date instead of the waypoint creation time/date. These need to be fixed at some point. 2004-07-09 08:19 rzg * src/alert.c: Fixed read of unitialized data according to valgrind. 2004-07-08 16:34 rzg * src/main.c: Fixed comparisions of unitialized variables, and another small bug. 2004-07-08 14:49 we7u * src/main.c: Initializing some variables as they are defined. 2004-07-08 14:49 we7u * src/map_geo.c: Added some comments. 2004-07-08 14:48 we7u * src/interface.c: Reformatting. No code changes. 2004-07-08 14:48 we7u * src/draw_symbols.c: Initializing a variable as it is defined. 2004-07-08 12:38 we7u * src/main.c: Commenting out RINO debug fprintf() statements. 2004-07-08 12:07 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Implemented auto-download capability for the RINO waypoints. A new slider added to the File->Configure->Timing dialog. A setting of 0 disables the function. Anything else invokes GPSMan at the interval selected, downloading all waypoints from a RINO, and creating APRS objects out of those that have "APRS" as the beginning four characters of the waypoint name. 2004-07-08 08:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Initial support for Garmin RINO "contact" waypoints. A new entry on the Interface menu allows snagging waypoints from a RINO. Any that begin with the letters "APRS" will have those four letters removed and then a standard APRS object is created from them and starts transmitting out from Xastir over APRS. We're using non-compressed Objects so that they will be visible on Kenwood displays, at the expense of throwing away some of the position resolution. The menu link-in may change, as we'll eventually go to an automatic poll scheme of the RINO instead of this manual operation. Currently requires a connected RINO on a serial port and GPSMan support compiled into Xastir. 2004-07-07 11:15 we7u * INSTALL: Tweaked the instructions for GDAL ever so slightly. 2004-07-07 09:30 we7u * configure.ac: Added a comment from Tom Russo. We need to make some changes to the Motif detect so that we're assured we have working headers/libraries before we get to the compile stage. 2004-07-06 15:29 we7u * configure.ac: Replacing our Motif search code with better code from the "vim" project. This code is purported to find the most recent variant of Motif on the system and use that, if there's more than one on the system. It also looks quite a few more places for the libraries/headers than our old code. 2004-07-06 11:23 we7u * src/main.c: Added comments. 2004-07-02 13:19 we7u * src/locate_gui.c: Fixed one printf format that had too many format specifiers in it. 2004-07-01 17:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/gps.c, src/gps.h, src/main.c: Adding GPS Quality info to the command line and to a new View->GPS Status option. 2004-07-01 14:33 we7u * src/xa_config.c: Setting more reasonable lower defaults for a couple of timing parameters. 2004-07-01 14:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/locate_gui.c: FCC/RAC callsign lookup which doesn't depend on stations being on the screen. 2004-07-01 09:26 we7u * src/bulletin_gui.c: Fix by Tom Russo for FreeBSD. 2004-06-30 22:00 we7u * src/maps.c: Converting from a strcpy() to a memmove() due to another bug that Reuven found. strcpy() cannot handle overlapping strings, while memmove() can. 2004-06-30 21:16 we7u * src/main.c: Fixing memory leaks. 2004-06-30 21:13 we7u * src/db.c: Fixing memory leaks. 2004-06-30 21:09 we7u * src/: messages_gui.c, track_gui.c, view_message_gui.c: Fixing memory leaks. 2004-06-30 21:05 we7u * src/: list_gui.c, locate_gui.c, location_gui.c, messages.c: Fixing memory leaks. 2004-06-30 21:00 we7u * src/interface_gui.c: Fixing memory leaks. 2004-06-30 20:55 we7u * src/: bulletin_gui.c, geocoder_gui.c: Fixing memory leaks. 2004-06-30 14:00 we7u * src/db.c: Fixing a bug Reuven found: Doing an "if" based on the value of an uninitialized variable. 2004-06-30 13:53 we7u * src/db.c: Fixing an indexing bug that Reuven found (via "valgrind"). We can't go past index 0 if we've assigned '\0' to a string. 2004-06-30 13:36 rzg * src/: color.c, dbfawk.c, main.c: Minor memory leak fixes. 2004-06-30 13:32 we7u * src/list_gui.c: Fixing a memory leak that Reuven discovered. 2004-06-30 12:43 we7u * src/db.c: Fixing a bug found by Reuven in the GLL decode routine. 2004-06-30 10:54 we7u * src/: db.h, db.c: Moved multipoints into a separate record, allocating only when needed. This provides additional memory savings over the tweaks that went in yesterday, with no loss in speed/efficiency. 2004-06-29 20:45 we7u * src/: db.c, db.h: Tweaks to significantly reduce memory usage. 2004-06-29 12:42 we7u * src/wx.c: Fixing all the 2^16 constants. Ten of them were incorrect. 2004-06-29 11:41 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added language strings for CAD objects and tactical calls. 2004-06-28 09:56 we7u * src/main.c: Added a comment. No code changes. 2004-06-27 17:15 rzg * src/main.c: Fixed array size error, to fix stack smashing issue. 2004-06-25 16:24 we7u * config/: Makefile.am, tnc-startup.tnc2-ui, tnc-stop.tnc2-ui: Start/stop TNC files contributed by Alessio Sangalli, IW2NYD, for the TNC2-UI TNC used in Europe. 2004-06-24 14:23 we7u * FAQ: Added a bit about ImageMagick and color-depth. 2004-06-24 13:49 we7u * src/: db.c, main.c: Adding some debug stuff to the expire code. Tweaking the status line station readout so it will reflect the current number of stations in all cases. 2004-06-24 13:08 we7u * src/main.c: Erasing box after Measure operation. 2004-06-24 13:00 we7u * src/: db.c, main.c: Removing tac-call capability for objects/items. The saving/restoring of these on startup is a problem. Perhaps we can add the functionality back in later for these, but probably only if we own the objects/items ourselves. Even then, deleting the objects/items needs to be looked at carefully. 2004-06-24 12:29 we7u * src/: db.c, db.h, main.c, util.c: Fix for Move function. Also changed tactical call so that it takes up less memory. 2004-06-23 16:19 we7u * src/main.c: Rearranging the Station menu slightly so that it is harder to delete all stations by mistake. It's now at the bottom of the menu. 2004-06-23 12:54 we7u * src/main.c: Adding a define, commented out currently, which sets all flags properly for a 640x480 touch-screen. Has no effect unless comments are removed. 2004-06-23 12:25 we7u * src/: interface.c, main.c: Backing out the changes that were just made for the Serial TNC Aux GPS interface. Turns out the code was right all along. The user that is experiencing difficulties with a KAM+ must have some other sort of problem. 2004-06-23 11:10 we7u * src/interface.c: Serial TNC AUX GPS interfaces weren't parsing GPS data out of the datastream. This should fix it. More testing to come. 2004-06-23 11:05 we7u * src/main.c: Comment changes. 2004-06-23 10:30 we7u * src/main.c: Changing one debug printf() 2004-06-22 13:44 we7u * src/main.c: Fixing the code so that the SWAP_MOUSE_BUTTONS #ifdef works properly again. 2004-06-22 12:36 we7u * src/db.c: Adding tactical call button to Station Info dialog. This is required for cases where multiple calls are near the pointer, else we can't assign tactical calls. 2004-06-22 10:41 we7u * src/db.c: Fixed a memory leak in the expire routines, where status data was not getting free'd. 2004-06-22 10:20 we7u * src/db.c: Fixing bug in expire code introduced by newly-added tactical call code. 2004-06-21 14:10 we7u * src/: db.c, main.c, main.h, xa_config.c: Adding a toggle flag for selecting only stations with tactical callsigns. 2004-06-21 11:03 we7u * src/: db.c, util.c: Restoring of tactical calls from file when Xastir starts up or after all stations are cleared. Dummy records are created which then get coupled to the real info when the station gets heard on the air. Also tweaked the expire code so that stations with tac-calls don't get expired. They should still get cleared from the screen, but the station and all it's original data, including tac-call, should appear again when the station re-appears on frequency. That new addition to the expire code is not tested fully yet. 2004-06-21 09:08 we7u * src/: db.c, main.c, util.c, util.h: Logging of tactical calls to disk. Added Clear Tactical Calls and Clear Tactical History menu options. Restore of tactical calls from disk at startup is not coded yet. 2004-06-18 22:24 we7u * src/db.c: Adding the callsign or the object/item name as a label in the Assign Tactical Call dialog, so that we know what we're renaming. 2004-06-18 13:32 we7u * src/db.c: Instant update when changing a tactical call. 2004-06-18 13:01 we7u * src/db.c: Minor tweaks to the tactical call stuff. Allows 19 chars now for the name. 2004-06-18 12:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/main.c: Implementing Tactical Calls. Added to the right-click mouse menu. 2004-06-18 10:09 we7u * src/interface.c: Comment changes. 2004-06-18 10:07 we7u * src/interface.c: Mostly comment changes. Added "Counts" to the generic measurements table ( units[] ). 2004-06-18 08:46 we7u * src/interface.c: Changing some comments. 2004-06-18 08:38 we7u * src/interface.c: Minor comment change. 2004-06-18 08:35 we7u * src/interface.c: Minor tweaks to the OpenTrac classification messages. 2004-06-18 08:24 we7u * src/interface.c: Adding in catch-all clauses for OpenTrac elements that are new or not-yet-implemented. 2004-06-18 08:03 we7u * src/interface.c: Putting in more dummy routines for the unimplemented OpenTrac element decoding. 2004-06-18 07:30 we7u * src/main.c: Fixing the AUX-TNC type so that it actually tries to parse the GPS sentences. It didn't appear to do that with the earlier code, while other types of interfaces did parse them. 2004-06-18 06:51 we7u * src/interface.c: Adding parsing for more OpenTrac elements. Not much is done with the data yet, but the placeholders are there now. Added better reporting for various classes of unknown OpenTrac element types also. 2004-06-18 00:08 we7u * src/interface.c: Added some comments. 2004-06-17 16:33 we7u * src/interface.c: More very minor OpenTrac tweaks. 2004-06-17 15:46 we7u * src/interface.c: Minor tweaks so that the OpenTrac comment field gets cleared before we process each piece, plus adding a space before the displayname part of the OpenTrac comment. 2004-06-17 15:11 we7u * FAQ: Added another question/answer about problems caused by the LANG environment variable setting. 2004-06-17 12:28 we7u * src/interface.c: Limiting the comment field on the converted OpenTrac packets to 40 chars, which is the max for a Base-91 compressed APRS packet. 2004-06-17 12:18 we7u * src/interface.c: Converting strcat() to strncat() functions in the OpenTrac routines. 2004-06-17 12:03 we7u * src/interface.c: Changed some comments. No code changes. 2004-06-17 11:10 we7u * src/interface.c: Higher-resolution OpenTrac positioning. We now convert to Base-91 Compressed APRS packets before throwing them into our standard decoding. This should give us 1/100 sec lat/long resolution, instead of the 60' resolution we had before. This new code is untested as of yet. 2004-06-17 10:46 we7u * src/: util.c, xastir.h: Adding a higher-resolution lat/long format, so we can make better use of OpenTrac resolution. 2004-06-17 08:06 we7u * src/interface.c: Changing from issuing the "conv" command to issuing the "k" command to get the TNC into converse mode. One european TNC doesn't implement the "conv" command. 2004-06-16 16:27 we7u * config/: tnc-startup.d700, tnc-startup.thd7: Adding TXD settings to the Kenwood startup files. 2004-06-14 23:23 we7u * src/interface.c: Added a comment. 2004-06-14 22:31 we7u * config/: Makefile.am, tnc-startup.kpc2: Initial kpc2 startup file by Tom Russo. Thanks! 2004-06-14 20:10 we7u * src/util.c: Changing one debug fprintf. 2004-06-14 13:40 we7u * src/interface.c: Removing an error messaging having to do with the tnc-start/stop META tag. This error message gets thrown out at odd times if you happen to have META in a comment in those file. Not needed. 2004-06-14 13:14 we7u * README.win32: Liblcms is now a Cygwin package, so changing the instructions to match. Thanks to Henk de Groot for this info! 2004-06-14 12:53 we7u * config/Makefile.am: Adding a new stop file for the TH-D7A. 2004-06-14 12:49 we7u * config/: tnc-stop.thd7, tnc-startup.thd7: Changes to the tnc-startup.d7a startup file by Henk de Groot, PE1DNN. Also a new tnc-stop.d7a file from him. Thanks! 2004-06-11 12:45 we7u * config/Makefile.am: Adding the new D700 start/stop files. 2004-06-11 12:44 we7u * config/: tnc-startup.d700, tnc-stop.d700: Adding files that David Flood, KD7MYC, came up with to start/top a Kenwood D700A and put it into the proper modes in each case. 2004-06-10 19:26 we7u * src/interface.c: Tweaks to allow more control in the tnc-startup.sys file. Adds a pause and a no-ctrl-C capability. 2004-06-10 16:51 we7u * Davis/src/db2APRS.c: Memory leak update by Bruce Bennett, KB8ROP. Thanks! 2004-06-08 08:37 we7u * config/language-Dutch.sys: Updates by Han Sytsma. Thanks! 2004-06-07 14:13 we7u * configure.ac: Bumping the development rev. up to 1.3.3. 2004-06-07 13:01 we7u * INSTALL: A note about adding a flag to the configure command-line to help it find the Motif include files. 2004-06-07 11:11 we7u * src/alert.c: Fixing string overflow problem triggered by extreme number of compressed alerts. 2004-06-04 15:47 we7u * src/: rac_data.c, rac_data.h: Fixing a possible buffer overflow problem that Tom Russo found. Thanks! 2004-06-04 13:39 we7u * config/: tnc-startup.aea, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: More PID filtering stuff. 2004-06-04 12:42 we7u * config/: tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: Adding PID filtering so that only 0xf0 PID's make it through in converse mode (APRS packets). 2004-06-04 10:36 we7u * src/fcc_data.c: Fix by Tom Russo. 2004-06-04 10:20 we7u * config/tnc-startup.kam: Adding PID OFF. 2004-06-04 09:53 we7u * config/tnc-startup.kpc3: Adding "PID off" so that other protocols don't show up in converse/monitor mode. 2004-06-03 22:49 we7u * src/main.c: Zoom-in box tweaks. These prevent the vectors from being drawn over again if a screen update has happened. Keeps extra line segments from appearing while doing the zoom-in box mouse operation. 2004-06-03 16:01 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM. Thanks! 2004-06-03 15:00 francais1 * config/language-French.sys: Updated somewhat 2004-06-03 14:36 we7u * src/main.c: Widening the zoom-in line width slightly. Looks very nice now/more visible. 2004-06-03 14:11 we7u * config/language-Italian.sys: Updates by Alessandro Frigeri, IK0YUP. Thanks! 2004-06-03 13:47 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2004-06-03 09:49 we7u * src/main.c: Better zoom-in box operation. Much better! 2004-06-02 14:28 we7u * src/main.c: Added another variable which we check against in order to NOT draw the zoom-in box when we're in the menus. 2004-06-02 12:43 we7u * src/map_gdal.c: Fixing the out-of-bounds check after the coordinate conversion. 2004-06-02 11:19 we7u * src/main.c: Adding a visible selection outline to the zoom-in function. The outline updates once per second currently and doesn't clean up after itself, but they disappear fairly quickly anyway. 2004-06-02 09:41 we7u * configure.ac: Adding Davis stuff. 2004-06-02 09:40 we7u * Makefile.am: Adding Davis directory. 2004-06-02 09:38 we7u * Davis/src/: Makefile.am, db2APRS.c, defs.h: Moved these from xastir/src/Davis/src to xastir/Davis/src 2004-06-02 09:37 we7u * Davis/: AUTHORS, COPYING, ChangeLog, INSTALL, Makefile.am, NEWS, README, bootstrap.sh, configure.ac: Moved these from xastir/src/Davis to xastir/Davis 2004-06-01 20:28 we7u * src/Makefile.am: Removing Davis from the list of subdirectories for now. 2004-06-01 15:49 we7u * src/Makefile.am: Tweaks to include the Davis code in the released tgz files. 2004-05-30 22:34 we7u * src/: dbfawk.c, map_shp.c: More Tom Russo fixes, also removing some debug code that I added earlier. 2004-05-30 18:28 rzg * INSTALL, README.MAPS, help/help-English.dat: Updates to all the docs, some more README.MAPS cleanups/updates. 2004-05-28 17:45 we7u * src/map_shp.c: Correcting what I submitted earlier to match what Tom Russo sent me. My oops. 2004-05-28 16:02 we7u * src/: alert.c, map_shp.c: Tom Russo's tweak to allow red flag alerts in their current transmitted form to be displayed by Xastir. Thanks! 2004-05-28 15:44 we7u * symbols/Makefile.am: Adding new red_flag.xbm file to the mix. 2004-05-28 15:43 we7u * symbols/red_flag.xbm: New warning by Tom Russo. 2004-05-28 12:23 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: More tweaks from Tom Russo. This one is intended to supply a "BOGUS" default value for the key if the shapefile has NULL entries. 2004-05-28 12:16 we7u * src/main.c: Mostly comment changes. Also removing the exit when Festival can't be connected to (which I don't think worked anyway). 2004-05-28 12:03 we7u * src/map_shp.c: Changed an exit() to a return() for the case where dbfawk fails. 2004-05-28 12:03 we7u * src/: hostname.c, sound.c: Added some comments. 2004-05-28 11:34 we7u * src/map_shp.c: Comment change. 2004-05-28 11:09 we7u * src/map_shp.c: Here's a fix for the missing weather alert problem, when using dbfawk. Turns out the latest zone file from NOAA has an unexpected mostly-NULL entry for shape 144, which caused our compare to match on that shape in all cases. It's definitely an incorrect shapefile entry, but it caused a problem in our code as well which needed to be fixed. We now check again using the title length if we got a match due to the key length being 0. 2004-05-28 07:48 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Tweaks by Tom Russo to reset fill_style in each dbfawk file. Thanks! 2004-05-26 19:11 we7u * src/: awk.c, dbfawk.c, map_shp.c: More of Tom Russo's memory leak fixes. Thanks! 2004-05-26 14:14 we7u * src/: awk.c, dbfawk.c, map_shp.c: Minor comment changes. Changed to correct cleanup routine for one type of object. More memory leak fixes. 2004-05-26 12:15 we7u * src/map_shp.c: Adding some more "free" stuff before yet another return. 2004-05-26 09:11 we7u * src/xa_config.c: Changing default for weather alert updates to 60 seconds instead of 30. 2004-05-25 22:57 we7u * src/awk.c: Closing another small memory leak. 2004-05-25 21:42 we7u * src/map_shp.c: Handling another error condition. 2004-05-25 21:37 we7u * src/dbfawk.c: More comments. Handled a few error conditions. Perhaps closed a few minor memory leaks. 2004-05-25 16:17 we7u * src/map_shp.c: More comments. 2004-05-25 13:45 we7u * src/: awk.c, map_shp.c: More comments. 2004-05-25 13:01 we7u * src/: dbfawk.c, awk.c: Added some comments. 2004-05-25 13:00 we7u * src/rotated.c: Added some comments regarding malloc's/free's. 2004-05-25 00:30 we7u * src/dbfawk.c: More comments. 2004-05-24 23:53 we7u * src/dbfawk.c: Moving some free() code to the proper places. 2004-05-24 23:08 we7u * src/map_shp.c: More comments. 2004-05-24 21:34 we7u * src/dbfawk.c: Adding more comments. 2004-05-24 21:18 we7u * src/: dbfawk.c, map_shp.c: Adding comments/printf's regarding allocation/deallocation of memory. 2004-05-24 21:11 we7u * src/: awk.c, testawk.c: Adding comments regarding allocations and free'ing of memory. 2004-05-24 18:55 we7u * src/: dbfawk.c, map_shp.c: More memory leak fixes for dbfawk. Getting better! 2004-05-24 14:53 we7u * src/: map_shp.c, dbfawk.c: Adding some free() statements to exit points in map_shp.c, to de-allocate memory that was allocated earlier in the function via dbfawk calls. 2004-05-24 11:02 gstueve * src/main.c: Actually maintain count of visible alerts on screen for increasing alert count. 2004-05-24 10:51 we7u * FAQ: Added a few more notes about what do do for "missing Motif" messages. 2004-05-23 17:01 n2ygk * src/: dbfawk.c, dbfawk.h, map_shp.c: Tom's "bloatpatch" for memory leak. 2004-05-22 18:54 rzg * README.MAPS: Some formatting fixes, updated URL for quad index shapefile. 2004-05-22 12:42 we7u * acinclude.m4, configure.ac: Mods by Tom Russo to allow the --without flags to work properly for festival and gpsman. Thanks! 2004-05-21 11:49 jtwilley * configure.ac: applied Tom Russo's emergency patch - will examine later 2004-05-20 14:46 we7u * src/map_shp.c: Closing a small memory leak in the dbfawk stuff. More to come. Thanks to Tom Russo for finding this one. 2004-05-19 16:23 we7u * src/main.c: Fixing the local station so that compressed posits turn off ambiguity. 2004-05-19 16:08 we7u * INSTALL, README.MAPS, configure.ac, xastir.spec.in: Making dbfawk be compiled in by default. Added --without-* flags for all of the optional libraries so that they can be disabled. Made geotiff compilation dependent on libproj being present. Made dbfawk compilation dependent on shapelib and pcre being present. The tests for the libraries are skipped entirely if the proper --without-* flag is passed to configure. 2004-05-19 09:05 we7u * config/Makefile.am: Adding the fire alert dbfawk file to the distribution. 2004-05-19 09:04 we7u * config/nwsfz_ddmmyy.dbfawk: Adding a dbfawk file for Fire weather alerts. 2004-05-19 08:55 we7u * config/nwsz_ddmmyy.dbfawk: Latest dbfawk file for weather zone shapefile. 2004-05-18 13:28 we7u * config/nwsz_ddmmyy.dbfawk: Added a commented line which works with fire zone files. Can't add it in yet as it appears to be mutually exclusive with the other line before it which works for regular zone files. 2004-05-18 13:26 we7u * src/map_shp.c: Added a comment. 2004-05-18 12:54 we7u * README.MAPS, src/map_shp.c, src/maps.c: Adding support for fire zone maps. Works now for non-dbfawk compiles, but need to get dbfawk working with them as well. The WXSVR should eventually start sending these types of alerts to us on firenet. 2004-05-18 09:42 we7u * src/db.c: Had to move the variable declarations up in the code block, else it fails compile on FreeBSD. Thanks to Tom Russo for this fix. 2004-05-17 13:06 we7u * src/db.c: A small tweak to make the FCC/RAC lookup for objects/items look at the FROM callsign instead of the object/item names. Now we can look up who is sending the objects in our database. 2004-05-17 12:44 we7u * src/db.c: Fixing the weather alert by "Station Info" lookups so that it works for more objects from the weather server. 2004-05-17 11:45 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/wx.h, src/wx_gui.c: Adding the capability to finger the WXSVR if an object/item and has "WXSVR" in the path. This is from a new button "Fetch NWS Alert" in the Station Info dialog. It takes the place of the FCC/RAC button if the above conditions are met. 2004-05-13 10:17 we7u * configure.ac: Moving the ImageMagick check so that it is the absolute last check, so that it doesn't mess up the GDAL check either. Added comments stating that the IM check should stay as the last check. 2004-05-13 09:51 we7u * configure.ac: Moving the ImageMagick test to later in the configuration. It appears to mess up the tests for other libraries if it fails. Now only the GDAL test is below it. 2004-05-12 13:49 we7u * src/alert.c: Additional comments. 2004-05-12 12:33 we7u * scripts/overlay.pl: Correcting the math for lat/long. 2004-05-12 11:56 we7u * src/interface.c: Making sure that the AGWPE path is upper-case. 2004-05-12 11:45 we7u * src/interface.c: Fixing a bug in AGWPE path for objects/items. This bug was caused by a different use of variables between the output_aprs_data() and output_my_aprs_data() functions, and then copying code from one to the other without changing the variables. Variable names are now more common between them, so this problem should be less likely to occur in the future. 2004-05-12 09:44 we7u * scripts/overlay.pl: Changes to comments. 2004-05-12 09:16 we7u * scripts/: overlay.pl, Makefile.am: Adding overlay.pl, which creates either Xastir log file format or Xastir object.log format files from CSV files. Used to create object overlays (actually APRS Items in this case) out of spreadsheet data. 2004-05-11 10:07 we7u * README.win32: Added a comment about an error caused by line-wrap in the Shapelib Makefile. 2004-05-10 13:51 we7u * src/: main.h, main.c: Adding #ifdef's for "OLD_PTHREADS", which knock out the SIGUSR1 handler if "OLD_PTHREADS" is defined in "main.h". 2004-05-10 12:33 we7u * src/db.c: Proper code for randomizing the object/item transmit times a bit. 2004-05-10 09:39 we7u * scripts/Makefile.am: Adding a few of the newer scripts to the install portion. 2004-05-08 19:54 we7u * src/: main.c, db.c: Tweaking the object/item timing to make sure that any changes to an object cause the object to immediately go to the initial state of the decay algorithm. 2004-05-08 18:55 we7u * src/db.c: Fixing the random number modulus operations for transmitting objects/items. It appears however that the rand() and random() functions are broken on this system, always returning 0. 2004-05-07 14:09 we7u * src/db.c: Reducing the randomizing of object/item TX times from 33% of interval to 20% of interval. 2004-05-07 13:45 we7u * src/db.c: Randomizing object/item transmit a bit so that they don't get transmitted together when restarting with active objects/items. This causes them to diverse fairly well after about the third transmit iteration. 2004-05-07 13:21 we7u * src/util.c: Adding some comments. 2004-05-07 11:02 we7u * src/db.c: Fix for objects/items: If we're using the name of one that has already been killed, we now delete the old record completely before creating the new one. This keeps us from drawing tracklines from one to the other or keeping info that doesn't apply to the new object/item. 2004-05-07 09:19 we7u * src/util.c: Fixing the logging of objects/items. There were problems with removing spaces from Items which made them not found in the search, and problems with comments in front of lines in the log file. 2004-05-07 09:16 we7u * src/: db.c, db.h: Comment changes. No code changes. 2004-05-06 16:27 we7u * src/messages.c: Reducing the initial time interval between transmitted messages from 15 to 7 seconds. 2004-05-06 16:19 we7u * src/: db.h, messages.c: Minor comment changes. 2004-05-06 14:40 we7u * src/: db.h, db.c, main.c: Implementing the decaying algorithm for timing of object/item transmits, similar to how Bob Bruninga does it in aprsDOS. Also added a segfault fix for moving Items (same fix as done earlier for moving Objects). 2004-05-04 10:59 we7u * INSTALL: Bumping rev. numbers for some of the optional libraries. 2004-05-03 11:58 we7u * README.MAPS: Added some geodesy links. 2004-04-30 13:27 we7u * INSTALL: Adding more URL's to lists of internet servers. 2004-04-29 15:30 we7u * FAQ: Adding a section describing the fixes for the CVS hostname change at SourceForge. 2004-04-28 14:43 shadow * configure.ac: Test for linker support of -Wl,--no-keep-memory rather than assuming it's safe everywhere; MacOS 10.3.x doesn't support it. 2004-04-27 09:23 we7u * INSTALL: Added instructions for connecting to an internet server plus a pointer to the current list of servers. 2004-04-26 12:31 we7u * README.win32: Additions by Henk de Groot. Thanks! 2004-04-26 11:14 we7u * INSTALL, README.win32: Shapelib links updates, thanks to Wes Johnston for pointing this out. 2004-04-23 10:46 we7u * src/interface.c: OpenTrac patch by J. Lance Cotton, KJ5O. Thanks! 2004-04-23 10:35 we7u * src/igate.c: Refusing to gate OpenTrac packets (which have been converted to APRS-format by Xastir) to/from RF or the INET. 2004-04-21 16:01 we7u * src/main.c: Working version of the new Center & Zoom mouse menu function. 2004-04-21 14:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Starting to add a new mouse menu entry: "Center & Zoom". Non-functional so far but won't take much more work to finish it. 2004-04-15 14:19 we7u * README.win32: An update to the link-step memory-hog note. 2004-04-15 10:12 we7u * README.win32: Added a note about the link-stage being very memory hungry/taking a lot of time to complete on Cygwin. 2004-04-14 14:31 we7u * configure.ac: Adding the no-keep-memory flag to LDFLAGS which makes the link stage on Cygwin much faster. 2004-04-14 10:12 we7u * README.win32: Specifying a minimum set of xorg packages necessary for installing the X11 stuff. Thanks to Henk for figuring this out for us! 2004-04-12 14:21 we7u * configure.ac: Removing one line to make output prettier. 2004-04-12 14:14 we7u * README.win32: Updating the package names for X11 plus removing a few packages that are unnecessary. 2004-04-12 13:18 we7u * README.win32: Changing names of Cygwin packages to correspond to Cygwin's current naming scheme for the X11 server. 2004-04-12 12:40 we7u * README.win32: Removed the xwinclip package from the requirements per Henk de Groot. Added notes by James Cour, K1ZC, and Tim Baggett, AA5DF, regarding the network audio instructions. 2004-04-09 13:07 we7u * README.win32: Removing the "for future development" notes from the pcre descriptions. We use that library for dbfawk support. 2004-04-09 09:44 we7u * README.MAPS: Adding more notes that might make the initial user's decision easier as to which libraries to compile in for the desired functionality. 2004-04-08 09:14 we7u * config/: Makefile.am, tgr2shp.dbfawk: Adding Tom Russo's tgr2shp.dbfawk file to our standard set. Useful for the 2003 tiger data that just came out. 2004-04-06 21:13 we7u * INSTALL: Adding a note about needing "pcre" to compile in dbfawk support. 2004-04-06 09:21 we7u * src/main.c: Adding a command-line option to deselect all maps: "-m" 2004-04-06 08:08 we7u * src/map_shp.c: Fix by Tom Russo: If running with dbfawk, sets everything to defaults in case a dbfawk file fails to reset things when done. 2004-04-05 13:14 we7u * README.win32: Added a note about winclip. 2004-04-02 17:19 we7u * src/: geo.h, geocoder_gui.c: Extending the lengths of the input fields for the Find Address function. 2004-04-02 14:16 we7u * README.win32: Added a note by Henk regarind lcms. 2004-04-02 13:30 we7u * README.MAPS: Added the Wiki page. 2004-04-02 08:03 we7u * configure.ac: Bumping the rev number. 2004-04-01 09:11 we7u * src/geo-find.c: Getting rid of some more compiler warnings. 2004-04-01 07:25 we7u * src/geocoder_gui.c: Fixing a compiler warning. 2004-03-31 22:11 we7u * src/util.c: Better implementation of the higher resolution s2l routines. 2004-03-31 20:46 shadow * INSTALL, help/help-English.dat: document the find address feature 2004-03-31 20:26 we7u * src/util.c: Backing out the changes done earlier today. Will try again to implement higher resolution NMEA strings at a later date. 2004-03-31 20:16 shadow * README.MAPS: Add pointer to Census 2003 data. Add pointer to geocoder data files. 2004-03-31 10:56 we7u * src/util.c: Extending the NMEA sentence decoding to handle DD MM.MMMM format, which the new Tinytrak-3 chips can put out. That resolution ends up being 0.6 counts of our Xastir coordinate system, so we need to resolve down to that level to avoid losing much. 2004-03-30 14:58 we7u * src/db.c: Changing from circles to an 'X' for marking a found address. 2004-03-30 12:49 we7u * src/xa_config.c: Saving/restoring the Mark Destination button state for the Find Address function. 2004-03-30 12:44 we7u * src/: db.c, geo.h, geocoder_gui.c: Added a togglebutton that enables/disables the marking of the destination for the Find Address function. 2004-03-30 12:21 we7u * src/: db.c, geo.h, geocoder_gui.c: Initial attempt at marking the destination target for a Find Address query. There's not capability yet for removing the marking, but you can always seek another address and it will move to the new one. Will probably change to some other marking at some point (a big 'X' perhaps?), and need to find a way to remove the mark that makes sense. 2004-03-30 08:58 we7u * src/geocoder_gui.c: Minor re-arranging of the Find Address dialog's widgets. 2004-03-29 15:57 we7u * src/io-mmap.c: Adding an include to get rid of compiler warnings about memcpy(). 2004-03-29 15:40 we7u * src/: LICENSE.geocoder, geo-client.c, geo-find.c, geo.h, geocoder_gui.c, io-common.c, io-mmap.c, io.h, Makefile.am, main.c, main.h, xa_config.c: Geocoding support added by Derrick J Brashear, based off code written by Daniel Egenor that was released under GPL license. 2004-03-26 10:17 we7u * Makefile.am: Moving the .geo files into a subdirectory called "Online". 2004-03-25 08:35 we7u * src/gps.c: Enabling setuid priviledge at the point where settimeofday() is called. Thanks to William Baguhn, kc9asi, for pointing this out. 2004-03-24 17:29 shadow * src/macspeech.c: macspeech support, but i need to write autoconf gunk, it just pretends to be festival 2004-03-23 15:12 we7u * INSTALL, README.win32: Updating Cygwin instructions: com1 -> /dev/ttyS0 and similar for com2. 2004-03-23 14:59 we7u * acinclude.m4: Tweaking Cygwin serial ports to more standard port names. 2004-03-23 10:01 we7u * src/wx.c: Changes by Bruce Bennett. 2004-03-22 14:12 we7u * src/map_geo.c: Moving an #ifdef so that no compiler warnings are generated when ImageMagick support is missing. 2004-03-22 13:52 we7u * acinclude.m4: Fixes for Cygwin regarding comm ports. 2004-03-22 09:23 we7u * README.win32: Adding instructions to side-step the "detecting devices" hang on WinXP. 2004-03-21 12:58 rzg * help/help-English.dat: Added info on the comment field in interfaces; started a new tally of what changed since release. 2004-03-19 14:38 we7u * src/map_gnis.c: Removing trailing spaces while reading lines in from GNIS files. They are notorious for having many spaces at the ends of the lines. 2004-03-19 12:37 we7u * src/map_shp.c: The rest of the code needed for the XReadBitmapFile() call failure, in order to make sure everything keeps running. 2004-03-19 12:34 we7u * src/map_shp.c: Getting rid of the exit(1) that we were doing when the XReadBitmapFile() call was failing during long runtimes. It's annoying if the bitmap is not found but it shouldn't kill all of Xastir in that case. I'll be checking to see if further changes to the code are necessary though to prevent segfaults happening later in that part of the code. 2004-03-19 09:52 we7u * scripts/split_gnis.pl: Added an RCS tag. Still needs a copyright blurb. 2004-03-19 09:51 we7u * src/interface.c: Fixing the long transmit delay, which was in port_write at the final select() call. 2004-03-18 19:21 jtwilley * scripts/split_gnis.pl: Added split_gnis.pl to scripts directory. The split_gnis.pl script will take any number of state-wide GNIS files listed on the command line and create smaller files based on county names. 2004-03-18 15:14 we7u * src/maps.c: Adding S57 map format to Xastir's supported map types. File extension currently has to be ".s57" for these types of maps to be recognized by Xastir. 2004-03-18 10:11 we7u * scripts/ozi2geo.pl: Changed one comment. 2004-03-18 09:58 we7u * scripts/ozi2geo.pl: Initial attempt at a conversion script from OziExplorer .map format to Xastir's .geo format. This version works with the one example map I had to work with. More than likely more work will be needed on the script as more types of maps are tried. 2004-03-15 15:49 we7u * scripts/split_gnis.bash: Added a comment about "dos2unix". 2004-03-15 15:47 we7u * scripts/split_gnis.bash: Script written by William Baguhn, kc9asi. Splits a GNIS files into smaller pieces which are more quickly loaded by Xastir when zoomed in. 2004-03-15 09:08 we7u * USRadar.geo: Tweaks by Gerry Creager. 2004-03-12 20:54 we7u * USRadar.geo: Mods by Gerry Creager. 2004-03-10 20:11 we7u * src/interface_gui.c: Implementing GUI input fields for the Interface->Properties "comment" field for each interface. 2004-03-10 09:50 we7u * src/interface_gui.c: Minor comment change. 2004-03-09 14:59 we7u * README.MAPS: Another note from Tom Russo on converting between datums. 2004-03-09 13:18 we7u * src/interface_gui.c: Adding some bookmarks. Places that might need to be tweaked for MKISS. 2004-03-09 08:47 we7u * src/interface_gui.c: Wiping out old interface params from config file when an interface is deleted. 2004-03-09 08:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Minor tweaks to the MKISS GUI. Not functional yet. 2004-03-08 22:54 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Updated language strings for MKISS and interface comments. 2004-03-08 22:42 we7u * src/: db.c, interface_gui.c, xa_config.c: Adding new MKISS interface (not complete yet). Adding interface comment capability. 2004-03-08 22:32 we7u * src/interface.h: Adding new fields. Needed for MKISS interface and for adding comments to interfaces. 2004-03-08 13:16 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Updates to language strings for MKISS TNC's. 2004-03-08 13:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c: Initial stab at creating a new SERIAL_MKISS interface type. So far it's an identical copy of the SERIAL_KISS interface type, but that will change soon. Intent is to support multi-port KISS TNC's such as the Kantronics KAM. 2004-03-04 15:12 we7u * USRadar.geo, help/help-English.dat, src/color.c, src/color.h, src/map_geo.c, src/maps.h: Fix for the TRANSPARENT tag in .geo's: Wasn't working right on 16-bit versus 24-bit Xwindows servers. 2004-03-03 14:54 we7u * src/map_geo.c: Toporama map speedups made possible by Steve Dimse's changes on the server. 2004-03-02 13:19 we7u * README.win32: A note by Steve Peters, N1TYE, regarding the lcms library on Cygwin. 2004-03-02 09:56 we7u * src/map_geo.c: Terraserver is playing games, changing their URL again. Changing back to the original one we used to use, which works for us again. The newer URL was returning all black images. 2004-03-02 00:10 we7u * src/map_geo.c: Commenting out debug output. 2004-03-02 00:07 we7u * src/maps.c: Sending tab map files to draw_ogr_map(). 2004-03-01 23:50 we7u * Makefile.am, src/map_geo.c: Initial version of code to support Canadian Toporama maps, downloading them automatically over the 'net from mm.aprs.net, including the dynamically generated .geo files. 2004-03-01 23:47 we7u * CanadaTopo250k.geo, CanadaTopo50k.geo: Initial checkin. 2004-03-01 09:31 we7u * README.MAPS: Changing notes regarding where to find free DRG maps. 2004-02-29 18:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Tweaking the Interface Start/Stop dialog so that it is much more readable. 2004-02-29 12:31 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added two new trail sliders to the timing dialog. They both control whether trails are displayed, one based on max distance, one based on max time. If either max distance or max time are exceeded for new trails, that segment is not drawn. Does not affect trail points that have already been received, just new trail points. 2004-02-27 19:12 we7u * src/main.c: Modifying the Move function so that it drops through all the dialogs and doesn't require any OK buttons to be pressed to effect the move. This is useful for drawing the expected route of a SAR team and documenting it via Shapefiles. It's much faster to do so now. Downside: Unintentionally moving an object gets an automatic confirm, and you'll have to move it back manually or else edit the object.log file by hand and read it in again. 2004-02-27 18:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c: Adding a "Disable Posit Dupe-Checks" option to Configure->Defaults. Disables the 30-minute dupe-checks that Xastir does when each packet is received. Does not affect igate dupe-checks. 2004-02-27 17:26 we7u * src/: db.c, main.h, util.c: Turning off trail-point dupe-checking when reading in objects/items from file. This lets us show SAR teams leaving and returning to base later, without having the last trail segment missing. 2004-02-27 17:00 we7u * src/db.c: Updating some comments. 2004-02-27 15:42 we7u * help/help-English.dat: Adding notes about trails and why some segments don't display. 2004-02-27 14:58 we7u * src/db.c: Changing the distance at which Xastir will skip a track segment, from >1 degree lat/long to >2 degrees. Any track segment less than 2 degrees in N/S and E/W length will get drawn, as long as the time between posits is less than 45 minutes. If over 45 minutes, the segment gets skipped as well. 2004-02-26 15:25 we7u * src/interface.c: New code to avoid opening the same serial port twice for two different interfaces. 2004-02-26 15:19 we7u * src/db.c: Changing some debug code. 2004-02-26 13:48 we7u * INSTALL: Added a note about how to test the festival server by telnet'ing to it. 2004-02-26 12:30 we7u * src/: map_geo.c, map_tiger.c, track_gui.c: Fixing the problem where a failed internet download (map or tracklog) would cause an older version of the same to get displayed. We now delete the old filename from our ~/.xastir/tmp directory before attempting the download each time. 2004-02-26 12:07 we7u * src/: db.c, db.h: Adding a retry timeout for killed object/items. We'll now transmit killed objects 11 times before ceasing to transmit them. 2004-02-24 11:34 we7u * README: Additions by Alan Shackelford, NG3B. 2004-02-24 09:28 we7u * README.MAPS: More good info from Tom Russo, KM5VY. 2004-02-23 14:52 we7u * README.MAPS: Added the FIPS locator URL. Useful stuff! 2004-02-21 22:32 we7u * INSTALL: Updating some libtiff/libgeotiff notes. 2004-02-21 12:35 kd6zwr * src/map_shp.c: Add label levels for point style shapefiles when using dbfawk 2004-02-13 13:40 we7u * src/maps.c: Fixing the prime meridian line for UTM grid. Wasn't being drawn at all zoom levels. 2004-02-13 08:54 we7u * README.win32: Added a warning about KDE. 2004-02-12 14:18 we7u * src/: interface.h, interface.c: New method of waiting for data to get to serial TNC's before closing the port. Method and most of the code contributed by Erik G. Burrows, KG6HEA. Additional code by WE7U to prevent locking up with poorly-behaved serial devices. 2004-02-11 14:40 we7u * src/map_geo.c: Making transparent images work again after the raster_intensity changes a few weeks back. 2004-02-11 13:35 we7u * src/main.c: Fixing an annoying floating-point conversion bug in the Map Intensity menus. For 70% and 90%, they were reported as 60% and 80% in the menus. 2004-02-11 10:24 we7u * Makefile.am, USRadar.geo, src/map_geo.c, src/maps.h: Changing to an unsigned long for holding the transparency value. Adding USRadar.geo as an installed map ('cuz it's just way cool). 2004-02-10 14:18 we7u * src/db.c: Making the 'h' in timestamp be case-insensitive on receive. 2004-02-10 14:18 we7u * src/db.c: Making the 'h' in a timestamp be case-insensitive on receive. 2004-02-09 12:20 we7u * src/db.c: Making N/S/E/W and the timestamp 'Z' non case-specific. This was requested by Bob Bruninga on the APRSSIG mailing list recently (sometime in january 2004, before our last stable release). 2004-02-06 14:39 we7u * src/interface_gui.c: Changing default path from RELAY,WIDE to WIDE. 2004-02-06 13:33 we7u * configure.ac, src/main.c: Adding a list of the compiled-in libraries to the Help->About dialog. 2004-02-05 11:00 we7u * INSTALL, README.CVS, README.win32: Updating CVS instructions because SourceForge isn't handling compression currently. 2004-02-04 12:41 we7u * bootstrap.sh: Adding the CVS tag line. 2004-02-04 08:49 we7u * src/: main.c, map_shp.c: Changing some error messages to provide more detail. 2004-02-02 23:10 we7u * README.win32: Mods by David Flood, KD7MYC. Thanks! 2004-02-02 14:31 we7u * configure.ac: Bumping the patch number so we can separate development versions from most recent stable release. 2004-02-02 13:41 we7u * config/language-German.sys: Updates by Rolf, DK7IN. 2004-02-02 12:58 we7u * src/main.c: Updating the Help->About message. Thanks for reminding me Ren! 2004-02-02 08:37 we7u * configure.ac: Bumping the revision to 1.3.0. Getting ready for stable release. 2004-02-02 08:35 we7u * help/help-English.dat: Very minor changes to the What's New section. 2004-02-01 23:26 rzg * help/help-English.dat: Moved old "What's new" list out of the way. 2004-02-01 23:23 rzg * help/help-English.dat: What's new section. Could use proofreading and the addition of stuff I forgot. 2004-01-30 15:48 shadow * README: update README to reflect what's needed to get MacOS X with GDAL. 2004-01-30 13:51 we7u * xastir.spec.in: Correcting the path to the man pages. 2004-01-30 10:12 we7u * symbols/symbols.dat: Implemented Wheelchair, Shelter, and proposed Waypoint symbol. Also changed one description from "HF Gateway" to "Any Gateway (w/overlay char)". The "Any Gateway" symbol still needs to be changed into something which would display an overlay char nicely. The Shelter symbol may need to be changed into something more recognizable. 2004-01-29 17:47 n2ygk * xastir.spec.in: --with-dbfawk. Curt: toss this if you feel dbfawk is not cooked enough. 2004-01-29 08:53 we7u * INSTALL: Updating the gpsman/gpsmanshp instructions for systems with tcl8.4 instead of tcl8.3. 2004-01-28 10:42 we7u * AUTHORS: Got rid of reference to non-existent file. Add note stating we don't try to keep this file up to date. 2004-01-28 10:11 we7u * UPGRADE: Added more notes about migrating to latest Xastir. 2004-01-28 09:42 we7u * README.CVS: Added another note about sticky tags. 2004-01-26 12:50 we7u * INSTALL: Adding a note about the port names for Cygwin. 2004-01-26 08:18 we7u * src/: Makefile.am, alert.c, alert.h, awk.c, awk.h, bulletin_gui.c, bulletin_gui.h, color.c, color.h, datum.c, datum.h, db.c, db.h, dbfawk.c, dbfawk.h, draw_symbols.c, draw_symbols.h, fcc_data.c, fcc_data.h, festival.c, festival.h, gps.c, gps.h, hostname.c, hostname.h, igate.c, igate.h, interface.c, interface.h, interface_gui.c, lang.c, lang.h, list_gui.c, list_gui.h, locate_gui.c, location.c, location_gui.c, main.c, main.h, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h, messages.c, messages.h, messages_gui.c, popup.h, popup_gui.c, rac_data.c, rac_data.h, rotated.c, rotated.h, snprintf.c, snprintf.h, sound.c, symbols.h, testawk.c, track_gui.c, track_gui.h, util.c, util.h, view_message_gui.c, wx.c, wx.h, wx_gui.c, x_spider.c, x_spider.h, xa_config.c, xa_config.h, xastir.h: Updating copyright notices. 2004-01-26 08:11 we7u * LICENSE, README.win32, callpass/Makefile.am, callpass/callpass.c, config/Makefile.am, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Makefile.am, scripts/example_objects.log, scripts/fcc-get, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, symbols/Makefile.am, symbols/symbols.dat: Updating copyright notices. 2004-01-26 08:09 we7u * AUTHORS, DEBUG_LEVELS, INSTALL, Makefile.am, NEWS, README, README.CVS, README.MAPS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, xastir.1, xastir.spec.in: Updating copyright notices. Adding a few more docs to the spec file. 2004-01-22 19:26 we7u * src/xa_config.c: Adding sys/stat.h call that is needed to compile this file on MacOSX. 2004-01-22 18:34 we7u * README.CVS: Updating the "unsticky" instructions for CVS. 2004-01-21 16:14 rzg * FAQ: Added a bit on support, fixed numbering, a typo, and copyright year. 2004-01-21 15:48 we7u * README.CVS: Added the "diff" line to .cvsrc note. Added "sticky" tags STABLE and RELEASE and explanations of how to use them. 2004-01-21 08:47 we7u * src/xa_config.c: Changing default for "Expand Dirs" in Map Chooser to 1. Better for new users. 2004-01-20 13:34 we7u * FAQ: Another note about ImageMagick dependencies and "spec" files. 2004-01-20 13:32 we7u * FAQ: Adding some notes about ImageMagick and failed dependencies. 2004-01-19 15:02 we7u * src/maps.c: Attempting to fix an indexing bug. New files are not picked up by indexing. This fix picks the later of ctime/mtime to use for the timestamp. Contributed by Reuven. 2004-01-19 13:33 we7u * src/: main.c, maps.c: Commented out some dead code in maps.c. Added new USR1 signal handler code by Tim Gimmel, KB4AMA. Just send a USR1 signal via "kill -USR1 " and Xastir will create a new snapshot. Useful for web page front-ends. 2004-01-16 12:25 gstueve * src/: alert.c, alert.h: Change numeric index references in flags to symbolic and fixed end-of-data to match sizeof data not fixed numeric values. 2004-01-16 12:18 gstueve * scripts/fcc-get: Update for new diretory layout with generic path name & add passive ftp. 2004-01-16 10:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.h, src/wx.c: Initial support for Davis Weather Monitor II, Wizard III, and Vantage Pro weather stations, written by Bruce Bennett. Thanks Bruce! 2004-01-15 13:28 we7u * src/xa_config.c: Attempting to recover from backup file renaming when things go wrong. We'll try to get as close to the original state of the files as we can. 2004-01-15 13:09 we7u * src/xa_config.c: More config file backup copies code. We now back out the renaming if the new config file can't be created, so we're left with the original config and two backups in that case. 2004-01-15 11:02 we7u * FAQ, src/interface.c, src/interface_gui.c, src/xa_config.c: Simplified the all interfaces up/down logic. It should work better now. Changed the config file backup code so that xastir.cnf.1 through xastir.cnf.3 are created. This should help insulate us a bit better from crashes, as we'll have more old copies of the config file to draw from if the main config file (xastir.cnf) gets trashed. 2004-01-15 08:56 we7u * configure.ac: Adding a line in for getting rid of duplicates in the LIBS variable. Commented out while testing so that it doesn't hurt any installations. 2004-01-14 15:07 we7u * src/main.c: Adding more sprintf's in cases of failure to create symlinks. 2004-01-14 12:07 we7u * configure.ac: Extending one comment. No code changes. 2004-01-14 12:00 we7u * src/main.c: Minor tweak to two fprintf strings. 2004-01-12 11:44 we7u * src/main.c: Changing back to a previous configuration for the end of the create_appshell() function. Attempting to get rid of this problem: "attempt to add non-widget child "DropSiteManager" to parent "xastir" which support only widgets" while not re-creating this problem: "Shell widget xastir has zero width and/or height". 2004-01-09 10:57 rzg * help/help-English.dat, src/maps.c: Map index checking now allows negative layer numbers. Minor helpfile updates 2004-01-09 08:11 we7u * src/map_gdal.c: More checks for invalid extents while indexing. If all 0's or outside indexes of the earth, we skip adding it to the index. 2004-01-08 13:38 we7u * src/main.c: Re-establishing the XtRealizeWidget() call in main that was commented out to help fix the "zero width or height" error on startup. Now we specify a minimum size in the XtVaAppInitialize() call that preceeds it, so the old problem shouldn't reoccur. 2004-01-08 13:34 we7u * src/main.c: Gives an initial size to the application. Makes it appear to come up faster. Whether or not it actually does is beside the point. May help to get rid of the initial sizing problem: "Error: Shell widget xastir has zero width and/or height". 2004-01-07 08:42 we7u * configure.ac: Minor tweaks to some AC_MSG_ERROR calls. 2004-01-07 08:42 we7u * INSTALL: Minor tweaks to the make instructions here and there. 2004-01-04 13:37 we7u * src/map_gdal.c: Correcting the limits for OGR indexing. 2003-12-30 07:38 we7u * src/maps.c: Changing startup STDERR output to show which library (Shapelib/OGR) is providing Shapefile support. 2003-12-26 09:26 we7u * src/interface.c: Bumping the read/write loop timeouts to 100ms. This should provide reasonable response time when killing ports, yet keep CPU usage low when no data is being read/written. 2003-12-26 08:17 we7u * src/interface.c: Bumping the timeout in port_write() select to 500ms. That timeout is used to jump out of the select() so that we can check whether the interface has gone down. It does not need to be very small, and in fact causes high CPU usage on freebsd systems if it's below about 1ms. Linux can handle somewhat smaller delays (100us is ok on Linux). 2003-12-24 17:07 rzg * help/help-English.dat: Whatsnew update, and tigermap.geo is back... 2003-12-23 17:49 we7u * src/: main.c, map_gdal.c, maps.c, xastir.h: Added another output line to the segfault handler. Minor tweaks to the OGR code. 2003-12-23 07:25 we7u * src/map_gdal.c: Added some comments. 2003-12-22 18:59 we7u * src/map_gdal.c: Starting to add map preferences code to the OGR map-drawing functions. 2003-12-20 16:18 we7u * src/main.c: Getting rid of a couple of messages used for cad object debug. Put them inside ifdef's. 2003-12-19 16:28 we7u * src/: map_geo.c, map_shp.c, map_tiger.c: Fixing raster_map_intensity for tiger and .geo maps. Changes in comments and remove of debugging code in map_shp.c 2003-12-19 13:33 we7u * src/map_geo.c: Minor tweak to make toposerver files work again and make the .geo code look like the tiger code w.r.t. image intensity. 2003-12-19 12:59 we7u * src/map_gdal.c: Improvements to the line drawing routines mostly. OGR stuff. 2003-12-19 12:59 we7u * src/maps.c: Major speed improvements to map_onscreen(), map_visible(), and map_visible_lat_lon() routines. 2003-12-19 12:58 we7u * src/main.c: Moved routines around. No code changes. 2003-12-18 16:04 we7u * src/map_gdal.c: Tweaks to OGR polygons. 2003-12-18 13:06 we7u * src/map_gdal.c: Working X11 Regions for drawing OGR "hole" or innner polygons. 2003-12-18 07:06 we7u * src/alert.c: Zero'ing out newly-added alert entries after each realloc() call. 2003-12-17 22:45 we7u * src/map_tiger.c: ImageMagick brightness code change by Jim Chandler, N0VH. 2003-12-17 22:40 we7u * src/map_gdal.c: Starting to add the framework for doing X11 Regions. Will allow doing "fill" and "hole" polygons as we currently do in the Shapelib code. 2003-12-17 13:07 we7u * src/map_gdal.c: More comments. 2003-12-17 12:58 we7u * src/map_gdal.c: Minor comment changes. 2003-12-17 12:56 we7u * src/map_gdal.c: More fill/hole polygon stuff. Currently drawing polygons with dashed lines for "hole" polygons, solid for "fill" polygons. This is if the use has decided not to fill the shapes. For filled shapes, the hole polygons aren't drawn at all currently. 2003-12-17 12:36 we7u * src/map_gdal.c: More comments. Starting to add polygon fill/hole differentiation code. 2003-12-17 12:06 we7u * src/map_gdal.c: More comments. 2003-12-17 10:24 we7u * src/map_gdal.c: Comment changes only. 2003-12-17 07:42 we7u * src/map_gdal.c: Fixing OGR polygons so they work again, still non-filled though. 2003-12-17 07:14 we7u * src/map_gdal.c: More comment changes. 2003-12-17 07:04 we7u * src/map_gdal.c: Changing default colors and changing a few comments. The colors won't stay, but they're useful at the moment for debugging. 2003-12-16 12:08 we7u * src/maps.c: Added some comments. 2003-12-16 10:16 we7u * src/interface.c: Fixes to make the OpenTrac tweaks compile properly. 2003-12-16 10:09 we7u * src/interface.c: Fixes to OpenTrac decoding by Scott Miller. 2003-12-16 08:19 we7u * src/alert.c: An attempt to skip over alert_list[] entries that are zeroed (title has '\0' as the first character) while doing an alert_match(). 2003-12-15 09:19 we7u * src/interface.c: Patch by Brian Heaton to prefix the port number to the incoming string we dump out via our segfault handler. 2003-12-15 07:56 we7u * README.MAPS: Added another SDTS note. 2003-12-13 10:36 we7u * INSTALL: Added another GDAL comment. 2003-12-13 10:33 we7u * src/map_gdal.c: Moved some XSet... calls down into the OGR drawing section. Above the indexing section they caused segfaults. We must not be calling the indexing functions with a valid widget? 2003-12-12 17:16 we7u * README.MAPS: Adding more map links for some new map formats. 2003-12-12 13:20 we7u * src/map_gdal.c: Faster OGR polygons. Transforming all of the points at once for each polygon. 2003-12-12 13:02 we7u * src/map_gdal.c: Faster OGR line drawing. Recognize more datums that we don't have to convert (faster again). 2003-12-12 12:31 we7u * src/map_gdal.c: Removing unneeded code. Adding more comments. 2003-12-12 12:24 we7u * src/map_gdal.c: Adding comments. 2003-12-12 12:20 we7u * src/map_gdal.c: Renaming OGR helper functions to make sure there aren't any clashes later with similar functions. 2003-12-12 12:17 we7u * src/map_gdal.c: Speeding up OGR Point drawing. Changing default point color to white. 2003-12-12 12:03 we7u * src/map_gdal.c: Faster OGR line/polygon drawing by checking extents on those datatypes that allow fast extent checking. 2003-12-12 12:02 we7u * configure.ac: Minor summary text change. 2003-12-12 08:23 we7u * src/map_gdal.c: Added TODO list for OGR and moved the Draw routines above the main OGR routine (getting rid of the prototypes). 2003-12-12 08:04 we7u * README.MAPS: Added a note about SDTS files. 2003-12-12 07:46 we7u * src/map_gdal.c: A bit of cleanup in the new OGR routines. 2003-12-12 07:30 we7u * src/map_gdal.c: Creating OGR Draw_Points() function which is similar to the Draw_Lines() and Draw_Polygons() functions. Skips drawing points that are outside the view. 2003-12-12 06:55 we7u * INSTALL: Changes to the GDAL/OGR notes. 2003-12-11 17:50 we7u * src/map_gdal.c: Optimizing Draw_Lines() and Draw_Polygons() functions in the OGR routines. We now check the extents of each feature and skip drawing it if it's not in our view. 2003-12-11 12:35 we7u * src/: main.c, map_gdal.c: Fixing map_interrupts so that they work properly and quickly. A few places were broken, including the new OGR code. 2003-12-11 11:42 we7u * src/map_gdal.c: Changed some variable names. Added some debug code, looking for sources of memory leaks. 2003-12-10 22:43 we7u * INSTALL: Added a new site for Shapelib. 2003-12-10 16:31 we7u * src/map_gdal.c: On-the-fly coordinate transforms while drawing. 2003-12-10 11:14 we7u * src/maps.c: Adding more map types that are accepted by OGR. 2003-12-10 10:18 we7u * src/map_gdal.c: Changed some comments. 2003-12-10 10:16 we7u * src/maps.c: Adding mif/mid (Mapinfo) to list of accepted map types for OGR. 2003-12-10 00:01 we7u * src/map_gdal.c: Minor reformatting. 2003-12-09 23:13 we7u * src/map_gdal.c: Added a comment. 2003-12-09 17:03 we7u * src/map_gdal.c: Better Polygons for OGR. 2003-12-09 12:27 we7u * src/map_gdal.c: Drawing of OGR polygons is now working. 2003-12-09 08:55 we7u * src/map_gdal.c: Slightly faster drawing code due to fewer sets of debug loops. More comments. 2003-12-09 00:22 we7u * src/: map_gdal.c, maps.c, maps.h: Added a new draw function for points. More tweaks to the OGR code. 2003-12-08 15:43 we7u * src/interface.c: Checking that I can stat a file and that it is a regular file before attempting to send a file of commands to the TNC. 2003-12-08 13:22 we7u * src/map_gdal.c: Adding indexing for files where spatial coordinate system is not known, but they still fall within the normal lat/long boundaries for file extents. We're assuming they're in geographic WGS84 coordinates in this case and allowing the indexing to complete. 2003-12-08 12:56 jtwilley * config/tnc-startup.null: Added a zero-byte file named 'tnc-startup.null' for those times when users do not want their TNC configurations changed by xastir. 2003-12-08 12:19 we7u * src/map_gdal.c: Comment updates. No code changes this time. 2003-12-08 12:10 we7u * src/map_gdal.c: Took out some debug stuff that messed with converting to nad27 datum for test runs. Generalized the code so that it works with projected coordinate systems. No computes file extents for state-plane coordinate systems. It should also work for UTM projected coordinate systems. 2003-12-07 23:50 we7u * src/map_gdal.c: For file extents (indexing): Datum translation is working now for geographic coordinate systems. Not implemented yet for projected coordinate systems. Haven't implemented datum translation for drawing yet. 2003-12-07 23:47 we7u * src/maps.c: Forcing shapefiles back to the old code for now. 2003-12-07 23:46 we7u * src/maps.c: More debug for map_driver stuff. 2003-12-07 12:23 we7u * src/interface.c: Reducing delay in port_write for checking queue. Down to 100us from 200ms. Makes writing to interfaces much snappier, but doesn't bog down CPU. Cranking up channel_data() busy wait from 1 to 2us. 2003-12-07 09:16 we7u * src/: main.c, xa_config.c: Fixing the 10% zoom in bug when at zoom level 1. 2003-12-06 12:10 we7u * src/map_gdal.c: Filling in a bit more for the OGR indexing code. 2003-12-06 09:20 we7u * src/interface.c: Reducing many of the usleep() delays while transmitting to serial TNC's. Users will have to rely on the new delay slider to add delays if they get into weird operation with any particular TNC. 2003-12-05 23:44 we7u * src/map_gdal.c: More changes to debug output. 2003-12-05 23:36 we7u * src/map_gdal.c: Partial map indexing working for OGR. Must be geographic coordinate system. Haven't implemented conversions from other datums or coordinate systems to geographic WGS84/NAD83 yet. 2003-12-05 22:33 we7u * src/map_gdal.c: Printing out extents now. Should have indexing implemented soon. 2003-12-05 22:02 we7u * src/map_gdal.c: More reformatting for debug purposes. 2003-12-05 19:11 we7u * src/map_gdal.c: Better formatting for OGR debug statements. 2003-12-05 17:36 we7u * src/map_gdal.c: Filling in more features. Slowly. 2003-12-05 14:07 we7u * src/xa_config.c: Changing the default serial_char_pacing to 1ms instead of 25ms. 2003-12-05 13:08 we7u * src/map_gdal.c: Working version of what I checked in last time. ;-) 2003-12-05 13:01 we7u * src/map_gdal.c: More good info in the OGR code. 2003-12-05 12:40 we7u * src/map_gdal.c: Fleshing out more details in the OGR driver. 2003-12-05 11:39 we7u * src/xa_config.c: Adding save/restore for serial character pacing. 2003-12-05 11:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h, src/map_gdal.c: Speeding up OGR. Adding a new inter-character delay timing slider that affects serial-port TNC's. 2003-12-04 10:58 we7u * src/map_gdal.c: Changed some comments. 2003-12-04 10:08 we7u * src/map_gdal.c: Adding map interrupt capability to the OGR code. 2003-12-04 08:39 we7u * src/maps.c: Fixing up the callouts to GDAL/OGR. We direct Shapefile stuff to draw_shapefile_map() right now instead of GDAL/OGR. Tiger goes to GDAL/OGR. This can be changed via a define near the top of maps.c so that Shapefile goes to OGR as well. 2003-12-04 08:36 we7u * src/map_shp.c: Getting rid of duplicate definition of font_size. 2003-12-04 08:21 n2ygk * src/map_shp.c: fix the font_size fix to use FONT_DEFAULT 2003-12-04 00:43 we7u * src/maps.c: Adding more vector types. Currently commented out, but the GDAL/OGR code will eventually support them. 2003-12-04 00:36 we7u * src/main.c: Added more vector formats to the Vector button in Map Chooser. 2003-12-04 00:25 we7u * src/map_gdal.c: Several segfaults fixed. Handles polyline shapefiles and raw Tiger/Line polylines so far. 2003-12-03 23:23 we7u * src/map_shp.c: Fixing a compile problem for non-dbfawk compiles. 2003-12-03 17:08 n2ygk * src/: main.c, map_dos.c, map_pdb.c, map_shp.c, maps.c, maps.h, xa_config.c, xastir.h: multiple font_sizes in maps/config/map label font 2003-12-03 17:05 n2ygk * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: font_size 2003-12-03 14:18 we7u * README.MAPS: Added a note about Tiger/Line maps (coming soon). 2003-12-03 13:08 we7u * src/map_gdal.c: Added some comments. 2003-12-03 12:53 we7u * src/map_shp.c: Removing the debug OGR code for the moment. 2003-12-03 12:52 we7u * src/map_gdal.c: OGR drawing for Shapefile polylines is starting to work. Not pretty yet. Points/Polygons not working yet. 2003-12-03 12:51 we7u * src/maps.h: Adding a prototype for a function needed in draw_gdal.c 2003-12-03 12:07 we7u * src/map_gdal.c: More OGR library stuff. Am at the point where I have access to the points/polylines/polygons... 2003-12-03 08:19 we7u * src/: main.c, maps.h: Changing the Map Properties dialog so that it only shows maps that were selected in the Map Chooser. Also the Ok and Cancel buttons in the Map Chooser are greyed-out when the Properties dialog is active (necessary due to the way I implemented the new feature). 2003-12-03 00:18 we7u * src/main.c: Added some comments. 2003-12-02 23:42 jtwilley * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added "Select All" line to the other language files. 2003-12-02 23:04 jtwilley * config/language-English.sys, src/main.c: Added "Select All" button to "Map Properties" dialog. 2003-12-02 16:25 we7u * src/map_shp.c: Forgot an #ifdef. 2003-12-02 16:23 we7u * src/: map_gdal.c, map_shp.c, maps.c: Debug OGR code. Nothing truly functional yet. Just getting a feel for how to go about it. 2003-12-02 15:06 we7u * configure.ac: Broke libproj check out into its own section and summary line. We still need it checked in the libgeotiff section as well though, as we depend on proj there too. 2003-12-02 14:16 we7u * src/: map_gdal.c, maps.c: Changing some warning messages. 2003-12-02 14:02 we7u * src/map_gdal.c: Getting rid of compiler warnings. 2003-12-02 13:50 we7u * configure.ac: Moving the pcre summary next to the dbfawk summary at the end of configure. Reordered some of the rest as well, putting all of the map libraries together. 2003-12-01 13:13 we7u * src/x_spider.c: Adding an include to make a compiler warning disappear. 2003-12-01 12:56 we7u * INSTALL: Removing a note that is no longer needed. CVS GDAL has been tweaked to fix it. 2003-11-29 11:12 we7u * src/x_spider.c: Flushing out the feature set for x_spider. Not ready for prime-time yet, but getting closer. It now echoes anything received from one client out to all other connected clients. No provision yet for detecting disconnected clients and removing their pipe structures. 2003-11-29 00:44 we7u * src/x_spider.c: Filling in more details for x_spider. Not functional yet. 2003-11-29 00:10 we7u * src/: x_spider.c, x_spider.h: More of the x_spider server code filled in. Not functional yet. 2003-11-28 22:34 we7u * src/: Makefile.am, x_spider.c, x_spider.h: Initial code for x_spider server. This is an APRS multiplexer that will eventually allow multiple other clients (Xastir or otherwise) to connect to a running Xastir and TX/RX APRS data between them. This will allow the other clients to share the TNC, AX.25, and network ports that Xastir is hooked up to. The code is not functional in that capacity yet, but it is a nice multi-connect echo server as it stands. 2003-11-28 22:26 we7u * src/: map_gdal.c, maps.c: Adding prototype for draw_ogr_map(). No real code yet. 2003-11-28 22:10 we7u * src/main.c: Fix for the stupid "PACKAGE" warnings that the GDAL include file causes. Fix figured out originally by Jack for the ImageMagick stuff, duplicated by me in the GDAL include area. 2003-11-28 21:57 we7u * src/main.c: Slowing down the UpdateTime() loop iteration. Some systems (RedHat/FreeBSD) appear to use up a lot of CPU time if this is set to '1' or '0'. Setting it to '2'. Will crank it up some more if people still report high CPU usage. 2003-11-28 14:55 kd6zwr * src/: main.c, map_gdal.c, maps.c: Cleaning up GDAL init, starting gdal code. 2003-11-26 18:47 we7u * src/maps.c: Changing from strstr() to strncmp() for matching selected directories with files inside them. Much more exact. 2003-11-26 14:10 we7u * src/main.c: Clearing the selected bits in the in-memory map index before we try to resync with the selected_maps.sys file's idea of what maps are selected. 2003-11-26 12:04 we7u * INSTALL: Adding GDAL instructions (not that there's much that can be done with it yet, but it's still nice to see the future list of supported map formats on startup!). 2003-11-26 09:37 we7u * src/maps.c: Getting rid of compiler warning when XPM is not available. This fix makes sure that the snapshot thread doesn't even get defined in that case. 2003-11-26 09:00 we7u * src/testawk.c: Fixing another couple of compiler warnings. 2003-11-26 08:54 we7u * src/awk.c: Fixing more compiler warnings. Trivial stuff. 2003-11-26 08:43 we7u * src/maps.c: Getting rid of another compiler warning. 2003-11-26 08:35 we7u * src/map_tif.c: Getting rid of compiler warnings. 2003-11-26 08:29 we7u * src/maps.c: Getting rid of compiler warnings and removing dead code. 2003-11-26 08:25 we7u * src/map_tiger.c: Fixing a compiler warning, although I can't for the life of me figure out why the compiler is confused. Perhaps all of the #ifdef's confused it. 2003-11-26 08:14 we7u * src/map_shp.c: Fixing a compiler warning. 2003-11-26 08:01 we7u * src/interface.c: Changing one variable to unsigned to get rid of a compiler warning. We don't need a signed variable there anyway. 2003-11-25 18:19 we7u * src/main.c: Converting to square meters/feet when the CAD object's area is too small for miles/km. 2003-11-25 14:34 n2ygk * config/tgrlk.dbfawk: label color blue for water 2003-11-25 14:14 we7u * src/main.c: Making the End Draw Mode function write the CAD objects out to disk as well. This makes it possible to save open polygons (polylines) instead of only closed polygons. 2003-11-25 12:49 we7u * src/main.c: Persistent CAD Objects. They get save/restored to/from file now. 2003-11-25 10:32 we7u * src/db.h: Changing the saved polygon area from an int to a float. 2003-11-25 10:31 we7u * src/main.c: Leaving the calculations in square nautical miles until we're finished, then converting to what the user needs. Saving the area now in the object in units of square kilometers. 2003-11-25 10:01 we7u * src/main.c: Issuing a popup message with the area measurement. 2003-11-25 09:49 we7u * src/main.c: More corrections to the area calculation. 2003-11-25 09:33 we7u * src/main.c: Forgot to add in the minus signs again. Area should be closer to being correct now for polygons. 2003-11-25 09:25 we7u * src/main.c: Computing area of a polygon. Correctly now I think. 2003-11-25 07:29 we7u * src/main.c: More CAD Drawing stuff. We now only compute area on polygons with 3 or more points, and don't "close" a polygon unless it has 3 or more points. 2003-11-25 07:14 we7u * src/main.c: More CAD Drawing stuff. 2003-11-25 07:05 n2ygk * src/map_shp.c: update comments 2003-11-25 00:46 we7u * src/main.c: Beginnings of computing area for a drawn polygon. 2003-11-24 23:42 we7u * src/: db.c, db.h, main.c, main.h, util.c, util.h: First semi-functional implementation of CAD drawing functions. No persistent storage has been implemented yet. 2003-11-24 16:45 we7u * src/maps.h: Exporting another function I'll need later in another module. 2003-11-24 14:38 we7u * src/main.c: Renaming one function. 2003-11-24 14:33 we7u * src/main.c: Changing a few comments. 2003-11-24 13:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/datum.c, src/db.c, src/list_gui.c, src/main.c, src/main.h, src/maps.c, src/xa_config.c: Adding the capability to use the special UTM zones with a new UTM selection, instead of using them only for MGRS. Seems some areas use them for regular UTM as well. 2003-11-24 13:32 we7u * src/main.c: Added more comments and some function prototypes for CAD objects. 2003-11-24 12:49 we7u * src/main.c: Non-blocking xfontsel code. Main app keeps humming along now even when xfontsel is up and running. 2003-11-24 11:20 rzg * help/help-English.dat: Updates for recent changes. 2003-11-24 10:35 we7u * src/main.c: Added some comments to the xfontsel code. 2003-11-24 10:24 n2ygk * src/main.c: simplified implementation of xfontsel using popen. 2003-11-23 23:07 we7u * src/main.c: Added another comment regarding xfontsel and possible conversion to another thread. 2003-11-23 22:50 we7u * src/main.c: We now write the output of xfontsel back into the Map Label Font dialog via the use of an intermediate file we write to ~/.xastir/tmp. 2003-11-23 21:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added xfontsel option to map label font dialog. 2003-11-22 20:38 we7u * src/main.c: More temporary CAD drawing changes. These allow experimentation without the drawings disappearing. Drawings do not survive pan or zoom though. 2003-11-22 15:40 we7u * src/main.c: Added crosshair cursor for Measure/Move modes, and pencil cursor for CAD Draw mode. 2003-11-21 13:55 we7u * src/db.c: Fixing a pointer problem that Jack Twilley found. This one occurs when we're deleting expired stations from our database in time order. We weren't saving a pointer to the next time-ordered record before free'ing the memory for the first. 2003-11-16 22:14 we7u * src/main.c: Adding some comments. No code changes. 2003-11-16 15:33 we7u * README.MAPS: Added a note from Tom Russo regarding limitations of shpproj. 2003-11-13 10:37 we7u * src/main.c: Added an erase option for the CAD objects. Non-functional so far. 2003-11-13 10:11 we7u * src/main.c: Moving more menu stuff around. Making it harder to move my station using the mouse. Put Pan stuff in a submenu to make the main mouse menu shorter. 2003-11-13 09:52 we7u * src/main.c: More Draw CAD-mode stuff. 2003-11-13 09:29 we7u * src/main.c: More draw CAD objects stuff. Not ready for prime-time yet. 2003-11-13 08:16 we7u * src/main.c: Moving the "Move my station here" menu option to the very bottom, more out of the way. 2003-11-13 07:27 n2ygk * config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, src/map_shp.c, src/maps.c, src/maps.h: Centered area polygon labels. Use light blue for area label color. 2003-11-12 13:23 we7u * INSTALL: Changing some instructions to use "su -c" instead of "su" and "exit". 2003-11-11 21:37 we7u * src/main.c: Very preliminary etch-a-sketch mode. Allows the operator to draw lines on top of the map display. Eventually this will be turned into something useful. Right now the lines disappear at the next screen refresh. 2003-11-11 07:03 n2ygk * config/: nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: "pattern" set to match X line attribute. Also some other minor tweaking. 2003-11-11 07:02 n2ygk * src/map_shp.c: add default dbfawk when signature not found. change "pattern" to just be the X line attribute pattern (0, 1, or 2). 2003-11-10 09:18 we7u * src/main.c: Changing the default symbol to a dot. Used to be the emergency symbol, which is probably not a good idea as a default. 2003-11-10 08:39 we7u * src/main.c: Saving/restoring comment and name fields when switching between different types of Create Object/Item dialogs. 2003-11-10 07:20 n2ygk * src/map_shp.c: Use 'fill_color' to fill polygons; 'color' for polygon border. 2003-11-10 06:57 n2ygk * config/: tgrlk.dbfawk, tgrlpt.dbfawk, tgrwat.dbfawk: fill_color 2003-11-10 06:56 n2ygk * config/: Makefile.am, tgrlpy.dbfawk, tgrplc00.dbfawk: More dbfawk's 2003-11-10 06:55 n2ygk * README.MAPS: use consistent style for variable names 2003-11-08 17:42 jtwilley * configure.ac, src/dbfawk.c, src/testawk.c: Tom Russo's patch to help dbfawk build under FreeBSD. 2003-11-07 22:57 we7u * src/main.c: Added some comments. 2003-11-07 22:49 we7u * src/main.c: Fixes for Map Chooser Properties buttons. The string offset was incorrect after the strings were shortened. Fixed now. 2003-11-07 13:46 we7u * src/maps.c: Fixing a problem whereby the weather alert filenames are guessed wrong if there are similarly-names zip files in the Counties directory. 2003-11-07 10:15 we7u * src/main.c: Fixing objects/items with respect to probability circles and multipoint polygons. We can now do compressed objects/items with these features, and we get a space before the multipoint string, as the spec requires. 2003-11-06 15:27 we7u * src/db.c: Changing the extract_multipoints() function so that it doesn't remove the multipoint string from the comment field of objects or items. This allows us to transmit the multipoint string every time we transmit the object/item. 2003-11-06 15:26 we7u * src/draw_symbols.c: Changed one comment. 2003-11-06 09:21 we7u * src/interface.c: OpenTrac bug-fix by Henk. Thanks! 2003-11-06 09:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Fixing Map Properties columns for other languages. 2003-11-06 09:02 we7u * config/language-English.sys, src/main.c: Making Map Properites even narrower. 2003-11-06 08:21 we7u * src/main.c: Reorganizing the buttons on Map Chooser->Properties so that the dialog will be narrower. 2003-11-06 07:56 we7u * src/main.c: Moving some of the Map menu into a submenu. Lesser-used stuff now resides in a Configure submenu off the Map menu. 2003-11-06 07:44 we7u * config/language-English.sys: Changing a few labels in the menus. Minor stuff. 2003-11-05 22:54 jtwilley * config/tnc-startup.aea: Moved 'EXP on' to the top of the file and commented out lines which produce errors on my AEA PK-232. 2003-11-05 10:35 we7u * src/maps.c: Fixing the high CPU-usage bug with XDrawLines() in draw_grid with UTM grids. 2003-11-05 10:10 we7u * src/maps.c: Added an interation max to the while loop in draw_grid(). Just in case. 2003-11-05 07:06 n2ygk * src/map_shp.c: Fix WX alerts 2003-11-04 15:24 we7u * src/map_shp.c: Patch submitted by Tom Russo, KM5VY. Allows dbfawk to control more than just color. 2003-11-04 15:00 we7u * src/main.c: Added a rather stupid fix for the problem: 'Error: attempt to add non-widget child "DropSiteManager" to parent "xastir"'. Making a couple of harmless Motif calls before calling XtVaCreateWidget in create_appshell(). 2003-11-04 14:24 we7u * src/map_geo.c: Wrapping a call with ifdef's for people that don't have ImageMagick compiled in. 2003-11-04 14:20 we7u * tigermap.geo: Adding this file so that Tigermap may be a normal option in the Map Chooser. 2003-11-04 13:46 we7u * src/main.c: Moving things around to different menus. Cleaning up the interface just a bit. 2003-11-04 11:28 we7u * src/xa_config.c: Remembering Tigermap config settings between sessions. 2003-11-04 09:17 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tiger.c, src/xa_config.c, src/xastir.h: Making the regular Map Intensity controls work for the TigerMap intensity as well. Simplifying the user interface a bit. 2003-11-04 08:46 we7u * Makefile.am, src/main.c, src/main.h, src/map_geo.c, src/map_tiger.c, src/xa_config.c: Moving Tigermap enable to the Map Chooser (so that all maps are selected/deselected from one dialog). Removed the Enable button from the Tigermap config dialog. 2003-11-03 13:22 we7u * src/location_gui.c: Removing unnecessary db.h include. 2003-11-03 13:22 we7u * src/: bulletin_gui.c, datum.c, db.c, db.h, gps.c, interface.c, interface_gui.c, list_gui.c, locate_gui.c, main.c, messages.c, messages_gui.c, track_gui.c, util.c, util.h, view_message_gui.c, wx.c, xa_config.c: Fixed the problem with coordinate calc and inputting UPS coordinates. Moved some routines from db.c to util.c that were general-purpose string routines. Got rid of unnecessary db.h includes. 2003-11-03 12:59 we7u * src/main.c: Added a debug line. 2003-11-03 11:04 we7u * src/util.c: Fixing the "nice" formatting for UTM so that extra spaces aren't added on the status line for MGRS coordinates. 2003-11-03 10:59 we7u * src/: datum.c, db.c, list_gui.c, main.c, util.c, util.h: Cleaning up the MGRS_string stuff. Formatting the string nicely for the Coordinate Calculator. 2003-11-03 09:19 we7u * src/datum.c: Fixed utm_ups_to_ll() function for the south polar region. 2003-11-03 09:13 we7u * src/util.c: Switching back to original math. 2003-11-03 08:33 we7u * src/datum.c: Added a comment about the problems with utm_ups_to_ll() function in the south polar region. 2003-11-03 08:14 we7u * src/main.c: Adding MGRS to Coordinate Calculator as an output format. Still has problems in the south polar region, but other than that it appears to work properly. 2003-11-03 08:10 we7u * src/util.c: Switching to MGRS zones when doing MGRS conversions, and restoring the "coordinate_system" variable when done. Changed some math to make it more understandable what was going on. 2003-11-03 08:08 we7u * src/datum.c: Changed a comment. 2003-11-01 10:57 we7u * src/util.c: Correct 2-letter digraphs now for the UPS regions while using MGRS coordinates. 2003-10-31 21:15 we7u * src/util.c: Changing the formatting for MGRS. 2003-10-31 16:35 we7u * src/util.c: MGRS appears to be functional in the UTM area. Still needs work in the UPS (polar) areas. 2003-10-31 15:35 we7u * src/: datum.c, datum.h, db.c, list_gui.c, main.c, main.h, maps.c, util.c, util.h, xa_config.c: Initial code for implementing MGRS coordinates. Not quite ready for prime-time yet. 2003-10-31 15:34 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding a label for selecting MGRS coordinates. 2003-10-30 14:32 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding Max/Min Zoom headings to Map Chooser->Properties dialog for other language files. 2003-10-30 10:50 we7u * src/xa_config.c: More error-checking for lat/long as read in from the config file. In case someone hand-edits the station location and gets the format wrong. 2003-10-29 19:38 we7u * src/maps.c: Fixing the edges of the earth, UTM grid style. 2003-10-29 13:03 we7u * src/: datum.c, datum.h, maps.c: Fixing the UTM grid. Added "MGRS_grid" variable. If set, we draw the irregular grids and report UTM coordinates using those grids. If zero, we draw the regularly-spaced six-degree zones and report using those regular zones. 2003-10-29 12:50 we7u * src/maps.c: Correcting UTM grid for the civilian UTM grid (non-MGRS grid). 2003-10-29 12:27 we7u * src/main.c: Saving our place in the Map Properties dialog. No more scrolling trying to get back to where you were. 2003-10-29 11:59 we7u * src/main.c: Commenting out debug code. 2003-10-29 11:51 we7u * src/main.c: Commenting out a debug line. 2003-10-29 11:23 we7u * src/maps.c: Adding code to migrate from old map_index.sys format to the new format. Accepts either 8 or 10 parameters per line and writes out the new 10-parameter format if the 8-parameter format is found. Swapped the max_zoom and min_zoom parameters to further down the data line. 2003-10-28 22:26 jtwilley * config/language-English.sys, src/main.c, src/maps.c, src/maps.h: Added support for max/min zoom levels. Work still needs to be done on removing existing zoom-level-sensitive code and supporting other languages. 2003-10-28 16:35 we7u * src/main.c: Moved the "XtRealize" call down lower in the routine, after the size has been specified. This is to help get rid of the "Error: Shell widget xastir has zero width and/or height" problem that some users have been having. 2003-10-28 16:29 we7u * src/main.c: Moving the "manage" call for the main app down lower after the size of the widget has been specified. Attempting to get rid of the "Error: Shell widget xastir has zero width and/or height" problem that some users are still having. 2003-10-28 15:46 we7u * src/xa_config.c: Setting screen_height and screen_width to minimums of 40 and 100. 2003-10-28 15:20 we7u * src/main.c: Getting rid of the auto-clear function for the map chooser topo and vector buttons. They are now additive instead of exclusive. 2003-10-28 07:02 n2ygk * src/list_gui.c: Fix X crash when list width/height somehow get set to zero. 2003-10-27 17:40 rzg * INSTALL, README.MAPS: Minor updates. I'm still around. :-) 2003-10-23 12:48 uid74947 * src/maps.c: Another comment. 2003-10-22 17:30 we7u * src/maps.c: Comment changes. 2003-10-22 17:22 we7u * src/maps.c: More comments. 2003-10-22 17:19 we7u * src/maps.c: Changing the scale at which the UTM subgrid starts to be drawn. We weren't drawing it properly at scales of 2048 and up anyway. 2003-10-22 17:15 we7u * src/maps.c: More comment changes. 2003-10-22 16:44 we7u * src/maps.c: Adding comments. More checking for invalid numbers in draw_grid(). 2003-10-22 16:19 we7u * src/maps.c: Commenting out some debug lines. 2003-10-22 16:06 we7u * src/maps.c: Fixing another bug in draw_grid() that caused a segfault while drawing UTM grids. Added more debug and comments. The segfault fix causes some grid lines to get skipped but that's better than a segfault. 2003-10-22 14:39 we7u * src/maps.c: More comment changes. 2003-10-22 14:08 we7u * src/maps.c: Correcting some comments. 2003-10-22 13:53 we7u * src/maps.c: Correcting some comments based on input from Peter Dana. 2003-10-22 13:50 we7u * src/maps.c: Added another comment. 2003-10-22 12:50 we7u * src/maps.c: Adding lots of comments in the draw_grid() function. Trying to understand Olivier's code for drawing UTM grids, so it can be improved in the areas of major grid intersections, and in handling the irregular zone widths. 2003-10-22 11:43 we7u * src/maps.c: Changed some comments. 2003-10-22 09:33 we7u * src/maps.c: Last log message should have said: Changed/updated some comments. No code changes. Same for this log message. 2003-10-22 09:32 we7u * src/maps.c: [no log message] 2003-10-22 06:57 n2ygk * README.MAPS, config/tgrlpt.dbfawk, src/map_shp.c: dbfawk symbol support for point shapefiles 2003-10-21 08:22 n2ygk * src/map_shp.c: duh - sym[4] to fit the null at the end! 2003-10-21 08:21 n2ygk * src/map_shp.c: sym[3] to allow for overlay char too 2003-10-21 08:20 n2ygk * README.MAPS: document "roll your own shapefile maps" 2003-10-19 15:31 we7u * src/main.c: Added a comment. No code changes. 2003-10-19 15:28 we7u * src/maps.c: Changing the UTM/UPS grid so that only two zones each are drawn at the poles (in the UPS region). 2003-10-19 15:26 we7u * src/datum.c: Fixing the output zone number in the UPS regions to "00". 2003-10-17 23:13 we7u * src/maps.c: Tweaking the UTM grid so that it extends to the poles, now that I know what the UPS grid (near the poles) should look like. 2003-10-17 22:55 we7u * src/: datum.c, datum.h, main.c, map_geo.c, maps.c, util.c: Implemented proper UTM/UPS to Lat/Long conversions. Also fixed the coordinate calculator so it would accept UPS coordinates. 2003-10-17 21:49 we7u * src/: datum.c, datum.h, main.c, map_geo.c, maps.c, util.c: Implemented proper UPS output, when using UTM/UPS and near the poles. 2003-10-17 20:22 we7u * src/datum.c: Temporarily making the easting and northing for the UPS areas (near the poles) equal to all zeroes. This is to prevent someone thinking that the numbers we're showing are valid coordinates. We haven't been computing proper coordinates in the UPS areas. Am still working on the problem and hope to have valid UPS numbers by the end of the weekend. 2003-10-17 14:21 we7u * src/datum.c: Changed some comments. Added some output if we're trying to convert a UPS coordinate to Lat/Long. 2003-10-17 13:39 we7u * src/: datum.c, datum.h: Changed utm_letter_designator() to properly handle the zones for UPS grid. Still need to get the easting/northing numbers to work right, but the zone letters are now correct. 2003-10-17 12:50 we7u * src/datum.c: Modified utm_letter_designator() function so that 'Z' is displayed above 84N, and 'A' is displayed below 80S. It's better than it was, but we still need to implement full UPS coordinate systems in the pole regions. 2003-10-17 12:38 we7u * src/main.c: Tweaking TrackMouse() so that the coordinates stop changing when the mouse goes off the edge of the earth. 2003-10-17 08:21 n2ygk * src/map_shp.c: still incomplete attempt at handling fill styles. 2003-10-17 08:19 n2ygk * config/: Makefile.am, tgrlpt.dbfawk: add tgrlpt (Tiger/Line landmark points) 2003-10-17 08:18 n2ygk * config/tgrlk.dbfawk: add complete documentation of CFCC codes 2003-10-17 02:13 we7u * bootstrap.sh: Added a line to remove the autom4te.cache directory and contents. This sometimes gets in the way when running autoheader, and I have to delete it manually in that case. No more. 2003-10-16 16:38 we7u * src/map_geo.c: Excluding map indexing from being able to set the map refresh interval. 2003-10-16 16:09 we7u * src/: map_gdal.c, maps.c: Minor comment changes. 2003-10-16 15:59 we7u * src/: map_gdal.c, maps.c: Dumping out map types on startup. 2003-10-16 14:48 we7u * src/map_gdal.c: Changed comments. No code changes. 2003-10-16 14:44 we7u * configure.ac: Moving the GDAL stuff after shapelib and libgeotiff. We want GDAL to get linked AFTER the other libraries, at least until we get GDAL fully integrated. If GDAL is linked earlier than these other libraries, function calls get made to GDAL instead of the correct libraries. 2003-10-16 14:42 we7u * src/map_tif.c: Added more debugging output. 2003-10-16 14:39 we7u * src/maps.c: Added more debug info. 2003-10-16 14:11 we7u * src/map_gdal.c: Minor stuff, getting ready to try to open a file. 2003-10-16 12:40 we7u * src/map_gdal.c: Printing out OGR drivers as well now. 2003-10-16 12:33 we7u * src/map_gdal.c: Nicer formatting for the GDAL drivers. 2003-10-16 12:30 we7u * src/map_gdal.c: Better formatting for listing GDAL drivers. Starting to add code to list OGR drivers as well. 2003-10-16 11:58 we7u * src/map_gdal.c: Print out a list of all registered GDAL drivers upon Xastir startup. 2003-10-16 09:56 we7u * src/map_gdal.c: Moved the #warning text inside the #ifdef block. Will only see the warning if GDAL is installed and usable on your system. 2003-10-16 09:48 we7u * src/map_gdal.c: Minor changes to comments. Removed a #define that shouldn't have been committed. 2003-10-16 09:42 we7u * src/map_gdal.c: Added example code snippets from the GDAL tutorial. 2003-10-16 09:07 we7u * configure.ac, src/main.c, src/map_gdal.c, src/maps.h: More initial framework for GDAL integration. Now adds it to the list of supported libraries in "configure", and adds the library to the link line. 2003-10-16 08:30 we7u * src/Makefile.am: Adding map_gdal.c to the list of files. 2003-10-16 08:29 we7u * src/map_gdal.c: Adding initial file framework for integrating the GDAL library. No real code here yet. 2003-10-14 13:49 we7u * src/map_geo.c: Another #ifdef fix regarding raster_map_intensity. 2003-10-14 13:44 we7u * src/main.c: More #ifdef cleanup regarding raster_map_intensity. 2003-10-14 13:37 we7u * src/: main.c, maps.h, xa_config.c: Fixing #ifdef's, consistent with new uses of raster_map_intensity variable (used to be geotiff_map_intensity). 2003-10-13 14:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Implementing Henk de Groot's icon outline code. Added code to make the changes instantly visible in the drawing area. Thanks Henk! 2003-10-13 14:30 we7u * src/: main.c, map_geo.c, map_tif.c, maps.c, maps.h, xa_config.c: Attached geo files to the raster intensity variable, so they can be darkened from the menus now. Had to hard-code toposerver images to be 100% brightness though, as the colors get strange on that particular image. Other images can be fixed by adding the "modulate" tag to the .geo file, if this problem should surface elsewhere. 2003-10-13 13:22 we7u * src/maps.c: More efficient snapshot code: Moved the .geo code back into the separate thread now that the symbol-blanking bug is fixed. 2003-10-13 12:57 we7u * src/maps.c: Fixed snapshots so that .geo file creation works without blanking symbols on the screen. The code was leaving incorrect values in global variables that were later used by the symbol drawing code. 2003-10-13 10:57 we7u * src/: main.c, maps.c, xastir.h: Fixing the symbols-going-away-after-snapshot problem. Unfortunately it appears that the .geo code for snapshots is the problem. Will have to figure out why yet and then reinstate that part of the code. 2003-10-12 21:22 we7u * src/: main.c, maps.c, xastir.h: Attempting to fix the snapshot problem where stations disappear off the display. Created another Pixmap: pixmap_snapshot, and copy pixmap_final to it just before the snapshot thread is started. This should separate any accesses to the data so that no conflicts occur while making the snapshot. 2003-10-09 19:20 we7u * src/maps.c: Tweaking the width of the equator line in UTM grid (again). 2003-10-09 19:14 we7u * src/maps.c: Minor changes to equator/prime meridian again for UTM. 2003-10-09 18:41 we7u * src/maps.c: Changing line widths for the lat/long grid and the major UTM zones to width 2. This makes them more noticeable against the smaller UTM subgrid and against map lines. 2003-10-09 13:16 we7u * src/maps.c: Changing the color for lat/long grids as well so that they work with the gc_tint stuff and show up on maps well. 2003-10-09 13:09 we7u * src/maps.c: Changing to gc_tint for map grids so that the grid can always be seen on top of maps. 2003-10-09 12:52 we7u * src/maps.c: Switching to purple lines as they show up well on topo and terraserver maps. 2003-10-09 12:47 we7u * src/maps.c: Changing the smaller UTM grids to display in bright yellow. Easier to see on maps. 2003-10-09 09:18 we7u * src/maps.c: Initial attempt at finer UTM grids, using preliminary code by Olivier Calle (N7TAP). The code handles the irregular regions near/above Norway for the major UTM grid zones only (not for the minor grids yet). There are known problems near the zone boundaries with lines not getting drawn or incorrect lines getting drawn. For the most part, if you're inside a zone and not in the irregular zone area, this code works very well, and is very fast! 2003-10-09 09:03 we7u * src/: db.c, main.c, map_geo.c: Changing a few printf's to fprintf's. 2003-10-08 12:48 we7u * src/maps.c: Simplified code for drawing UTM grid. 2003-10-08 12:12 we7u * src/maps.c: Changing the UTM grid to dashed lines instead of solid. 2003-10-08 11:31 we7u * src/maps.c: Proper UTM grid, including irregular areas near Norway. Area from 84N to 90N and 80S to 90S is still in question, as that is in the UPS coordinate system area (the poles). Also, the UTM coordinates on the status line are incorrect when the mouse pointer is moved into these areas. 2003-10-08 10:16 we7u * src/maps.c: More draw_vector stuff. Both Xastir coordinate system and lat/long vector drawing functions work now. Still need to work on the "is it in the view" code, as it's not working correctly.. 2003-10-08 09:42 we7u * src/maps.c: Added more UTM grid comments. 2003-10-08 09:37 we7u * src/maps.c: Adding a new draw_vector() function, which I'll use for drawing the UTM grid shortly. Changed/added a bunch of comments in draw_grid() regarding UTM. 2003-10-07 12:59 we7u * src/maps.c: Changed some comments. 2003-10-07 11:51 we7u * src/maps.c: Tweaked the boundary checks before the XDrawLine call. Added/changed some comments regarding UTM grid. 2003-10-06 19:41 we7u * src/maps.c: Initial UTM grid attempt. This mod causes the six degree vertical lines to be drawn that define the major UTM zones. It will draw them if the map grid is enabled and UTM is the selected coordinate system. 2003-10-02 16:51 we7u * src/db.c: Fixing the Pmin/Pmax stuff so that it gets transmitted properly across the air. 2003-10-02 13:21 we7u * src/maps.c: Xastir now creates a snapshot.geo file corresponding to the snapshot.png file. 2003-10-02 10:08 we7u * README.win32: Added a note about removing the "-local" option for nasd. 2003-10-02 07:09 n2ygk * src/main.c: Duh. Hung Map_font off of Gamma_correct button. 2003-09-30 06:57 n2ygk * INSTALL, README.MAPS: document dbfawk 2003-09-28 15:39 n2ygk * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Add map label font selection (please translate these!) 2003-09-28 00:03 we7u * src/xastir.h: Minor tweak to fix a compile problem in main.c with sizeof(). 2003-09-27 07:18 n2ygk * config/language-English.sys, src/awk.c, src/awk.h, src/dbfawk.c, src/main.c, src/map_shp.c, src/maps.c, src/xa_config.c, src/xastir.h: Add user-selectable MAPS_LABEL_FONT. Add dbfawk-selectable label color. Add "skip" keyword to dbfawk to permit overriding bad shapefile dbf data. 2003-09-26 16:34 we7u * README.win32: Clarified that maps can go in the maps directory and subdirectories thereof. 2003-09-26 16:26 we7u * README.win32: Added a note about possible problems with IM-5.5.7. 2003-09-26 16:22 we7u * README.MAPS: Specified where the sound files go. 2003-09-26 10:06 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added an "Apply" button to the Map Chooser that applies the changes immediately without destroying the Map Chooser. 2003-09-26 09:16 we7u * README.win32: Added note about Perl 5.8 and page faults while compiling. 2003-09-19 16:48 we7u * README.win32: Added a note about ImageMagick being necessary to view .geo maps. 2003-09-19 16:41 we7u * README.win32: Added a Win2k note. 2003-09-19 16:34 we7u * README.win32: Minor edits. 2003-09-19 16:06 we7u * README.win32: Added to more XFree86 packages to the selections. 2003-09-19 15:40 we7u * README.win32: Better fix for the _reent bug. 2003-09-19 15:37 we7u * README.win32: Added another note about the _reent bug. 2003-09-19 10:58 we7u * README.MAPS: Minor changes to the download NOAA weather alert maps section. 2003-09-19 10:57 we7u * src/util.c: Caused the code to recognize "NWS_" as valid. Didn't appear to be doing so, which might have been knocking out a lot of compressed weather alerts. 2003-09-19 10:57 we7u * src/db.c: Changed some comments. 2003-09-19 10:56 we7u * src/alert.c: Minor changes to comments and added another possible case for SOLAR that can get parsed (don't know if it'll ever get used). 2003-09-18 12:38 we7u * src/main.c: Setting the initial symbol to be a hiker when creating new object/item with probability circle toggle enabled. 2003-09-18 12:04 we7u * src/: main.c, db.c: Working implementation of SAR probability circles. 2003-09-17 17:24 we7u * src/: db.c, db.h, draw_symbols.c, draw_symbols.h, main.c: Half of an implementation for drawing Search & Rescue probability circles. Have the encoding parts and display parts done. Next need to do the decoding so that the circles show up on the map. 2003-09-16 10:46 we7u * src/xastir.h: Adding preliminary support for the libgc garbage collection library. Disabled by default. This gives automatic garbage collection of unused memory space to Xastir. During long runtimes, this seems to improve memory usage a bit. 2003-09-16 10:13 we7u * src/map_geo.c: Fixing trans_skip for the non-ImageMagick case. 2003-09-15 11:49 we7u * README.win32: Very minor wording change in the CVS instructions. 2003-09-12 07:48 n2ygk * configure.ac, src/dbfawk.c, src/map_shp.c: properly conditionalize WITH_DBFAWK. More dbfawk tweaks in map_shp 2003-09-11 15:04 jtwilley * src/dbfawk.c: Added check for DBFAWK define. 2003-09-11 13:19 n2ygk * config/nwsc_ddmmyy.dbfawk, src/map_shp.c: Fix a stupid error in symtbl 2003-09-10 13:53 rzg * help/help-English.dat: whatsnew update 2003-09-10 13:27 kd6zwr * README.MAPS, help/help-English.dat, src/map_geo.c, src/maps.h: Changing TRANSPARENT geo tag to accept a user defined color to zap. 2003-09-09 06:56 n2ygk * config/nwsc_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrwat.dbfawk, src/map_shp.c: more dbfawk tweaking 2003-09-08 07:37 n2ygk * config/nwsc_ddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, src/map_shp.c: more dbfawk tweaks. WX alerts now search properly. 2003-09-05 14:25 we7u * src/main.c: Removed some unneeded comments. 2003-09-05 14:12 we7u * src/main.c: Taking out the Move/Measure menu prevention logic for the case where the mouse buttons are _not_ swapped. 2003-09-05 13:20 we7u * src/main.c: Preventing the mouse menu from coming up if SWAP buttons is enabled and we're doing the Move or Measure functions. 2003-09-05 12:47 we7u * src/main.c: Added another define that allows moving the mouse menu to button1. 2003-09-05 12:07 we7u * src/main.c: Swapping zoom/pan buttons so that zoom buttons are more often on the screen with a small window size. 2003-09-05 06:56 n2ygk * config/: Makefile.am, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: First pass at handling WX alerts with dbfawk 2003-09-04 23:37 we7u * src/main.c: Added some notes about xmodmap for swapping mouse buttons in a touchscreen configuraton. 2003-09-04 15:48 we7u * config/language-English.sys: Making Z-In/Z-Out labels shorter to help fit on 640x480 LCD screen. 2003-09-04 15:28 we7u * src/main.c: Changing the optional SMALL system font. 2003-09-04 14:39 n2ygk * src/testawk.c: Make it compile even without DBFAWK 2003-09-04 14:22 we7u * INSTALL: Added a bit more about libgeotiff's private include directory. 2003-09-04 11:00 we7u * src/main.c: Another tweak for fixed-size small displays. This new define forces dialogs to pop up over the main application, near the left top corner. 2003-09-04 10:11 we7u * src/main.c: Adding an option for a much smaller default system font. Useful for smaller displays. 2003-09-04 10:10 we7u * config/language-English.sys: Making Zoom buttons smaller by shortening the string. Needed for smaller displays. 2003-09-04 09:40 we7u * src/: main.c, xa_config.c: Allowing much smaller screen sizes for Xastir. It should start up in roughly the same size as saved now also. 2003-09-04 09:18 we7u * src/main.c: Changing the minimum size for the main window down to 1/4 VGA. This allows it to be resized much smaller than before. Useful for fixed-size LCD displays. 2003-09-04 09:11 we7u * FAQ: Added a few more words about why stations might not appear on the screen. 2003-09-04 07:38 n2ygk * src/map_shp.c: more dbfawk tweaking 2003-09-03 17:01 we7u * INSTALL: Revised the libgeotiff instructions slightly. 2003-09-03 12:37 we7u * README.win32: Added "touch .cvspass" to the instructions. Some Windows boxes fail without this. 2003-09-03 11:26 kd6zwr * README.MAPS, help/help-English.dat: Documenting the new TRANSPARENT and CROP .geo file tags. 2003-09-03 08:19 n2ygk * configure.ac, src/Makefile.am, src/awk.c, src/dbfawk.c, src/dbfawk.h, src/map_shp.c, src/testawk.c: change to use WITH_DBFAWK. dbfawk now searches for mapfilename.dbfawk before looking in config/*.dbfawk, enabling map-specific special cases. 2003-09-03 00:28 kd6zwr * src/: map_geo.c, maps.h: Adding TRANSPARENT and CROP tags to the geo file. First cut at transparent, needs to be augmented to allow a list of colors to zap. 2003-09-02 16:43 jtwilley * configure.ac: Moved AM_INIT_AUTOMAKE and added arguments. Added documentation for AM_INIT_AUTOMAKE. 2003-09-02 14:05 n2ygk * config/tgrcty.dbfawk, src/map_shp.c: tgrcty: fix Louisiana FIPS code map_shp: start adding layer setting via dbfawk too 2003-09-02 10:50 we7u * README.win32: Added another comment about "nano" being more user-friendly than "vi", for people coming from a Windows background. 2003-08-30 13:41 jtwilley * src/awk.c: Added reference to to match dbfawk.c 2003-08-29 09:50 n2ygk * configure.ac, config/Makefile.am, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrwat.dbfawk, src/Makefile.am, src/awk.c, src/awk.h, src/dbfawk.c, src/dbfawk.h, src/gps.c, src/map_shp.c, src/testawk.c, src/tgrcty.dbfawk, src/tgrkgl.dbfawk, src/tgrlk.dbfawk: gps.c: handle spurious compile time warning everything else: add dbfawk support for shapefile maps. Enable with: ./configure --with-dbfawk 2003-08-22 21:37 we7u * src/interface_gui.c: Adding another #include, needed for usleep() call. 2003-08-21 15:01 we7u * src/db.c: Changed some comment formatting. 2003-08-21 14:10 we7u * src/interface_gui.c: Adding a delay after shutting down a port before it is brought up again. These delays are in the interfaces->properties menu when changing an interface that's running. 2003-08-21 12:31 we7u * src/: db.c, db.h: Added a new flag to WeatherRow called wx_storm. We wet it when we find any kind of a severe storm, then use that flag in our logic that decides how to draw things. This gets rid of wind barbs for some severe storms. 2003-08-21 11:01 we7u * scripts/inf2geo.pl: New revisions by ZL2UMF. Thanks! 2003-08-21 09:42 we7u * src/igate.c: We now drop generic queries heading to RF. Also tweaked the log reject messages to be more consistent. 2003-08-21 09:30 we7u * src/igate.c: Removed the '*' requirement for TCPXX*, so we now reject anything with TCPXX in it. Added NOGATE options for dropping packets to all igate functions. Added generic query rejection for gating to 'net. Still need to add it into the gate-to-rf code. 2003-08-20 12:55 we7u * symbols/symbols.dat: Changing the "smoke" symbol so that it shows a volcano instead of a smokestack. This is more inline with the reason the weather server puts out these symbols, and is more recognizable than the smokestack symbol anyway. 2003-08-20 11:05 we7u * src/main.c: Changing the network port check from 7.5 minutes down to one minute. This should reconnect ports more quickly if/when they go down. 2003-08-18 16:16 we7u * src/db.c: Removing a back-slash that got in there accidentally. 2003-08-18 15:46 we7u * src/db.c: Getting the sort order correct for inserting records into the station database. Didn't work well with the wrong order. 2003-08-18 11:09 we7u * src/db.c: Commenting out some speedup code in station_shortcuts_update_function() that may be causing problems at present. 2003-08-18 10:40 we7u * src/maps.c: Henk's fix to a pointer problem that I created recently. 2003-08-16 23:04 we7u * src/db.c: Fixing a bug in the hash table code which looks for station matches. Making the clear all stations function faster by clearing out the hash table first. 2003-08-15 18:40 we7u * src/maps.c: Making index_retrieve() faster by relying on alphanumerical ordering of the map files in the index list. We now save the pointer between runs, and start searching the list at the point we left off. 2003-08-15 18:12 we7u * src/main.c: Minor comment cleanup and removing dead code. 2003-08-15 18:04 we7u * src/main.c: Better pointers for Map Chooser select updates. 2003-08-15 17:53 we7u * src/main.c: Changing from n*n searches to n searches for updating selected bits when closing Map Chooser. 2003-08-15 17:12 we7u * src/interface.c: Bumping out of port_read less often. This is only to check whether the thread should be taken down anyway. If a packet is waiting for us to read it, we'll wake up out of the select() anyway. 2003-08-15 16:55 we7u * src/main.c: Rearranging some if statements to get a little more speed out of it. 2003-08-15 16:11 we7u * src/: main.c, maps.c, maps.h: Added caching of XmString values corresponding to the map filenames for the Map Chooser. The first time bringing up Map Chooser will be at the same speed as before. Second and succeeding invocations of the Map Chooser should be a bit faster because the XmString's are used from the map index records again instead of being created from scratch each time. 2003-08-15 12:30 we7u * src/interface.c: CPU-usage optimization tweak to port_read(). 2003-08-15 12:11 we7u * src/: interface.c, main.c: CPU-usage tweak for dtr_all_set calls. It was getting called constantly whenever an HSP port was enabled. 2003-08-15 11:51 we7u * src/maps.c: CPU-usage tweak to index_retrieve(). 2003-08-15 11:20 we7u * src/db.c: Yet another CPU-usage tweak. This one is to search_station_name(). It's more efficient now at finding stations in the linked list, using a hash table as a jumping-off point. 2003-08-14 15:02 we7u * src/map_shp.c: Changing the level at which shorelines get drawn. 2003-08-14 14:59 we7u * src/map_shp.c: Setting up more levels at which things won't be drawn. Will make things faster/less cluttered. 2003-08-14 14:46 we7u * src/map_shp.c: Optimizing shapefile vector drawing. We don't convert the coordinates for each point now unless we're going to draw the darn thing. 2003-08-14 13:52 we7u * src/maps.c: More speedups. 2003-08-14 13:27 we7u * src/map_shp.c: Added some comments. 2003-08-14 09:12 we7u * src/: main.c, maps.c, maps.h, xastir.h: First part of speeding up Shapefile drawing by staying with lat/long values as much as possible, rather than doing conversions to Xastir coordinate system at every step. The end goal is to do as little math as possible to put pixels on the screen. These changes give a slight speedup to shapefile drawing, noticeable only when loading lots of maps. 2003-08-13 16:26 we7u * src/map_shp.c: Reverting back to last version. Floats made CPU-usage worse in this case. 2003-08-13 15:49 we7u * src/map_shp.c: Speedups. Using floating point operations instead of unsigned longs. 2003-08-13 12:45 gstueve * .cvsignore, callpass/.cvsignore, config/.cvsignore, help/.cvsignore, m4/.cvsignore, scripts/.cvsignore, src/.cvsignore, symbols/.cvsignore: Ignore generated files within CVS base. 2003-08-13 12:38 we7u * src/draw_symbols.c: Made the symbol() routine more efficient. Uses much less CPU now. 2003-08-12 11:48 we7u * src/interface.c: More performance improvements. 2003-08-12 11:45 we7u * src/popup_gui.c: Another performance improvement. Only check for expired popups every two minutes. 2003-08-12 10:29 we7u * src/bulletin_gui.c: Another performance improvement. The timing was set up such that find_zero_position_bulletins() ran every time UpdateTime() was started. We now wait 15 seconds between each invocation. 2003-08-11 16:57 we7u * src/: db.c, messages.c: More optimizations for speed/CPU-usage. Hash table entry creation is now more efficient. Check_and_transmit_messages now gets skipped if we ran it already that second. 2003-08-11 16:15 we7u * src/main.c: Added a comment. 2003-08-11 16:05 we7u * INSTALL: Added RH9 ImageMagick instructions, courtesy of Wes Johnston. 2003-08-11 15:40 we7u * src/: db.c, main.c: Moved station # display code from db.c to main.c:UpdateTime() so that the number of stations will accurately reflect our count even when no packets are coming in. 2003-08-11 15:08 we7u * src/interface.c: Another performance/CPU-usage tweak. 2003-08-11 14:48 we7u * src/main.c: Another performance tweak. This one lets you handle multiple high-speed 'net connections and keeps up with the receive queues. 2003-08-11 14:07 we7u * src/interface.c: Performance enhancements. Helps Xastir to keep up with very fast network interfaces. 2003-08-11 13:24 we7u * src/main.c: Making UpdateTime() run more often, which helps us keep up with fast internet feeds. 2003-08-11 12:57 we7u * src/db.c: Changing how often we check for stations and messages to expire from our database. This should also reduce CPU usage. 2003-08-11 11:31 we7u * src/bulletin_gui.c: Another CPU-usage tweak. Running through all of the messages looking for new bulletins every 15 seconds instead of every 2. Keeps mscan_file() calls down a bit, which is using a lot of CPU if run often. 2003-08-11 07:04 n2ygk * src/: awk.c, awk.h, dbfawk.c, dbfawk.h, testawk.c: Save a newer snapshot of in-progress code. Still not baked. 2003-08-08 18:03 we7u * src/db.c: Implementing a 14-bit hash table for station record lookup. This appears to have a BIG effect on CPU usage. May be a bit before the codebase is stable again though, but the gains are definitely worth it. It gives us a feeling for what an SQL database will do for us. 2003-08-08 16:16 we7u * src/db.c: Implemented an array of pointers for the station linked list. Each entry represents one possible starting letter/number for the callsign. We use this to speed up the search for a particular record, which is our hardest hitter in terms of CPU-usage right now. This appears to reduce Xastir's CPU requirements by quite a bit, particularly when a lot of stations are in the database. 2003-08-07 13:47 we7u * src/draw_symbols.c: Backing out one change which broke the port activity symbols. They're working again now. 2003-08-07 10:01 we7u * src/Makefile.am: Taking out the awk/dbfawk stuff temporarily until it can be compiled on most systems again. 2003-08-06 17:54 we7u * src/maps.c: Another speedup. 2003-08-06 16:19 we7u * src/draw_symbols.c: Speeding up the loading of symbols. 2003-08-06 16:18 we7u * src/lang.c: Breaking out of a loop as soon as we get a non-match. 2003-08-06 10:43 we7u * README.win32: Added a note regarding Windows not allowing access to files at times. 2003-08-05 07:34 n2ygk * src/: Makefile.am, awk.c, dbfawk.c, dbfawk.h, testawk.c: more dbfawk utility functions. I'll be integrating this into map_shp.c RSN! 2003-08-04 16:13 we7u * src/main.c: Another small change which makes a difference in CPU usage. 2003-08-04 15:36 we7u * src/draw_symbols.c: Changing draw colors only when necessary. Found this one while profiling using gprof. May be more to change in this procedure to speed things up a bit.. 2003-08-02 10:00 we7u * src/main.c: Tweaked Coordinate Calculator so that it checks lat/long minutes/seconds values for negative numbers and >= 60.0. If out-of-range numbers are found, the error text is displayed in the dialog and a warning message is written to STDERR with a bit more detail on the problem found. Later this STDERR output should probably go to a popup or the main dialog instead, and language strings should be created for them. 2003-07-31 09:01 we7u * src/view_message_gui.c: Making the Close button larger. 2003-07-31 08:21 we7u * src/view_message_gui.c: Made the View->All Messages dialog resizable in both directions. 2003-07-31 06:00 we7u * src/bulletin_gui.c: Fixed View->Bulletins dialog so that it is resizable in both directions. 2003-07-27 22:20 we7u * src/: db.c, main.c: Improved Display Packet Data dialog. This one is resizable and very fast. Much better than the previous implementation. 2003-07-26 17:11 we7u * symbols/symbols.dat: Added the MODIS Earth Observation symbol. Added a comment specifying where to find the color definitions used for symbols. 2003-07-26 09:35 we7u * src/map_dos.c: Commented out some fprintf's that were getting quite verbose when certain Win/DOS maps were loaded. Warnings were that we were trying to call draw/fill polygon routines with 1 or 2 points. 2003-07-25 13:00 we7u * src/main.c: Cranked up the delay on REDRAW from 2 to 3 seconds. Changed the dead-reckoning code to schedule a map redraw instead of doing on itself (which probably duplicated some drawing). CPU usage seems to be down because of these changes. 2003-07-25 11:18 we7u * src/gps.c: Improved GPS parsing code. Fixed buffer overflow problems and restructured code. 2003-07-25 07:36 we7u * src/: gps.c, interface.c: Added line-terminations after strncpy() calls and a bunch of comments at those places as well. 2003-07-24 14:18 we7u * src/main.c: Adding more comments. 2003-07-24 14:14 we7u * src/: db.c, main.c: Adding uncompressed altitude extension to compressed objects/items. 2003-07-24 09:17 we7u * README.win32: Some very minor changes to the Cygwin instructions. 2003-07-24 06:33 n2ygk * src/: awk.c, testawk.c, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk: Add some samples dbfawk files. Remove incorrect "re" pointer. 2003-07-23 14:34 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, util.c: We now copy the map pixmap to the display if we're loading maps when the interrupt_drawing_now variable gets set. 2003-07-23 13:29 we7u * src/map_shp.c: Changing the quantites of labels drawn for each zoom level. 2003-07-23 12:17 we7u * src/: Makefile.am, map_geo.c, map_tiger.c, maps.c: Fixes for handling various combinations of Xpm/ImageMagick libraries installed/not-installed. Re-ordered the compile order for the source files to mostly alphabetical order. 2003-07-23 10:33 we7u * src/: db.c, location.c, main.c, main.h: Adding more map interrupt capability to tracking and button callback functions. 2003-07-23 09:20 we7u * README.win32: Added a note about spaces in filenames/directories/user accounts. 2003-07-22 13:13 we7u * src/map_shp.c: Fixing colors so that generated map files put into the maps/GPS directory will show up properly. 2003-07-22 11:15 we7u * README.win32: Changed View to Full for selecting packages. Added pcre and pcre-devel to the list. 2003-07-22 07:11 n2ygk * src/: awk.c, awk.h, testawk.c: add begin, end_rec. Add some dbf stuff to testawk.c 2003-07-21 09:51 we7u * src/awk.c: Initializing a pointer to NULL to get rid of another compiler warning. 2003-07-20 10:44 n2ygk * src/: awk.c, awk.h, testawk.c: Make awk.* cleanly compile with -Wall 2003-07-18 14:05 we7u * src/: main.h, main.c, maps.c: Setting up code so that the Disable All Maps toggle will immediately take effect while loading maps. 2003-07-18 13:58 we7u * configure.ac: Removing -Wall from configure.ac. Jack Twilley added the correct fix to acinclude.m4. 2003-07-18 13:52 jtwilley * acinclude.m4: Wrapped gcc-specific tests in an if test for gcc. Added -Wall to CFLAGS when using gcc. 2003-07-18 13:15 we7u * configure.ac: Adding "-Wall" to CFLAGS. Not sure if this is the perfect way to get it included into src/Makefile, but this method definitely works. 2003-07-18 12:49 we7u * src/gps.c: Adding a define necessary before including time.h, in order to get strptime() function defined on some versions of Linux. 2003-07-18 12:12 we7u * src/interface.c: Adding casts to first parameter of pthread_cleanup_push() so that after macro substitution the compiler is still happy with the 2nd parameter of _pthread_cleanup_push(). 2003-07-18 11:13 we7u * INSTALL: Removing tabs. 2003-07-18 06:14 rzg * help/help-English.dat: Moved some stuff around, AGWPE now a section, minor corrections. 2003-07-17 19:29 n2ygk * INSTALL, configure.ac, src/Makefile.am, src/awk.c, src/awk.h, src/testawk.c: Start adding support for my awk-like metadata for shapefiles: Tests for -lpcre, documentation of where to find pcre, and awk.c, awk.h which is the code that will be called once I get the nerve to do some serious hacking on map_shp.c:-) 2003-07-17 14:54 we7u * README.win32: Added another note about the .cvspass file. 2003-07-17 12:37 we7u * src/util.c: Fixing timezone for non Cygwin systems. #ifdef's were a bit wrong. 2003-07-17 12:25 we7u * README.win32: Adding a few more error messages that might occur while doing CVS operations. 2003-07-17 08:28 we7u * src/db.c: Making Tropical Storm/Tropical Depression/Hurricane wind speed rings disappear at the ghosting time. 2003-07-16 14:07 we7u * src/interface.c: Installing thread cleanup routines. These should take care of unlocking mutex's when the threads terminate for any reason. Should keep the rest of the program running. 2003-07-15 22:25 we7u * README.win32: Changing the note about creating the .cvsrc file. Trying to make it VERY CLEAR that a Unix-type editor must be used. 2003-07-15 15:58 we7u * src/util.c: Changing the begin_critical_section() functio (mutex locks). If a resource has already been locked, output a warning message and skip trying to lock again. This should allow Xastir to recover should locks or unlocks be tried twice or more in sequence. Warning messages will get printed, but the threads should continue to run. 2003-07-15 15:42 we7u * src/main.c: Adding the busy cursor in a couple of places so that we have a better indication of when map drawing is taking place. 2003-07-15 13:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Cranking up the GPS timing if it is set lower than 3 seconds. We also now present a popup to the user to notify them that the GPS timing has been changed. 2003-07-15 13:23 we7u * src/main.c: Adding a timeout for HSP ports for GPS listener mode. 2003-07-15 12:34 we7u * src/interface.c: First attempt at fixing some of the HSP interface's problems. This one will send strings other than GPGGA and GPRMC through the normal decoding sequence. That will at least process received TNC strings, which the previous code did not. 2003-07-15 11:13 we7u * src/util.c: Skip copying final pixmap to display if we have a map interrupt. 2003-07-15 11:08 we7u * src/map_tiger.c: Commenting out a bunc of the map interrupt code to see if it eliminates segfaults that some users are seeing. 2003-07-15 07:17 n2ygk * src/: alert.c, color.c, color.h, db.c, list_gui.c, main.c, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h, util.c, xa_config.c, xastir.h: Update to newer emacs c-basic-offset 2003-07-14 14:37 we7u * README.win32: Changed "diff" to "diffutils", as they apparently changed what package "diff" could be found in. 2003-07-14 14:26 we7u * README.win32: Adding a blurb about the final-final dialog for Cygwin installs that must have it's OK button pressed for the whole thing to finish. 2003-07-14 13:31 we7u * help/: help-English.dat, help-German.dat, help-Italian.dat, help-Portuguese.dat, help-Spanish.dat: Changing docs to match new /usr/local/share/xastir/* directories. 2003-07-14 13:24 we7u * FAQ, INSTALL, README.MAPS, README.win32, UPGRADE: Changing docs to match newer /usr/local/share directory structure. 2003-07-11 08:44 we7u * src/util.c: GMT -> Localtime fixes for both Unix and Cygwin. 2003-07-10 13:25 we7u * src/util.c: Timezone changes for Cygwin. 2003-07-10 12:06 we7u * src/interface.c: Changes for HSP. 2003-07-10 12:00 we7u * src/draw_symbols.c: Forcing expire of severe weather polygons at a 10 minute interval, ignoring the user-settable ghosting period for these objects. 2003-07-09 17:18 we7u * src/main.c: Changing one comment. 2003-07-09 17:18 we7u * src/interface.c: Changing some usleep's throughout. Mostly making them larger, having to do with starting/stopping interfaces. 2003-07-09 17:04 we7u * src/interface_gui.c: Backing out a few of the TAB_GROUP items. Don't work for some widgets. Cause segfaults. This version appears to work properly. 2003-07-09 16:34 we7u * src/interface_gui.c: Setting up tab groups for all of the interface GUI dialogs. 2003-07-09 15:55 we7u * src/interface_gui.c: Fixing tab groups for Interfaces->Properties dialog for internet servers. Probably more to come for other interface types. 2003-07-09 15:26 we7u * src/draw_symbols.c: Detaching multipoint object drawing from the "Include Expired Data" toggle. They now expire at the ghosting interval. 2003-07-09 15:02 we7u * src/xa_config.c: Making the default for displaying old data equal to zero now instead of 1. 2003-07-07 16:51 we7u * src/main.c: Causing display updates once per 60 seconds, even with no input triggers. 2003-07-07 16:19 we7u * src/map_shp.c: Adding in maximum zoom levels for various water features. They still need fine-tuning. 2003-07-07 14:30 we7u * src/db.c: Added a limit to the number of trackpoints displayed in Station Info. This prevents lockups when display Station Info on extremely long paths, for instance: TrackMe with GPS enabled, displaying Station Info on my own station. 2003-07-07 14:20 we7u * src/main.c: Added in the map interrupt stuff for drawing symbols/tracks. Maps and symbols/tracks now appear to be drawn & interrupted together. 2003-07-07 13:56 we7u * src/interface.c: Tweaks for HSP interfaces. DTR should be reset now after sending waypoint strings out to the GPS on an HSP port. 2003-07-07 13:23 we7u * src/main.c: Changed some comments. 2003-07-07 13:22 we7u * src/interface.c: Changed a comment. 2003-07-07 11:09 we7u * scripts/xastir-fixcfg.sh: Script now removes the map_index.sys file and moves the selected_maps.sys file to selected_maps.sys.backup 2003-07-07 10:57 we7u * src/maps.c: Changed some comments. 2003-07-07 10:17 we7u * scripts/icontable.pl: Changed path to match new Xastir directory structure. 2003-07-07 09:33 we7u * UPGRADE: Added instructions for migrating to Xastir's new directory structure. 2003-07-05 08:28 n0vh * scripts/fcc-get: Updated to reflect the new directory structure. 2003-07-04 15:17 we7u * scripts/xastir-migrate.sh: Changing script so that it deletes the old files and not the new. 2003-07-04 12:32 we7u * src/: db.c, location.c, main.c, main.h, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c: A better implementation of the interrupt-map-loading function. We still end up with tracks/stations drawn strangely when we first interrupt, but that's the next problem I'll tackle. 2003-07-04 10:10 rzg * help/help-English.dat: Listing the last few changes... 2003-07-04 02:11 we7u * src/main.c: Made some of the mouse and keyboard operations interruptible. 2003-07-03 14:30 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c: More map interrupting capability. Currently works for resizing quite nicely. 2003-07-03 13:23 we7u * src/: map_geo.c, maps.c: Adding in more map drawing interruption capability. 2003-07-03 12:13 we7u * src/: main.c, main.h, maps.c: Added some flags that get set by da_resize, which then immediately exits allowing X11 to continue. If interrupt_drawing_now is set, map drawing ceases after the map we're currently loading is finished. If request_resize is set, then a resize operation is started by UpdateTime. We can add checks for interrupt_drawing_now to other routines later in order to stop map drawing more quickly. Next is to do a similar thing for the da_input function, so that a keypress or mouse click can interrupt map loading. 2003-07-03 10:32 n2ygk * scripts/Makefile.am: eliminate duplicate config data 2003-07-03 10:07 n2ygk * xastir.spec.in: Patches are now integrated in the main trunk. 2003-07-02 14:49 we7u * scripts/: migrate-config.sh, migrate-dirs.sh: Removed these two files in favor of two new files by Alan. 2003-07-02 14:48 we7u * scripts/: xastir-fixcfg.sh, xastir-migrate.sh: Minor tweaks. Added Id tags for CVS and more directories. 2003-07-02 14:19 n2ygk * Makefile.am, configure.ac, config/Makefile.am, help/Makefile.am, scripts/Makefile.am, symbols/Makefile.am: Changed locations of shared xastir files. After make install you should run scripts/xastir-migrate.sh and scripts/xastir-fixcfg.sh. The former fixes the shared files directory. The latter fixes your personal xastir.cnf references to those shared files. 2003-07-02 14:03 n2ygk * scripts/: Makefile.am, xastir-fixcfg.sh, xastir-migrate.sh: Add xastir-fixcfg.sh and xastir-migrate.sh 2003-07-02 08:49 we7u * README.win32: Added a chmod command for creating a script for starting Xastir. 2003-07-02 07:11 n2ygk * src/map_dos.c: fix reversed cleanup of __LCLINT__ ifdef that was wrong. 2003-07-01 23:10 we7u * src/map_dos.c: Fixed some minor bugs w.r.t. DOS map decoding. 2003-06-30 14:37 we7u * src/maps.c: Fixing a naming problem for a variable. 2003-06-30 09:53 we7u * src/maps.h: Adding more prototypes needed by some of the map files that have been newly separated out from maps.c. 2003-06-30 09:52 we7u * src/maps.c: Commenting out an unused function. 2003-06-30 09:52 we7u * src/map_dos.c: Commenting out some unused variables. 2003-06-26 08:37 n2ygk * src/: Makefile.am, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h: split maps.c into several map-specific files. 2003-06-25 12:00 we7u * src/main.c: Update tracking station call if TrackMe is enabled when we change our own station callsign. 2003-06-22 12:48 we7u * src/maps.c: Decoding school district types in shapefiles and displaying as a yellow border. 2003-06-20 19:06 we7u * src/main.c: More moving save station trail and GPSMAN functions to use the local users' ~/.xastir/gps and ~/.xastir/tracklogs directories. 2003-06-20 19:05 we7u * src/maps.c: Starting to move GPS and Save station trail functions so that they use ~/.xastir/gps and ~/.xastir/tracklogs directories. 2003-06-20 18:27 we7u * src/: maps.c, track_gui.c: Shortening the temp files to get rid of "xastir_" and the username. 2003-06-20 16:55 we7u * src/: main.c, track_gui.c, maps.c: Moving temporary files into the users ~/.xastir/tmp directory. 2003-06-20 16:10 we7u * src/maps.c: Changing default auto_maps for directories and .geo files to 0. 2003-06-20 15:52 we7u * scripts/: migrate-config.sh, migrate-dirs.sh: Migration scripts by Alan Crosswell, N2YGK. 2003-06-20 15:29 we7u * src/track_gui.c: Added some comments regarding the date/timestamp that's available on findu.com for track downloads. 2003-06-20 14:57 we7u * src/: db.c, draw_symbols.c, draw_symbols.h, main.c: Tweaks to display signpost symbol data next to symbol. Also allow letters now instead of just digits, as the spec appears to allow this. Next thing to bring us fully into compliance is to only show the signpost data at close-in zoom levels (minor), and perhaps also to show the data on top of the sign (also minor). 2003-06-18 11:40 we7u * src/main.c, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys: Fixes for the Map Chooser confusion regarding the clear and the map-type selection buttons. 2003-06-18 11:12 we7u * src/maps.c: Tweaks by Derrick J Brashear, KB3EGH, to handle non-USGS geotiff images properly. 2003-06-17 21:13 rzg * help/help-English.dat: Beginnings of new BETA section, list form... 2003-06-17 18:29 kd6zwr * src/maps.c: Adding check for raster maps that are too big or small for display. define FUZZYRASTER to enable. 2003-06-17 17:24 we7u * config/xastir.rgb, src/main.c: Making a color change that Henk wanted, so that yellow tracks can be seen on top of yellow map fills. 2003-06-17 17:02 we7u * src/maps.c: Added MAP_SCALE_CHECK define and associated code. Will skip maps whose extents are smaller than 4% of the view size. The define is commented out by default so that the check is not performed. 2003-06-17 12:48 we7u * src/xa_config.c: Added a comment. 2003-06-16 15:56 we7u * src/interface.c: Support for sequence numbers in OpenTrac packets. Can send multiple positions in one packet. 2003-06-16 13:48 we7u * help/help-English.dat: More details on the REFRESH .geo tag. 2003-06-16 11:50 we7u * src/interface.c: Fixing a small bug in the OpenTrac text output regarding symbols. 2003-06-16 11:49 we7u * src/: db.c, maps.c, util.c: Changing puts() calls to fprintf(). 2003-06-16 10:34 we7u * help/help-English.dat: Added the REFRESH tag description for .geo files. 2003-06-15 17:33 we7u * configure.ac: Bumping rev number past the last stable rev number. 2003-06-14 00:19 we7u * src/interface.c: Translating from OpenTrac symbols to APRS symbols. 2003-06-13 22:35 we7u * src/interface.c: Taking out devel code that's not working yet. 2003-06-13 18:47 kd6zwr * src/: main.c, main.h, maps.c: Added REFRESH tag to geo files. 2003-06-13 16:34 we7u * src/interface.c: Terminating the list with empty strings. 2003-06-13 16:08 we7u * src/interface.c: Adding a symbol translation table for OpenTrac. Not used in the code yet. 2003-06-13 15:22 we7u * src/interface.c: Initial OpenTrac decode routines. Implemented only for AX.25 interfaces to date. 2003-06-13 15:17 we7u * src/maps.h: Adding an export for a routine which will be needed in interface.c soon. 2003-06-13 14:15 we7u * configure.ac: Bumping rev up to 1.2.0 in preparation for stable release. 2003-06-13 13:42 rzg * help/help-English.dat: Adding a bit about the green and blue weather boxes (multipoints) 2003-06-11 11:15 we7u * help/: help-English.dat, help-Portuguese.dat: Fixed some of the FIXME's. 2003-06-11 10:42 we7u * help/: help-German.dat, help-Portuguese.dat: Changed "BETA" to "1.2". 2003-06-11 10:32 rzg * help/help-English.dat: Release will be 1.2 2003-06-08 09:15 we7u * src/gps.c: Removing tabs (again). 2003-06-07 15:43 kd6zwr * src/gps.c: fixing null pointer reference 2003-06-07 15:43 kd6zwr * src/db.c: fixing compiler warnings 2003-06-07 07:19 francais1 * config/language-French.sys: Updated 2003-06-07 00:29 we7u * config/language-Italian.sys: A few more translations by Marco Calistri, IK5BCU. 2003-06-06 17:34 we7u * src/draw_symbols.c: Changing tabs to spaces. 2003-06-06 17:19 we7u * src/main.c: Converting more tabs to spaces. 2003-06-06 17:12 we7u * src/track_gui.c: Changing more tabs to spaces. 2003-06-06 17:04 we7u * src/: interface.c, maps.c: Changing more tabs to spaces. 2003-06-06 16:57 we7u * src/: db.c, igate.c, popup_gui.c, wx_gui.c, xa_config.c: Removing tabs that snuck into the source code. Replaced with spaces. 2003-06-06 12:50 we7u * src/maps.c: Adding another error message in Snapshot thread. If we get a system() call error but errno is zero, this fprintf() will get triggered. 2003-06-06 12:49 we7u * src/db.c: Changes by Henk de Groot, PE1DNN. 2003-06-06 12:37 we7u * README.win32: More revisions to the note about modifier keys. 2003-06-05 17:02 we7u * README.win32: Added a few notes about the libraries which currently cannot be used with Cygwin. 2003-06-05 16:56 we7u * README.win32: Revising a few notes. Added a new section detailing how to keep Cygwin and Xastir up-to-date. 2003-06-05 13:55 we7u * src/maps.c: Checking errno in snapshot routine if the system call returns a possible error. 2003-06-05 13:11 we7u * acinclude.m4, src/maps.c: Reverting back to older snapshot method. Removing configure message regarding old ImageMagick versions, as even the old versions appear to currently work with the Tigermap intensity slider. 2003-06-05 10:54 we7u * src/db.c: Changes by Henk de Groot, PE1DNN. Fixes weather packet parsing problems for packets containing spaces or dots in place of data. 2003-06-05 10:05 we7u * README.win32: Added notes about X modifier keys and Cygwin web sites. 2003-06-05 09:53 we7u * README.win32: Adding more notes about Cygwin's network installer. 2003-06-04 15:35 rzg * help/help-English.dat: Fixing the formatting in a few spots and correcting an unlear statment. 2003-06-04 09:05 we7u * src/: maps.c, track_gui.c, util.c, util.h: Fixing a bug where we don't return from map routines properly on a libcurl error. 2003-06-03 14:49 we7u * src/main.c: Fixing a bug in the Map Chooser which occurs when deselecting files. It was putting a warning message to STDERR. 2003-06-03 14:31 we7u * FAQ: Added a note about color tinting using Hummingbird eXceed. 2003-06-03 14:01 we7u * README.win32: Added notes about totally black images for geotiff files and how to fix it. 2003-06-02 16:58 we7u * src/maps.c: Knocking out the snapshot code for the case where ImageMagick isn't present. When Jack is finished, he can take the #ifdef back out. 2003-06-02 16:23 jtwilley * src/maps.c: Use new acinclude.m4 logic to include correct ImageMagick header. 2003-06-02 16:20 jtwilley * acinclude.m4: Added extra header checks for ImageMagick. 2003-06-02 02:49 jtwilley * src/maps.c: Replaced XpmWriteFileFromPixmap + system("convert") with ImageMagick code 2003-05-30 22:47 we7u * src/maps.c: Fixing some ambiguous if/else bracing. 2003-05-30 22:43 we7u * src/db.c: Fixing some ambiguous if/else braces. 2003-05-30 15:51 jtwilley * acinclude.m4: Checked in fabulous new ImageMagick code. 2003-05-30 12:16 we7u * src/maps.c: Protecting some draw functions from getting called with too few vertices. 2003-05-30 11:54 we7u * src/rotated.c: Added code to skip XFillPolygon() call if the number of points is too few or negative. 2003-05-30 11:44 we7u * src/draw_symbols.c: Added some comments. No code changes. 2003-05-29 08:27 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Spanish.sys: Changing spacing slightly to align Map Properties dialog column headings. 2003-05-29 08:26 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-29 08:25 we7u * config/language-Italian.sys: Changes by Alessandro Frigeri, IK0YUP. 2003-05-28 17:12 we7u * README.win32: Added instructions for snagging/installing liblcms, needed by later versions of ImageMagick. 2003-05-28 16:21 we7u * src/maps.c: Terraserver changed to a new hostname. Changing to correspond. 2003-05-28 13:33 we7u * config/language-German.sys, help/help-German.dat: Changes by Rolf Bleher, DK7IN. 2003-05-28 13:24 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 12:58 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-28 12:57 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-28 11:49 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 11:18 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 11:09 we7u * config/language-German.sys: Translation of "Moisture" by Rolf Bleher, DK7IN. 2003-05-28 10:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: More translations. Also changing "meters" to "m". 2003-05-28 10:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Changing a few more hard-coded strings. 2003-05-27 18:00 rzg * help/help-English.dat: Grammar corrections. :-P 2003-05-27 16:44 we7u * INSTALL, README.win32: More ImageMagick notes. 2003-05-27 15:24 we7u * src/db.c: Fixed how we handle space/dot-filled temperature/humidity fields. 2003-05-27 13:43 we7u * src/main.c: Commenting out the new ifdef. Forgot to after testing. 2003-05-27 13:40 we7u * src/: main.c, interface_gui.c: Separated out the LARGE_FONT #ifdef's into two: USE_LARGE_SYSTEM_FONT and USE_LARGE_STATION_FONT. This is to help the visually impaired. Made the cursor position visible in more of the Interfaces->Properties dialogs. 2003-05-27 13:25 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-27 10:57 we7u * help/help-English.dat: Clarified the note about IMAGESIZE being required for .geo files with URL's, optional for local images. 2003-05-27 10:56 we7u * README.MAPS: Another note about IMAGESIZE being a required parameter for .geo files with URL's in them. 2003-05-24 22:52 we7u * src/: maps.c, popup_gui.c: Moved some code and added comments to make it very obvious that fonts are not to be loaded often. Causes memory leaks. 2003-05-24 21:58 we7u * src/main.c: Adding a method to switch to larger fonts, helpful to visually-impaired users. Uncomment the USE_LARGE_FONTS #ifdef at the top of main.c to enable these larger fonts. Off by default. 2003-05-24 00:57 we7u * src/main.c: Re-doing the widget geometry for the Configure->Audio Alarms dialog. It now works with large or small fonts. 2003-05-24 00:05 we7u * src/draw_symbols.c: Added some comments. 2003-05-23 16:30 we7u * src/maps.c: Fixing intensity slider for Tigermap by switching from LevelImage() call to ModulateImage() call. 2003-05-23 15:59 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-23 15:59 we7u * config/: language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-23 14:58 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-23 14:18 we7u * src/xa_config.c: Setting initial default for MAP_CHOOSER_EXPAND_DIRS to 1, so that the terraserver.geo and toposerver.geo files will appear by default for new users. 2003-05-23 13:32 we7u * terraserver.geo, toposerver.geo: Adding these files to the sources. 2003-05-23 13:32 we7u * Makefile.am: Auto-installing terraserver.geo and toposerver.geo in the maps directory. 2003-05-23 13:29 we7u * README.win32: More explanation of CVS errors when SourceForge is too busy. 2003-05-23 13:19 we7u * README.win32, help/help-English.dat: Added TOPOSERVER instructions. 2003-05-23 13:16 we7u * README.MAPS: Added the TOPOSERVER keyword and explanation. 2003-05-23 13:11 we7u * src/maps.c: On-line topo maps. I considered the utility of this versus not adding it until after release. This is just too useful for new (and old) users not to have put it in. Enjoy! Geo file with "TOPOSERVER" in it will get you online topo maps. 2003-05-23 12:06 we7u * src/main.c: Fixing SmartBeaconing dialog so that it's aligned properly. 2003-05-23 11:44 we7u * src/main.c: SmartBeaconing dialog now supports metric units. 2003-05-23 10:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/track_gui.c: Changing more hard-coded strings into language-specific strings. 2003-05-23 10:08 we7u * help/help-English.dat: More minor spelling on consistency changes. 2003-05-23 09:14 we7u * config/language-Portuguese.sys: Making the time periods correspond with the English file. 2003-05-22 22:14 we7u * help/help-English.dat: Lots of minor tweaks throughout the file. 2003-05-22 14:01 we7u * help/help-English.dat: Minor updates. 2003-05-22 13:20 we7u * README.MAPS: Updating the NOAA filenames for the alert shapefiles. 2003-05-22 12:37 we7u * README: Correcting spelling. 2003-05-22 12:33 we7u * README.MAPS: Added notes about setting up permissions for maps/GPS directory. 2003-05-22 12:22 we7u * AUTHORS, INSTALL, NEWS, README.MAPS: Tweaking docs here and there. 2003-05-22 12:02 we7u * DEBUG_LEVELS: Swapped the two sections. Most useful info at the top of the file now. 2003-05-22 11:58 we7u * DEBUG_LEVELS, FAQ, INSTALL, LICENSE, NEWS, README, README.CVS, README.MAPS, README.win32, UPGRADE: Adding/changing copyright notice. 2003-05-22 11:48 we7u * README.win32: Adding more notes. Reworking existing notes to make them more understandable to Windows-folk. 2003-05-22 09:32 we7u * INSTALL: Adding info regarding matching up the libtiff/libgeotiff versions. 2003-05-21 16:16 we7u * src/: db.h, main.c: Reversing the direction of the two Area Object lines, to correspond with dos/winAPRS and UI-View. 2003-05-21 16:16 we7u * src/draw_symbols.c: Added some comments. 2003-05-21 15:40 francais1 * src/: db.c, db.h, draw_symbols.c, draw_symbols.h: Fixed corridor > 127 bug (now works up to 999, which I believe is the spec limit) 2003-05-21 15:34 we7u * src/draw_symbols.c: Added some comments. 2003-05-21 14:18 we7u * src/draw_symbols.c: Implemented area object ellipse display exactly the same as circle display. This is what UI-View is doing. dos/WinAPRS don't implement ellipses at all. 2003-05-21 13:31 we7u * config/language-German.sys, help/help-German.dat: Changes by Rolf Bleher, DK7IN. 2003-05-21 12:56 we7u * src/maps.c: Canceling certain warning messages while indexing. 2003-05-21 12:30 we7u * README.CVS: Updates to match our current codebase and how we do things. 2003-05-21 12:22 we7u * src/main.c: Fixing the Map Properties strings so that they are auto-centered in the columns and truncated to the column widths. 2003-05-21 11:45 we7u * src/main.c: Truncating language strings in Map Properties columns (the "yes" string) so that it fits our column width. 2003-05-21 10:01 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-21 09:45 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-21 09:44 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-21 09:44 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-21 09:22 francais1 * config/language-French.sys: Translated added English 2003-05-20 17:15 we7u * src/: interface.c, main.c: Correcting some grammar. 2003-05-20 17:14 we7u * README.win32: Removing the Perl 5.6 restriction. Perl 5.8 appears to work properly now with Xastir and it's optional libraries. 2003-05-20 14:28 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-20 12:51 we7u * config/language-Italian.sys: Adding some missing strings. 2003-05-20 12:22 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing more hard-coded language strings. 2003-05-20 12:09 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing hard-coded strings. Added missing GPS strings in Italian file. 2003-05-20 11:16 we7u * FAQ: Added two more questions/answers. 2003-05-20 10:34 we7u * src/: bulletin_gui.c, fcc_data.c, gps.c, interface.c, lang.c, main.c, maps.c, messages.c, rac_data.c, util.c, view_message_gui.c, wx.c, alert.h: Fixing up the and includes with the proper ifdef's. 2003-05-19 20:42 rzg * help/help-English.dat: Typo fixes pointed out by Rolf, minor other things. 2003-05-19 20:28 rzg * INSTALL, README.CVS, README.MAPS, UPGRADE: Adding copyright notices to the docs that lack. 2003-05-19 13:14 we7u * README.win32: Changes by Kirk Mefford, KC2ELO. 2003-05-19 12:52 we7u * src/main.c: Correcting the time.h include to make it sys/time.h. 2003-05-19 11:24 we7u * README.win32: Adding checkboxes. 2003-05-19 11:13 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-19 10:57 we7u * README.win32: Changes by Wes Johnston, edited slightly by me. 2003-05-19 10:35 we7u * INSTALL: Added another festival note from Alan Crosswell. 2003-05-19 09:59 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-18 11:29 we7u * config/language-Italian.sys: Changes by Marco Calistri, IK5BCU. 2003-05-16 17:07 we7u * src/maps.c: Removing the debug fprintf() statement. 2003-05-16 17:03 we7u * src/maps.c: Fix for wrong guessing of road widths for some types of Shapefiles. 2003-05-16 16:06 we7u * INSTALL: Shapelib instructions for MacOSX. 2003-05-16 14:44 we7u * README.win32: More detailed instructions for Shapelib integration. 2003-05-16 13:12 we7u * README.win32: More ImageMagick notes for Cygwin. Setting the MAGICK_HOME variable with the new X configuration. 2003-05-16 11:16 we7u * README.win32: Adding a note about the 'X' in the system tray. 2003-05-16 11:10 we7u * README.win32: Changing desktop shortcut to start from Cygwin home directory. 2003-05-16 11:02 we7u * README.win32: Updated Cygwin instructions to allow using Xwindows apps and Windows apps from the same desktop transparently. No Xwindows large box anymore! 2003-05-15 12:32 we7u * src/maps.c: Adding another helpful message for the case where a GEO file is being opened, but perhaps no support is compiled in for the map format. 2003-05-15 12:18 we7u * src/maps.c: Spit out appropriate error messages if various optional map libraries are not installed and the user tries to load unsupported map types. 2003-05-15 11:12 we7u * src/: maps.c, track_gui.c: Changing one warning message. 2003-05-15 08:09 we7u * configure.ac: Bumping the revision up to 1.1.5. 2003-05-15 07:47 we7u * Makefile.am: Getting rid of the last remnants of README.1ST. Adding other doc files. 2003-05-14 22:18 rzg * FAQ, README.1ST, README.win32: Docs cleanup take 5. 2003-05-14 22:07 jtwilley * Makefile.am, xastir.spec.in: Removed references to README.1ST and TODO 2003-05-14 21:02 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-14 20:59 we7u * src/main.c: Moving the time.h include outside the HAVE_IMAGEMAGICK ifdef's. 2003-05-14 19:14 rzg * README: Took last important bit from README.1ST, ready to trash it... 2003-05-14 17:14 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-14 17:08 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-14 16:30 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-14 16:29 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-14 16:06 francais1 * config/language-French.sys: Updated 2 strings to match English. 2003-05-14 16:02 we7u * config/language-English.sys: Updating the reindexing strings. 2003-05-14 15:50 we7u * AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, NEWS, README, README.CVS, README.MAPS, UPGRADE, changes.txt: Adding/Changing to Id: RCS tag in files. 2003-05-14 15:41 we7u * README.MAPS: Updating a NOAA URL. 2003-05-14 13:47 we7u * config/language-Spanish.sys: Changed by Jose R. Marte A., HI8GN. 2003-05-14 12:44 francais1 * config/language-French.sys: Updated 2003-05-14 09:28 rzg * README.MAPS, help/help-English.dat: Docs- big cleanup take 4! 2003-05-14 09:14 rzg * INSTALL, README, README.1ST, UPGRADE: Docs- big cleanup take 3! 2003-05-14 08:42 rzg * INSTALL, README.1ST, README.CVS, README.MAPS: Docs- big cleanup take 2! 2003-05-14 08:40 rzg * TODO, UPDATES: Docs - big clean up take 1! 2003-05-13 14:56 jtwilley * README.win32: Added Kirk Mefford's suggestion re: creating .cvsrc file 2003-05-12 23:59 we7u * src/db.c: CPU Usage fixes. We no longer do complete symbol updates at a high rate. We update only the new symbol, then do cleanup at a 60-second rate sometime later. CPU usage drops a bit with this latest code. 2003-05-12 16:59 we7u * src/main.c: Slowed down UpdateTime() iterations so that the read/write threads would have time to do their thing. Cranked up the maximum packets processed by UpdateTime() in one iteration. Added a usleep() after processing each packet so that the read threads would have time to put another packet in the queue. CPU time has gone down by these changes, but we still appear to keep up with the incoming packets. 2003-05-12 16:56 we7u * src/interface.c: Speeding up the receive threads. They don't take any CPU time anyway, so this doesn't hurt CPU usage. They process one line then wait for the main thread to pick it up before they process the next line. 2003-05-12 13:59 we7u * src/main.c: Changing main.c:UpdateTime() to wait 15ms between each run instead of 10. This reduces CPU time a bit, yet still allows packets to get processed from the receive queues. 20ms appeared to be too slow. Will investigate adding longer delays between graphics updates in this routine, yet allowing packet processing to proceed at a fast pace. That should further reduce CPU cycles yet not get behind in the receive queues. At that point we might reduce the delay again between UpdateTime() runs. 2003-05-12 12:39 we7u * README.win32: Updating the list of Cygwin packages to include tcl/tk and Curl. 2003-05-11 22:18 we7u * config/language-Italian.sys: Another phrase translated by Marco Calistri, IK5BCU. 2003-05-11 08:06 we7u * config/language-Italian.sys: Adding a missing string. In English so far (until I get an Italian translation of it). 2003-05-10 16:42 we7u * src/maps.c: Fix by Magne Mhre, la1bfa, for segfault generated when Shapefiles can't be created on the file system, usually due to permissions problems in /usr/local/maps/GPS. 2003-05-10 00:31 we7u * src/alert.c: Converting one more strcpy to strncpy. 2003-05-10 00:15 we7u * src/alert.c: Fixing another killer packet bug in the alert code. 2003-05-09 14:13 we7u * config/language-English.sys: Changing one label slightly regarding reindexing. 2003-05-09 10:43 we7u * src/maps.c: Tweaks to maintain selected map properties when a full reindexing is requested. 2003-05-08 23:39 we7u * src/: maps.c, maps.h, main.c: Implementing an indexing scheme that takes care of finding updated files quickly, deleting records for deleted files, and wasting everything and starting from scratch to build a new index. This code can do all of that. 2003-05-08 23:32 we7u * README.win32: Removed an email address so that Kirk won't get spammed by the spambots. 2003-05-08 23:28 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing/Adding Map Re-Index strings for menus. 2003-05-08 17:44 rzg * README.win32: Sound Alert information from Kirk Mefford kc2elo@softhome.net 2003-05-08 14:36 we7u * src/main.c: Changed a comment. 2003-05-08 12:31 we7u * src/db.c: Fixing the Station Info dialog so that the multipoint strings aren't shown. They're now removed from the string inside the extract_multipoint() function. 2003-05-07 22:26 we7u * src/alert.c: Fixing the alert matching so that a new alert will match a pre-existing CANCL packet in the list. This is in response to a bug on the bug-list. 2003-05-07 13:32 francais1 * src/maps.c: Fixed relative paths to images in .geo files 2003-05-06 21:32 kd6zwr * src/maps.c: Made IMAGESIZE tag optional for geo files, (imagemagic ping to autodetect size) Also allow absolute pathnames in geo files, as well as relative. 2003-05-06 14:49 we7u * src/db.c: Don't draw wind barbs for severe storm objects. 2003-05-06 13:33 we7u * src/db.c: Adding the other types of severe storms that the weather server can issue. This is part of the general hurricane bug fix on the bug list. 2003-05-06 13:19 we7u * src/db.c, src/db.h, symbols/symbols.dat: Moving wind speed into the proper field (so that it shows up in Station Info) for hurricanes. This is a partial fix for a bug on the buglist. Changing the tornado symbol so that it stands out more (thanks to Dale Huguley for that one). 2003-05-06 08:17 we7u * help/help-English.dat: Added a description of the weather watch box colors/patterns, courtesy of Dale Huguley. 2003-05-05 21:22 we7u * src/util.c: Correcting for daylight savings time when converting from zulu time to Unix epoch time. Also added some debug code. 2003-05-05 16:08 jtwilley * README.1ST: Minor correction to FreeBSD notes. 2003-05-05 13:36 we7u * src/alert.c: Changed some comments. No code changes. 2003-05-05 11:00 we7u * src/alert.c: Fixing another "killer packet" problem: If we got an uncompressed message that looked like a weather alert but was simply a test message, we segfaulted while trying to move uninitialized strings around. 2003-05-02 17:31 we7u * src/: db.c, alert.c: Rewrote weather alert handling so that compressed format weather alert packets are parsed/displayed correctly. 2003-05-02 11:03 kd6zwr * src/maps.c: Initialize a few variables to NULL to shut up -Wall 2003-05-02 10:43 we7u * help/help-English.dat: Added a note about IMAGESIZE now being a required keyword in .GEO files. 2003-05-02 01:44 we7u * src/db.c: Re-wrote relay_digipeat() so that it is more correct. It now appears to get to the correct part of the path before checking for my_call or RELAY. 2003-05-01 09:47 kd6zwr * src/: maps.c, maps.h: Changed reading in map index to much faster mode, and added a sort routine to make sure it is still sorted correctly. 2003-05-01 09:38 we7u * src/db.c: Reordered the widgets in the Station Info dialog so that it can be resized properly. This is to take another bug off the buglist regarding oversized Station Info dialog that can't be resized. It can now. 2003-04-30 23:38 we7u * README.1ST: Added some notes about tiger file types and NOAA weather alert shapefiles. 2003-04-30 21:19 we7u * src/maps.c: Working code for Shapefile polygon "holes"!!! 2003-04-30 13:22 we7u * src/util.c: Adding two more lower-case letters to those accepted by valid_path() for Q-constructs. 2003-04-30 13:10 we7u * src/maps.c: More debug stuff. More work on Shapefile holes in polygons. 2003-04-30 12:50 we7u * src/util.c: Added more debug statements to valid_path(). 2003-04-30 10:50 rzg * help/help-English.dat, FAQ: Qxx, and other minor updates to help and FAQ. 2003-04-30 09:02 we7u * src/maps.c: Comment changes. No code changes (yet!). 2003-04-29 14:37 jtwilley * src/main.c: Fixed warnings with libcurl. Started GDAL integration. 2003-04-29 13:24 we7u * src/maps.c: Changing/adding comments. 2003-04-29 13:02 we7u * src/maps.c: Implementing a better fill/hole ring-direction algorithm for Shapefiles. This one is snagged directly from Shapelib and used by permission of the author, Frank Warmerdam. 2003-04-28 23:03 we7u * src/maps.c: More tweaks to the Shapefile "hole" ring code. Not fully implemented yet, but added some speed improvements. Next is to implement a clip-mask in the form of regions. 2003-04-28 22:59 we7u * src/interface.c: Getting rid of an unused variable. 2003-04-28 21:59 rzg * README.1ST: Updates WTR igating weather alerts, minor spacing changes, and nicer libcurl URL. 2003-04-28 21:24 jtwilley * README.1ST: Added URL for libcurl. 2003-04-28 20:57 we7u * src/db.c: Changed the extract_GLL() function from using strtok() to split_string(). 2003-04-28 17:04 we7u * src/db.c: Converted extract_RMC() to using split_string() instead of strtok(). 2003-04-28 16:17 we7u * src/db.c: Removing unused variables. 2003-04-28 16:08 we7u * src/db.c: Re-wrote extract_GGA() to avoid a segfault with a killer packet. Need to re-write extract_RMC() and extract_GLL() in a similar manner. The fix is to get rid of strtok() and use util.c:split_string() instead. 2003-04-28 14:50 we7u * src/: interface.c, util.c, util.h: Moved split_string() function to util.c/util.h in preparation for using it from more places in the code (instead of just interface.c). 2003-04-28 11:47 we7u * src/maps.c: Making debug levels more consistent. 2003-04-28 11:43 we7u * src/maps.c: Adding new routine which can determine whether a Shape ring is a fill or a hole ring. This is part of the work to implement the "holes" properly for Shapefiles. 2003-04-28 10:27 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-04-27 20:45 we7u * src/maps.c: Adding more comments. 2003-04-26 23:38 we7u * src/maps.c: More comment changes. No code changes. 2003-04-26 23:15 we7u * README.1ST: Changed the location for the Tiger/Line->Shapefile downloads. 2003-04-26 18:21 we7u * src/maps.c: Working on the Shapelib drawing function "hole" problem. So far just adding comments and example code in comments. No code changes yet. 2003-04-25 17:32 we7u * src/maps.c: Adding more comments. 2003-04-25 17:09 we7u * src/maps.c: Added comments. 2003-04-25 15:49 we7u * config/language-Italian.sys: Another tweak by Marco Calistri, IK5BCU. 2003-04-25 15:45 we7u * src/maps.c: Changing to "Nonconvex" parameter for the rest of the XFillPolygon calls. This should speed up drawing a bit. 2003-04-25 15:30 we7u * src/maps.c: Changing XFillPolygons to use Nonconvex parameter, which speeds up map drawing for cases where the line doesn't cross its own path. Added some comments. 2003-04-25 15:29 we7u * config/: language-Dutch.sys, language-French.sys, language-Italian.sys, language-Spanish.sys: Correcting one bug left in the files due to a mistyped character. Checking in latest Italian translation by Marco Calistri, IK5BCU. 2003-04-25 13:36 we7u * README.win32, README.1ST: Added notes about libcurl. 2003-04-24 17:25 jtwilley * src/maps.c: Added code to support libcurl. Added code to remove PACKAGE_* warnings. 2003-04-24 17:24 jtwilley * src/track_gui.c: Added code to support libcurl. 2003-04-24 17:20 jtwilley * src/main.c: Added code to support libcurl. Added code to remove PACKAGE_* warnings. 2003-04-24 17:19 jtwilley * src/util.c: Added code for curl_fwrite and curl_getfile. 2003-04-24 17:15 jtwilley * src/util.h: Added declarations for curl_fwrite and curl_getfile. 2003-04-24 17:04 jtwilley * configure.ac: Added check for libcurl. 2003-04-24 15:25 we7u * src/: interface.c, maps.c: Adding comments. 2003-04-24 14:06 we7u * README.win32: Revising the Perl interpreter to install. There are problems with 5.8.0 yet. 2003-04-23 13:16 we7u * src/interface.c: Changing port_read() to a 50ms delay instead of 20ms. Last checkin was a slight oops. 2003-04-23 13:15 we7u * src/interface.c: Speeding up the port_read() and port_write() delays again. We were starting to get behind at processing packets from full-feeds, with 100ms delays. Changed to 50ms delays and we appear to catch up when we get a bit behind. The correct solution for this is to use select() to wait for data to process, instead of using it as a short sleep function. Something to change another day... 2003-04-22 23:08 we7u * src/maps.c: Minor revisions to the create_shapefile from APRS Trail functions. Maps are now saved in the /maps/GPS/ directory and are red dashed lines by default. They appear in the Map Chooser once re-index maps has been run. 2003-04-22 10:34 we7u * src/: db.c, main.c, main.h, maps.c, maps.h: The "Store Track" button on the Station Info dialog now saves the station track as a Shapefile map in /var/tmp/, if Shapelib has been compiled in. The Shapefile filename will contain the callsign and a date/timestamp. The original function of the button still remains as well: It also saves the info in the original text format. 2003-04-22 01:35 jtwilley * src/main.c: Added tnc_data_clean call to static TNC case. 2003-04-22 01:30 jtwilley * src/interface.c: Replaced broken routine in tnc_data_clean with working routine. 2003-04-21 15:45 we7u * src/interface.c: Changed port_write() so that it'll send blocks of characters across network interfaces, single chars with inter-character pacing across serial interfaces. 2003-04-18 17:21 we7u * xastir.spec.in: Updated spec input file. Starting to work. 2003-04-18 17:21 we7u * Makefile.am: Adding xastir/GNIS/ directory to install. Used for searching. 2003-04-18 15:37 we7u * README.win32: Updating library versions that we've tested with. 2003-04-18 13:59 we7u * README.1ST: Updating optional library versions that Xastir has been tested with. 2003-04-18 13:48 we7u * xastir.spec.in: Fixes so that man page gets installed correctly. 2003-04-18 12:47 we7u * xastir.spec.in: Tweaks to make the spec file more up-to-date. The changes fix several of the failures in building RPM's, but still fails building the man page. 2003-04-18 12:09 we7u * README.win32: Updating docs to latest Shapefile version tested. 2003-04-18 11:46 we7u * README.1ST: Updating version of Shapelib library to latest tested. 2003-04-17 15:08 we7u * src/igate.c: Added a comment. 2003-04-17 14:32 we7u * src/igate.c: Adding AGWPE devices to the dupe queues for igating. 2003-04-17 13:35 we7u * README.1ST: Adding another map link. 2003-04-17 10:24 we7u * README.1ST: Another GPSMan note. 2003-04-17 10:21 we7u * README.1ST: Updating the libgeotiff instructions. 2003-04-17 10:11 we7u * README.1ST, README.win32: Re-organization of the wetnet directories. Changed links in README's to match. 2003-04-17 09:56 we7u * README.1ST, README.win32: Changed from eskimo.com to wetnet.net for some of the optional map library download sites. 2003-04-16 17:12 we7u * src/igate.c: We now allow partial matches of NWS data, but the strings defined in the nws-stations.txt file must be at least three characters long in order to create a valid match. 2003-04-16 16:42 we7u * src/: interface.c, interface_gui.c, location_gui.c, maps.c: Fixing more possible scanf()/sscanf() buffer overflow conditions. 2003-04-16 16:40 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-16 16:27 we7u * src/igate.c: Fixing a possible buffer overflow condition where we're reading the nws-stations.txt file into an array. 2003-04-16 16:14 we7u * README.1ST: Miscellaneous maps notes. Put in eskimo.com as an alternate location for some of the map libaries. 2003-04-16 15:56 we7u * README.win32: Added more download sites for the optional map libraries. 2003-04-16 14:12 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-16 14:04 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-04-16 12:32 we7u * config/language-Spanish.sys: Adding the strings back in that were added yesterday but left out of the last translation. 2003-04-16 12:29 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-16 10:14 we7u * src/interface.c: Added comments. Added character pacing on write again for the DEVICE_NET_AGWPE interface. It's separate from the others so that it can be fine-tuned. 2003-04-15 17:24 we7u * src/interface.c: Adding some debug statements. 2003-04-15 15:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Putting in language strings instead of hard-coded English for Configure->Timing dialog. 2003-04-15 15:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixes for hard-coded English strings in Maps->Enable/Configure Tigermap dialog. 2003-04-15 14:34 we7u * src/main.c: Fixing Configure->Defaults dialog so that all of the widgets are visible in all of our supported languages. 2003-04-15 13:41 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-04-15 13:00 we7u * src/interface_gui.c: Disabling relay digipeat for AGWPE interface until raw transmit packet frames can be implemented. 2003-04-15 12:52 we7u * src/db.c: Added a comment. 2003-04-15 12:51 we7u * src/interface.c: Comments. Changed test packet callsigns. 2003-04-15 09:04 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-04-15 08:41 we7u * config/language-English.sys: Committing changes for Rolf Bleher, DK7IN. 2003-04-15 01:21 we7u * src/interface.c: Fix to igate_path for AGWPE interfaces. 2003-04-14 09:32 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-13 08:51 rzg * help/help-English.dat: Various updates for new features, and typo fixes, more to come. 2003-04-11 18:32 we7u * src/: db.c, db.h, festival.c, festival.h, main.c, main.h, rotated.c, rotated.h, wx.c, wx_gui.c: Corrected some inconsistencies found by running the compiler at higher warning & pedantic levels. 2003-04-11 17:07 we7u * src/: maps.c, messages_gui.c, util.c: More minor cleanups. 2003-04-11 16:59 we7u * src/: bulletin_gui.c, db.c, gps.c, interface.c, interface.h, main.c, maps.c: Minor cleanups. Lots of them. 2003-04-11 16:58 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-11 15:36 we7u * config/language-Portuguese.sys: Tweaks to add missing strings. 2003-04-11 15:30 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-11 15:13 we7u * README.1ST: Another tweak by J. Lance Cotton. 2003-04-11 15:08 we7u * README.1ST: Added instructions for reprojecting Shapefiles, courtesy of Derrick J Brashear and J. Lance Cotton. 2003-04-11 14:07 we7u * src/: db.c, interface_gui.c: Setting up for relay digipeating using AGWPE interfaces. Untested. 2003-04-11 13:49 we7u * src/igate.c: Added AGWPE to igating code. 2003-04-11 13:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface_gui.c: Implemented the transmit radioport option for AGWPE interfaces. This can be adapted to other multi-port TNC interfaces later. 2003-04-11 13:26 we7u * src/interface.c: Backing out one change to avoid high CPU-usage in the port_write() function. Added comments to the port_read() and port_write() threads to hopefully eliminate this sort of problem in the future. 2003-04-11 11:17 we7u * src/interface.c: Added code to disable Nagle's algorithm for TCP/IP sockets : TCP_NODELAY setsockopt(). 2003-04-11 10:25 we7u * src/interface.c: Eliminated line pacing for network connections. Added more serial types to the character pacing code. 2003-04-10 17:10 we7u * src/interface.c: Fixing a lock problem and commenting out some debug packets for AGWPE. 2003-04-10 14:17 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Tweaking AGWPE labels. 2003-04-10 14:13 we7u * src/interface_gui.c: Removing filter options from AGWPE Properties dialog. Doesn't apply. 2003-04-10 14:05 we7u * src/interface_gui.c: Extending the length for AGWPE passwords. 2003-04-10 13:58 we7u * src/interface_gui.c: More AGWPE stuff. 2003-04-10 12:49 kd6zwr * src/maps.c: Fix for systems with both Xpm.h and XpmI.h 2003-04-10 12:46 we7u * src/interface.c: Getting rid of unused variables and old code. 2003-04-10 12:40 we7u * src/interface.c: Moved the unproto path selection into its own routine. More code changes to support agwpe. 2003-04-10 11:14 we7u * README.1ST: Specifying an alternate ftp site to get the radar geo's from. 2003-04-10 09:45 we7u * README.1ST, help/help-English.dat: Adding a few notes about the .GEO file format specifying that decimal degrees are used for lat/lon in these files. 2003-04-08 14:30 we7u * src/interface.c: Changing input parameter for send_agwpe_packet() to accept a digi path instead of a list of digi's. This will integrate into the Xastir method of specifiying paths more easily. 2003-04-08 13:33 we7u * src/interface.c: Changing the AGWPE login ID to be callsign minus SSID (removed SSID). 2003-04-07 23:17 we7u * src/interface.c: Initial transmit capability for AGWPE interfaces. Currently the path is hard-coded to RELAY,WIDE2-2, but that will change given time. The method of specifying the path differs greatly from Xastir's original method, plus the Properties GUI for AGWPE needs to be reworked to add in the optional path fields. 2003-04-07 10:26 we7u * src/interface.c: Commenting out some debugging printf's. 2003-04-06 13:25 we7u * src/main.c: The other small tweak needed in order to decode AGWPE packets. 2003-04-06 13:22 we7u * src/interface.c: AGWPE interface receive mode is not functional. Transmit is still being worked on. 2003-04-05 11:16 we7u * src/interface.c: More AGWPE code. We're getting packets sent in both directions now, although the login/password packet doesn't appear to be accepted properly yet. No decoding/encoding of real packets is implemented yet. 2003-04-04 16:55 we7u * src/xa_config.c: Fixing this so that it handles the correct types of interfaces. 2003-04-04 14:04 we7u * src/interface.c: Added some comments. 2003-04-04 13:50 we7u * src/interface.c: More AGWPE stuff. Not functional yet. 2003-04-04 12:52 we7u * src/interface.c: Send the login packet to AGWPE only if the passwd string has something in it. 2003-04-04 11:48 we7u * src/interface.c: More AGWPE interface code. Now sending login/password string and command to ask AGWPE to send us the monitored packets. Don't have transmit or the receive decode of those packets completed yet, but debug code is in place that looks for complete headers and packets and notifies us on reception. 2003-04-03 23:48 we7u * src/interface.c: More AGWPE stuff. Not functional yet. 2003-04-03 17:12 we7u * src/interface.c: More AGWPE work. Not functional yet. 2003-04-03 14:40 we7u * src/interface.c: Reformatting. No code changes. 2003-04-03 14:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface.h, src/interface_gui.c: Initial steps at adding network support for AGWPE. 2003-04-03 12:57 we7u * src/: main.c, maps.h: Adding my test_create_shapefile stuff back in, this time with the proper #ifdef's so that everybody can still compile the code whether they have shapelib installed or not. 2003-04-03 11:52 we7u * src/: main.c, maps.c: Spawning off a separate thread for doing the Snapshot() function. 2003-04-03 09:39 we7u * src/maps.c: Changing the Snapshot function so that it can reduce to 256 colors if necessary when converting from XPM to PNG. 2003-04-02 13:01 francais1 * src/interface.c: Enable suid privileges around bind to reset from callsign (RELAY digipeat bugfix with 2.2.19 kernels, I hope.) 2003-04-02 11:30 we7u * src/main.c: Disabling my test_create_shapefile_map entry. Some people can't get Xastir to compile with it in there, and it's test code anyway. 2003-04-01 16:27 we7u * src/: main.c, maps.c, maps.h: Testing of the shapefile creation function. Attached to the "Test" button on the menus. 2003-04-01 15:25 we7u * src/maps.c: Changed to comments. No code changes. 2003-04-01 13:13 we7u * src/interface.c: Adding some white space. No code changes this time. 2003-04-01 09:55 we7u * src/xastir.h: Enabling serial KISS tnc relay digipeat functionality by default. Initial testing shows that this portions of relay digipeat is working. AX.25 relay digipeat still needs a bit of work to get the source callsign to be set properly. 2003-04-01 01:09 we7u * src/: db.c, interface.c: Changes to make RELAY digipeating functional for Serial KISS TNC interfaces. May have fixed AX.25 interfaces as well. 2003-03-31 23:16 we7u * src/db.c: Better debug output for relay_digipeat() function. 2003-03-31 15:31 we7u * src/db.c: More debug messages for relay_digipeat() function. Again, will be removed later. 2003-03-31 14:59 we7u * src/db.c: Adding some debug output for relay digipeat. It'll be removed later when we get things working properly. 2003-03-28 17:05 we7u * src/db.c: More KISS variant comments. 2003-03-28 16:37 we7u * src/db.c: Added another kiss variant to the comments. 2003-03-28 16:34 we7u * src/db.c: Added some notes about KISS protocol variants. No code changes. 2003-03-28 11:13 we7u * src/maps.c: Changing point shapefiles so that if labels are turned off, the symbols still get drawn. 2003-03-28 10:33 we7u * src/: interface.c, db.c: Added comments. Now mask off the AX.25 P/F bit before checking the control byte for 0x03 (UI Frame). Now drop the Serial KISS packet if the final result is not 0x03. 2003-03-27 15:57 we7u * src/db.c: Taking out the control byte == 0x03 restriction for Serial KISS packets. MKISS TNC's encode the channel number in the control byte. 2003-03-27 15:46 we7u * src/db.c: Added a note to decode_ax25_header() function. 2003-03-27 15:42 we7u * README.1ST: Added a GPSMan install step to set the permissions on the /usr/local/xastir/maps/GPS/ directory so that files could be written there. 2003-03-27 15:33 we7u * src/db.c: Changing the Serial KISS interface to ignore packets if the control byte != 0x03 and the PID byte != 0x0f. This will make it co-exist on channels that might have other protocols on them (net/rom, tcp/ip, etc.). The AX.25 interface code already had the PID==0x0f restriction on it. 2003-03-27 14:32 we7u * README.win32: Changed "go.bat" to just "go". Less typing to get things rolling that way. 2003-03-27 14:16 we7u * README.win32: Added zip/unzip to the list of packages to install. Helps when installing some map files later. 2003-03-27 11:21 we7u * README.win32: Added some blank lines. 2003-03-27 11:17 we7u * README.1ST: Added notes about how to decompress the World shapefile. 2003-03-27 11:11 francais1 * FAQ: Added a lesstif/openmotif entry 2003-03-26 22:10 we7u * README.win32: More details for the user in terms of creating subdirectories while adding in the optional libraries. 2003-03-26 11:55 we7u * Makefile.am: Added the xastir/maps/GPS/ directory to the directories created during install. This directory is required for GPSMan to operate with Xastir properly. 2003-03-26 11:28 we7u * src/main.c: Updating about message to contain 2003 instead of 2002. 2003-03-26 10:41 we7u * src/main.c: Changing the method of parameter passing between GPS_operations() and gps_transfer_thread() in order to solve a user's problem. 2003-03-26 10:00 we7u * src/main.c: A few minor tweaks to GPS_operations and gps_transfer_thread, mostly to debug problems with parameter passing. 2003-03-24 15:28 we7u * README.win32: One more note to get libgeotiff working on Cygwin. Must rename the libtiff dll's in order to be compatible with the version of libgeotiff. 2003-03-24 13:36 we7u * README.win32: Removed warning note above the geotiff instructions: It is working again with the current instructions. 2003-03-24 12:52 we7u * README.win32: Some minor additions to the libproj install that helps the libgeotiff install to complete. 2003-03-23 18:46 we7u * README.win32: Added more notes to clarify places where some users were tripping up. 2003-03-23 18:45 we7u * README.1ST: Added asterisks next to the note about the Shapefile world map. 2003-03-22 00:28 we7u * src/interface.h: Reversed order of arguments for socklen_t typedef. 2003-03-21 16:50 we7u * README.win32: Taking out some old notes that aren't applicable anymore. 2003-03-21 16:49 jtwilley * configure.ac: Forgot to actually include -lax25 when detecting it 2003-03-21 16:48 we7u * README.win32: Another minor Cygwin tweak. 2003-03-21 16:28 we7u * src/util.c: Another minor Cygwin tweak. 2003-03-21 16:25 we7u * README.win32: More Cygwin tweaks. 2003-03-21 16:02 jtwilley * src/: interface.c, interface_gui.c: Changed references of HAVE_AX25 to HAVE_LIBAX25 to match new configure. 2003-03-21 12:44 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Removing the "Are You Sure?" button on exit (to keep peace with the other war-monger developers ;-) 2003-03-20 14:29 jtwilley * acinclude.m4, configure.ac, src/hostname.c, src/interface.c, src/interface.h, src/main.c, src/maps.c, src/maps.h, src/util.c, src/wx_gui.c, src/xa_config.c: Massive configuration overhaul -- moving functions from configure.ac to acinclude.m4 and beginning to streamline configure.ac, with attendant changes in various source files. 2003-03-18 14:59 we7u * src/: db.c, interface_gui.c, xastir.h: Tweaks to enable testing of RELAY digipeat with serial KISS TNC's. One define in xastir.h needs to be changed in order to enable it. 2003-03-18 14:39 francais1 * src/: db.c, interface_gui.c: Allowed selection of AX25 relay digipeat 2003-03-18 14:28 we7u * src/: gps.c, gps.h, main.c: Changing how GPS status messages are done. 2003-03-18 13:50 we7u * src/: gps.c, interface.c, main.c, xastir.h: Fixes for the GPS high-CPU usage. We now save GPRMC and GPGGA strings in global variables, dropping all other strings. At the GPS Check Interval, we decode up to two strings that we have saved most recently. 2003-03-17 14:58 we7u * configure.ac: Another ImageMagick tweak for Cygwin. 2003-03-17 12:39 we7u * configure.ac: Trying another small tweak for Cygwin. It's not currently recognizing the ImageMagick libraries installed in /usr/lib. 2003-03-16 23:29 we7u * src/main.c: We now call reload_object_item() after we clear all stations. This keeps locally-owned objects on our screen and in our in-memory database. 2003-03-16 21:54 we7u * README.1ST: Added a Festival note from J. Lance Cotton. 2003-03-14 21:59 we7u * src/main.c: Fixing an errand comment on a #endif statement. 2003-03-14 17:01 we7u * README.win32: Tweaking the Cygwin/ImageMagick notes. 2003-03-14 16:41 we7u * README.win32: More optional library notes. Trying to work through the problems with the latest ImageMagick/proj.4/libgeotiff libraries. 2003-03-14 13:10 we7u * README.win32: More notes about problems with geotiff maps and current Cygwin versions. 2003-03-14 11:51 we7u * README.win32: Adding more notes about the impure_ptr problem. 2003-03-14 11:43 we7u * README.win32: Changing the version of libgeotiff called out. 2003-03-14 11:41 we7u * README.1ST: Removed Cygwin info. It now tells Windows users to refer to the README.win32 file instead. 2003-03-13 10:29 we7u * README.1ST: Added a bit to the GPSMan notes. 2003-03-12 20:43 we7u * README.1ST: Minor fixes to the gpsman instructions. 2003-03-12 13:20 francais1 * src/interface.c: Fix to remove the star before the ax25_aton_entry call because it would call it a bad callsign. 2003-03-12 11:23 we7u * src/main.c, configure.ac, README.1ST: Added support for the production version of GPSMan. Have at it! 2003-03-11 17:02 we7u * README.win32: Minor cygwin changes. 2003-03-11 16:43 we7u * README.1ST, README.win32: Slight changes to Cygwin instructions. 2003-03-11 16:26 we7u * README.win32: Adding a Cygwin/Win32 specific README file to make it easier for Windows users to get up and running with Xastir. Initial check-in. 2003-03-07 17:31 we7u * README.1ST: More Cygwin changes. 2003-03-07 17:25 we7u * README.1ST: More Cygwin changes. 2003-03-07 16:36 we7u * README.1ST: More Cygwin notes. 2003-03-07 16:15 we7u * README.1ST: Correcting some Cygwin libproj notes. 2003-03-07 14:07 we7u * README.1ST: Minor change to library revision number for Cygwin. 2003-03-07 14:02 we7u * README.1ST: More Cygwin notes. 2003-03-07 13:46 we7u * README.1ST: Added notes regarding "make install-strip" option. 2003-03-07 13:10 we7u * configure.ac: libproj/libgeotiff fixes for Cygwin. 2003-03-07 11:07 we7u * README.1ST: Tweaked the comments about creating the terraserver .geo file. 2003-03-07 11:03 we7u * src/maps.c: Starting to add shapefile creation functions. Intend to use these to save station trails to map files eventually. 2003-03-06 14:41 we7u * configure.ac, src/main.c: Changed some comments. 2003-03-06 14:21 we7u * README.1ST: Added initial notes regarding gpsmanshp and GPSMan. 2003-03-06 14:04 we7u * configure.ac: Adding checks for GPSman and gpsmanshp.so. Not ready for prime-time yet, but should be soon. 2003-03-06 10:47 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/gps.c, src/interface.c, src/main.c: Added a popup when GPS data goes stale. We now allow one posit when GPS interfaces are first enabled before we consider the data stale and disable transmit of My Position. Removed the statusline messages that happen when we successfully decode GPRMC or GPGGA sentences: They were causing too much CPU time on Yellow Dog Linux (powerPC). 2003-03-05 16:39 we7u * src/interface.c: Fix the case where someone plays with a GPS interface and then turns it off again. Before this change, posits would be disabled unless GPS interface was re-enabled that had good data coming in, or unless the user restarted Xastir. 2003-03-05 15:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c: Language strings for GPS operations. Added more colors. Create default time/date filename if no filename given. 2003-03-05 14:04 we7u * src/main.c: Added a UI to the gps transfer code. Not enabled yet for users. 2003-03-05 13:54 we7u * src/maps.c: Minor changes to new GPS stuff. 2003-03-04 16:51 we7u * src/maps.c: Removing the color portion of the filename for GPS map labels. 2003-03-04 16:49 we7u * src/main.c: Changed a few comments. 2003-03-04 16:34 we7u * src/main.c: Minor updates to new GPS stuff. Not enabled for normal use yet. 2003-03-04 15:55 we7u * src/main.c: Converted to switch statement in new GPS transfer routines. Can now because it's an int. 2003-03-04 15:42 we7u * src/main.c: Separated the GPS transfer functions into their own thread. GPS transfers now run concurrently with the other threads, updating the map view when they complete. 2003-03-04 12:34 we7u * README.1ST: More Cygwin libproj and libgeotiff notes. 2003-03-04 11:13 we7u * README.1ST: Correcting spelling. 2003-03-04 10:51 we7u * src/: main.c, maps.c: More experimental GPSMan stuff. Not ready for release yet. 2003-02-28 17:52 we7u * README.1ST: More Cygwin libgeotiff notes. 2003-02-28 17:48 we7u * src/maps.c: Changing the line style for GPS info. 2003-02-28 17:38 we7u * README.1ST: More Cygwin notes. 2003-02-28 17:31 we7u * README.1ST: More Cygwin stuff: libgeotiff. 2003-02-28 16:30 we7u * src/maps.c: Rotating the labels to horizontal for GPS maps. Changing orange to lighter orange. 2003-02-28 16:20 we7u * src/maps.c: Chopping off the ".shp" portion of the GPS labels. 2003-02-28 16:00 we7u * src/maps.c: More label/color stuff for gps maps. 2003-02-28 15:48 we7u * src/maps.c: Adding labels to the GPS tracks/routes. 2003-02-28 13:39 we7u * src/maps.c: More GPS stuff. Not enabled yet. 2003-02-28 13:19 we7u * src/main.c: Turning off the new GPS stuff. 2003-02-28 12:48 we7u * src/main.c: More gps transfer stuff. Not ready for prime-time yet. 2003-02-27 16:40 we7u * configure.ac: Reversing the order of lib checking for libproj and libgeotiff. 2003-02-27 16:30 jtwilley * ChangeLog, configure.ac: Cleaned up XASTIR_TOCALL in configure.ac to no longer require SHORT_VERSION 2003-02-27 15:52 we7u * README.1ST: More Cygwin notes. libgeotiff stuff. 2003-02-27 15:31 we7u * README.1ST: More changes for Cygwin. Installation of Proj.4 now complete and documented. I'm still working on installation of libgeotiff. 2003-02-27 12:53 we7u * src/main.c: Preliminary support for GPSMan: Downloads track, creates Shapefile map, auto-imports and displays said map in Xastir. Requires pre-release GPSMan plus gpsmanshp.tgz file installed. Also requires that the "WE7U" define at the top of main.c be defined to put the new code into operation. 2003-02-27 09:39 we7u * configure.ac: Added a tweak to look for the Shapelib include file in subdirectory _not_ ending in /libshp/ 2003-02-26 10:09 we7u * src/: alert.c, alert.h: Removing dead code. Changed/added a few comments and debug messages. Removed prototypes from alert.h that aren't being used. 2003-02-26 09:38 we7u * configure.ac: Taking out extra X11 include path that was just added for linux recently. 2003-02-25 17:55 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c, db.h: Fixes for bulletin popups. 2003-02-25 13:45 we7u * src/db.c: Changes to comments only. 2003-02-25 12:50 we7u * src/: alert.c, alert.h, db.c, maps.c: Changing NWS weather alerts so that they are no longer stored in the message database and rescanned periodically. They now go straight to the alert_list. 2003-02-25 10:04 we7u * src/: bulletin_gui.c, bulletin_gui.h: Fixing another bug having to do with zero-distance bulletins popping up when the user settings tell Xastir not to. 2003-02-25 09:31 we7u * src/main.c: Added Map Display Bookmarks button to right-click mouse menu. 2003-02-24 23:03 we7u * configure.ac: Adding a path for Linux configure to help find Motif include files on some systems. 2003-02-24 22:30 kd6zwr * ChangeLog, src/db.c: Made my_station_gps_change update sec_heard to fix DR of my station. 2003-02-24 16:41 we7u * configure.ac: Adding /usr/X11R6/include/Xm as an include path for Motif/Lesstif for Slackware 8.1. May need additional things in order to link to the library as well. 2003-02-24 16:29 we7u * src/db.c: Added more comments. 2003-02-24 16:26 we7u * src/db.c: Added some comments. 2003-02-24 15:40 we7u * src/maps.c: Getting rid of unneeded code. 2003-02-24 15:40 we7u * src/db.c: Added some comments. 2003-02-24 15:26 we7u * src/: db.c, maps.c, maps.h: Starting to change the weather alert code to make it independent of the message database. Part-way to that goal. This version just relocates the weather alerts scan of the message database into the db.c code at the point where we received the alert. The next step is to just throw the alert onto the alert_list and skip the message database portion altogether. This current code appears to still be fully functional w.r.t. weather alerts. 2003-02-24 14:45 we7u * src/maps.c: Re-org of a bit of code w.r.t. weather alerts (no major changes though). Lots of comment changes. 2003-02-24 13:58 we7u * src/draw_symbols.c: Tweaks to watch boxes for Gerry Wheeler. 2003-02-24 13:35 we7u * src/maps.c: Removed dead code. Changed some comments. 2003-02-24 13:04 we7u * src/: alert.c, maps.c: Changes to comments only. 2003-02-24 12:46 we7u * src/: alert.c, main.c: Setting the proper variables so that a screen update happens in a timely manner after WX alerts expire. 2003-02-24 12:23 we7u * src/: alert.c, main.c, maps.c, wx_gui.c: We now expire wx alerts only in main.c:UpdateTime(), and only every 60 seconds. If any are expired, it schedules a screen update. 2003-02-24 11:41 we7u * src/: alert.c, alert.h, maps.c: More minor work on wx alerts. 2003-02-24 11:28 jtwilley * ChangeLog: Added entry for change made to src/interface.c 2003-02-24 11:25 jtwilley * src/interface.c: Changed timeouts to 100 milliseconds from 100 microseconds. 2003-02-24 10:25 we7u * src/: alert.c, alert.h, maps.c, wx_gui.c, xa_config.c: Moved alert expiration code into common alert_expire() function. 2003-02-23 08:58 we7u * src/alert.c: Making an int more global. Needed for wx alert expire code elsewhere. 2003-02-23 08:56 we7u * src/alert.h: Adding an extern int that other code needs now for wx alert expiration. 2003-02-23 08:48 we7u * src/alert.c: Changed a comment. 2003-02-23 08:44 we7u * src/maps.c: Another tweak to wx alert expiration. 2003-02-23 08:40 we7u * src/wx_gui.c: Another small tweak to expiration for wx alerts. 2003-02-23 08:37 we7u * src/util.c: Tweaking the alert expiration stuff some more. 2003-02-23 01:52 we7u * src/: alert.c, alert.h, maps.c, util.c, wx_gui.c: Fixed incorrect expiration times for weather alerts. Proper local expiration time is now computed and stored. View->WX Alerts dialog appears to update correctly as alerts come and go. Weather alert slots get re-used by new alerts properly. We might have incorrect expiration times for weather alerts twice a year when daylight savings time switches though. 2003-02-22 08:41 n0vh * src/main.c: Fixed the intensity slider since 0 was causing xastir to crash. Set the minimum to something reasonable. 2003-02-21 17:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a new button the Stations menu: Reload Object/Item History. 2003-02-21 16:58 we7u * src/sound.c: Adding some spacing. No code changes. 2003-02-21 15:53 we7u * src/: alert.c, alert.h, maps.c, wx_gui.c: Fixes to weather alerts. Should re-use weather alert slots in the array now, and should expire things properly as well. 2003-02-21 12:46 we7u * configure.ac: Modifying the error messages to make them consistent and provide useful info to the user. 2003-02-21 11:47 we7u * configure.ac: Taking out some commented-out code and some irrelevant comments. 2003-02-20 21:10 n0vh * src/main.c: Logging indicator now changes color to highlight that it's logging. 2003-02-20 20:31 n0vh * src/: main.c, main.h: Added a status text box at the bottom of the window that indicates that xastir is logging to disk. 2003-02-20 15:31 we7u * src/bulletin_gui.c: A few fixes for bulletins. Also added a callback for the togglebutton on the View->Bulletins dialog. 2003-02-20 14:34 we7u * src/db.c: Added a debugging message. 2003-02-20 14:18 we7u * src/main.c: Changing the "Test" function a bit. 2003-02-20 12:00 we7u * src/bulletin_gui.c: Changing time between receiving a new bulletin and checking whether it is within our range: From 15 seconds to 60 seconds. This actually delays our getting notice of each new bulletin, but helps to prevent popping up bulletins when a bulletin comes in and then a posit comes in later for that station (putting that station outside our range). The cause of the bulletin window popping up appears to be these inside-our-range/ outside-our-range-when-a-posit-comes-in bulletins. 2003-02-20 11:32 we7u * src/maps.c: Changed/added some comments. No code changes. 2003-02-20 10:31 we7u * configure.ac: Added more search paths for Solaris 8/9 binaries. 2003-02-20 02:10 we7u * bootstrap.sh: Added status messages. 2003-02-20 01:51 we7u * src/: alert.c, bulletin_gui.c, db.c, draw_symbols.c, gps.c, hostname.c, interface.c, interface_gui.c, list_gui.c, locate_gui.c, main.c, maps.c, popup_gui.c, rac_data.c, rotated.c, snprintf.c, track_gui.c, util.c, view_message_gui.c, wx_gui.c, xa_config.c: Added comments. 2003-02-20 01:45 we7u * src/: bulletin_gui.h, db.h, draw_symbols.h, festival.h, gps.h, hostname.h, igate.h, list_gui.h, main.h, maps.h, rotated.h, snprintf.h, track_gui.h, util.h, wx.h, xastir.h: Added comments. 2003-02-20 01:00 we7u * src/: maps.c, track_gui.c, util.c: More fixes for calling external programs. 2003-02-20 00:33 we7u * src/: maps.c, track_gui.c, util.c: Checking for existence of external programs before trying to invoke them. If they don't exist, we call "echo" instead (relatively harmless). 2003-02-19 23:56 we7u * src/: alert.c, wx_gui.c: Added code to clear out expired weather alerts so that later alerts can use that slot. Also caused the View->Weather Alerts dialog to skip empty slots. 2003-02-19 22:47 we7u * bootstrap.sh: Separating out the -a and -c params on the automake line, for Cygwin. 2003-02-19 17:22 francais1 * configure.ac: A little tweakage 2003-02-19 17:13 we7u * src/: maps.c, util.c: Changing code to use new paths computed via configure. 2003-02-19 17:07 we7u * configure.ac: Changing the quoting on some of the newer code I just added. 2003-02-19 16:46 we7u * configure.ac: Removing the "cat" checks as we don't use it currently. 2003-02-19 16:31 we7u * configure.ac: Path discovery for more utilities that we use from within Xastir. 2003-02-19 15:43 we7u * configure.ac, src/interface.c, src/maps.c, src/track_gui.c: Removing __CYGWIN__ #ifdef's. 2003-02-19 14:40 we7u * configure.ac, src/util.c: Getting rid of __FreeBSD__ #ifdef, replacing it with HAVE_GMTOFF test/ variable/#ifdef. 2003-02-19 13:55 we7u * configure.ac, src/gps.c, src/interface_gui.c: Getting rid of OS-specific #ifdef's related to settimeofday() function, where the GPS time can be used to set system time. 2003-02-19 13:15 we7u * configure.ac: Streamlined the ImageMagick checks. Added more comments. Temporarily commented out the "-Ldir -llibrary" MacOSX/ImagMagick line which is probably unnecessary. Will add it back if tests on MacOSX show it to be required. 2003-02-19 12:44 we7u * configure.ac: Streamlining geotiff and libintl code. Added comments here and there. 2003-02-19 11:44 we7u * configure.ac: Streamlining the X11 library checking code. 2003-02-19 10:51 we7u * configure.ac: A bit of housecleaning. Pretty'ing up the warning/error messages. Re-ordering the operating system-specific areas. 2003-02-19 10:00 we7u * configure.ac: Making all of the MacOSX comments have exactly the same spelling/case. Easier to grep for in the future. No code changes. 2003-02-19 09:35 we7u * configure.ac: MacOSX/ImageMagick fix. 2003-02-18 22:20 we7u * configure.ac: Removing two brackets that give Mandrake linux fits. 2003-02-18 14:11 kg4ijb * Makefile.am: bzip mod didn't propagate 2003-02-18 14:05 kg4ijb * src/Makefile.am: yikes!, automake_option was my bad, removed. 2003-02-18 13:33 we7u * src/Makefile.am: Moving the AUTOMAKE_OPTIONS to before the line continuation char. It doesn't work where it was put. Is it necessary? Should it be somewhere else in the file? 2003-02-18 13:16 we7u * configure.ac: Added some debugging info back in. Commented out so a typical user won't be bothered by it. 2003-02-18 12:49 kg4ijb * callpass/Makefile.am, config/Makefile.am, help/Makefile.am, symbols/Makefile.am, m4/Makefile.am, scripts/Makefile.am, src/Makefile.am: ID message 2003-02-18 12:44 kg4ijb * configure.ac: cleaned output and removed all libtool dependancies 2003-02-18 12:43 kg4ijb * Makefile.am: removed unecessary automake_options 2003-02-18 12:04 we7u * scripts/Makefile.am: Adding missing scripts. Fixing things so that "make dist" works properly. 2003-02-18 11:56 we7u * bootstrap.sh: Copying the files into the directory instead of making symlinks. 2003-02-18 11:36 we7u * Makefile.am, configure.ac: More fixes to allow "make dest" to work. 2003-02-18 11:04 we7u * Makefile.am: Adding a forgotten subdirectory that makes "make dist" fail if not present. 2003-02-18 10:57 we7u * Makefile.am: Removing the lt* files. 2003-02-18 09:34 we7u * src/: main.c, xa_config.c: Changing range for Tigermap intensity from 50-100% to 0-100%. 2003-02-18 08:23 we7u * configure.ac: Bumping revision up to 1.1.4 2003-02-16 22:53 we7u * README.1ST: Added a few notes after the lines calling out bootstrap.sh. 2003-02-16 21:25 we7u * configure.ac: Another tweak for ImageMagick on MacOSX. 2003-02-16 09:37 we7u * README.1ST: Added a note to the MacOSX section: Installing Xastir into /sw. 2003-02-16 09:30 we7u * configure.ac: Another ImageMagick fix for MacOSX. 2003-02-16 01:49 we7u * README.1ST: Added some more Solaris notes, courtesy of Chris Bell. 2003-02-16 01:35 we7u * configure.ac: Added check for sched_yield() function in librt (needed for Solaris). 2003-02-15 15:44 we7u * src/util.c: Changing back to a __solaris__ ifdef for now. 2003-02-15 14:35 we7u * configure.ac: Another fix for ImageMagick on MacOSX. 2003-02-15 14:30 we7u * configure.ac, src/hostname.c, src/interface.c, src/interface_gui.c, src/main.c, src/maps.c, src/snprintf.h, src/util.c, src/xa_config.c: Removing a lot of OS-specific #ifdef's, changing to function-specific #ifdef's instead. 2003-02-15 12:10 we7u * src/xa_config.c: Temporarily removing the CYGWIN #ifdef, to see if we have the proper configure.ac support for Cygwin now. 2003-02-15 12:09 we7u * src/gps.c: Cygwin change. Getting rid of CYGWIN tag and replacing with config.h stuff. 2003-02-15 11:39 we7u * configure.ac, src/gps.c, src/interface.c: More MacOSX fixes. Using variables in config.h now instead of #ifdef MACOSX. 2003-02-15 10:45 we7u * src/: gps.c, interface.c: Changing __MacOSX__ tag to MACOSX. 2003-02-15 09:59 we7u * configure.ac, src/gps.c, src/hostname.c, src/interface.c, src/main.c, src/maps.c, src/snprintf.h, src/util.c: MacOSX and Solaris fixes related to the new Autoconf stuff. 2003-02-14 19:55 kg4ijb * configure.ac: *BSD CFLAGS and pthread check 2003-02-14 17:15 we7u * configure.ac: Fix for finding Motif libraries on Solaris. 2003-02-14 16:11 we7u * configure.ac: Another MacOSX change. 2003-02-14 15:13 we7u * configure.ac: Another fix for MacOSX regarding Xm/Xm.h 2003-02-14 14:47 we7u * README.1ST: Cygwin/fvwm2 window manager instructions. 2003-02-14 13:55 we7u * configure.ac: Changing the old ImageMagick warning message slightly. 2003-02-14 13:39 we7u * configure.ac: Mac OSX/Fink ImageMagick fixes. Also moved the old version warning to the end of that section. 2003-02-14 12:59 we7u * configure.ac: Mac OSX/Fink mods to help find Shapelib. 2003-02-14 10:30 we7u * README.1ST: Added cvs update note to Cygwin section. 2003-02-14 10:15 we7u * configure.ac: Tweaking some comments. 2003-02-14 10:09 we7u * configure.ac: Adding an RCS tag so we can track revisions. 2003-02-14 09:50 kg4ijb * configure.ac: Fixed the tocall problem. Versioning only needs to be done in ac_init 2003-02-14 01:34 we7u * README.1ST: More Cygwin changes. 2003-02-13 15:39 we7u * README.1ST: More Cygwin updates. 2003-02-13 15:22 we7u * README.1ST: Updated to reflect new configure.ac stuff. 2003-02-13 14:46 we7u * configure.ac: Fixing the TOCALL. The "APX$SHORT_VERSION" thing doesn't work. :-( 2003-02-13 13:42 we7u * src/: interface.c, interface.h, interface_gui.c: Added "Networked Database" GUI code for Brenda Wallace to have as a front-end for her database code. 2003-02-13 13:40 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding strings for future networked database GUI. 2003-02-13 13:35 kg4ijb * ChangeLog: * bootstrap.sh - routine to rebuild autostuff environment 2003-02-13 13:31 kg4ijb * bootstrap.sh: builds necessary autostuff files in appropriate order 2003-02-13 13:12 kg4ijb * ChangeLog: [no log message] 2003-02-13 13:05 kg4ijb * symbols/Makefile.in: removed, locally generated 2003-02-13 13:00 kg4ijb * src/Makefile.in, scripts/Makefile.in, m4/Makefile.in, help/Makefile.in, config/Makefile.in, callpass/Makefile.in: removed files that are generated locally 2003-02-13 12:48 kg4ijb * ChangeLog, Makefile.in: removed remote files that are generated locally 2003-02-13 12:38 kg4ijb * acconfig.h, acinclude.m4: Removed old configure files and added new ac 2003-02-13 12:33 kg4ijb * configure.ac: * Removed old configure files and added new ac 2003-02-13 12:29 kg4ijb * config.guess, config.h.in, config.sub, configure, configure.in, install-sh, ltconfig, ltmain.sh, missing, mkinstalldirs: make way for new configure 2003-02-13 09:24 we7u * README.1ST: More changes to the Cygwin notes. 2003-02-12 15:00 we7u * src/: main.c, track_gui.c: Fixing some errant string lengths on some XtVaTypedArg calls. 2003-02-12 14:31 we7u * README.1ST: Slight changes to Cygwin notes. 2003-02-11 20:18 we7u * src/main.c: Correcting a slight misspelling. 2003-02-11 11:14 we7u * README.1ST: More CVS/Cygwin info. 2003-02-10 15:42 we7u * README.1ST: Changes to the Shapelib portion of the Cygwin notes. 2003-02-10 14:29 we7u * acinclude.m4: Formatting for better readability. No code changes. 2003-02-10 13:54 we7u * acinclude.m4, config.h.in, configure: Adding more error output for Shapelib file searches during configure. 2003-02-10 13:27 we7u * configure, configure.in: Small change to wording of Cygwin warning message. 2003-02-10 13:17 we7u * acconfig.h, config.h.in, configure, configure.in: Starting to add Cygwin support to autotools. 2003-02-10 12:20 we7u * src/db.c: Fix for 3rd-party packets being marked as local stations in Xastir. We now check the "third-party" variable at that stage of the code. 2003-02-10 10:54 we7u * src/db.c: A fix by Reuven w.r.t. setting the messaging-capable flag for the case of '@' packets. Curt added some run-time debug code for finding own object deletions that'll be in effect until we're sure the problem has gone away. 2003-02-10 03:26 we7u * src/maps.c: Adding Map Labels On/Off capability to pocketAPRS maps. 2003-02-07 17:35 we7u * README.1ST: Reformatted some Cygwin notes. 2003-02-07 17:33 we7u * README.1ST: More Cygwin. 2003-02-07 17:33 we7u * README.1ST: More Cygwin stuff. 2003-02-07 16:29 we7u * README.1ST: More Cygwin note changes. 2003-02-07 09:31 we7u * README.1ST: Updated Cygwin information regarding CVS and extra map libraries. 2003-02-06 12:29 we7u * README.1ST: Added general notes about how to configure/compile/install Xastir. Several people have mentioned to me that it's not clear how to go about this. 2003-02-06 11:45 we7u * src/: maps.c, track_gui.c: Specifying path to wget directly only on Cygwin systems. 2003-02-06 11:28 we7u * README.1ST: Adding notes about Cygwin/ImageMagick, which works by the way! 2003-02-06 10:11 we7u * README.1ST: Another Cygwin note. 2003-02-06 09:36 we7u * README.1ST: Tweaking the Cygwin/CVS note. 2003-02-05 23:57 we7u * src/: maps.c, track_gui.c: Adding a path for the "wget" executable. Hard-coding it to /usr/bin right now. 2003-02-05 17:13 we7u * README.1ST: More Cygwin stuff. 2003-02-05 14:57 we7u * README.1ST: Added Cygwin/Shapelib notes. 2003-02-05 11:38 we7u * README.1ST: More Cygwin. 2003-02-05 11:19 we7u * README.1ST: More Cygwin notes. 2003-02-05 10:33 we7u * README.1ST: More Cygwin notes. 2003-02-05 09:34 we7u * README.1ST: Added notes about Xastir on Cygwin. 2003-02-04 22:14 rzg * help/help-English.dat: Some updates to helpfile for config|timing and filtering. 2003-02-04 17:02 we7u * src/gps.c: Adding some more CYGWIN flags around variable definitions. This part of the code isn't used under Cygwin. 2003-02-04 11:30 we7u * src/interface.c: Changing default paths from "RELAY,WIDE" to "WIDE,WIDE2-2". 2003-02-04 00:43 we7u * src/maps.c: Getting rid of warning output that really isn't all that useful. 2003-02-04 00:06 we7u * src/main.c: Added zoom in/out buttons to toolbar. 2003-02-03 20:08 jtwilley * src/: alert.c, bulletin_gui.c, color.c, db.c, draw_symbols.c, fcc_data.c, gps.c, hostname.c, interface.c, interface_gui.c, lang.c, list_gui.c, locate_gui.c, location_gui.c, maps.c, messages.c, messages_gui.c, popup_gui.c, rac_data.c, rotated.c, sound.c, track_gui.c, util.c, wx.c, wx_gui.c, xa_config.c: Changed all printf's to write to stderr instead of stdout 2003-02-03 19:52 jtwilley * src/: igate.c, main.c: Changed all printf's to write to stderr instead of stdout 2003-02-03 17:19 we7u * src/igate.c: Changes to formatting and comments only. No code changes. 2003-02-03 17:03 we7u * src/main.c: Re-ordered the timing params on the Configure-Timing dialog to make more sense. 2003-02-03 16:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the label for the Configure->Timing dialog. 2003-02-03 16:19 we7u * src/main.c: Added another slider for setting the station removal time from the database. 2003-02-03 14:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/igate.c, src/main.c: Separated the timing sliders from the Configure->Defaults dialog, making a new Configure->Timing dialog out of them. 2003-02-03 13:12 we7u * src/main.c: Changing max posit rate to every 60 minutes instead of every 45. 2003-02-03 12:56 we7u * src/main.c: Added separate object/item TX timer and associated slider in Configure->Defaults. Now people with WX stations that want to transmit every 5 minutes can set their object/item TX rate separately. Also changed the posit rate slider to go from 0.5 to 45 minutes (30 seconds to 45 minutes). 2003-02-03 12:21 we7u * src/: db.c, main.c, main.h, util.c, xa_config.c: Separate TX timer for objects and items. New slider in Configure->Defaults for it as well. Probably needs more testing to assure that it's working correctly. 2003-02-03 11:38 we7u * src/: db.c, db.h, main.c, main.h: Added a slider for setting the dead-reckoning timeout value. 2003-02-03 11:21 we7u * src/main.c: Changed Configure->Defaults timing values to sliders. Makes the code much simpler plus gives the users more options in setting the values. 2003-02-02 23:21 jtwilley * acinclude.m4, config.guess, config.sub, missing, mkinstalldirs: Modified files to work with autoconf 2.53. There are some minor bugs still, but they are being worked on. 2003-02-02 23:19 jtwilley * COPYING: Changed example to be Y2K-compliant. 2003-02-02 23:19 jtwilley * ChangeLog: Updated autoconf files for new version. Fixed COPYING Y2K distraction. 2003-02-02 21:49 we7u * src/: db.c, db.h, draw_symbols.c, xa_config.c: Added DEAD_RECKONING_TIMEOUT value to xastir.cnf. The function is no longer tied to the ghosting interval. 2003-02-02 21:05 we7u * src/: db.c, db.h, xa_config.c: Added a global variable st_direct_timeout which is saved in the config file. This specifies the timeout value for the ST_DIRECT bit. 2003-02-02 08:42 we7u * src/db.c: Added comments around the ST_DIRECT bit setting/clearing code. Change the ST_DIRECT bit timeout from 1 minute to 1 hour. This gives stations that transmit only every 30 minutes (common) a chance to be seen as an ST_DIRECT station. As the comments show in that section of code, that timeout value will in the future probably change into a global variable that is set within the config file. 2003-02-01 23:22 we7u * src/db.c: Fixed a pointer-to-integer comparison (compiler warning). Reformatted the code per Xastir project specs. 2003-02-01 20:45 jtwilley * ChangeLog: Updated ChangeLog for solution for request ID #678322 2003-02-01 20:42 jtwilley * src/db.h: Added direct_heard variable to station data structure. This variable is set each time a direct packet is received from a station. 2003-02-01 20:40 jtwilley * src/db.c: Removed old support for direct stations and added new complete direct station support. Paths with WIDE and TRACE entries of all kinds are properly checked for directness. 2003-02-01 02:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/interface.c, src/main.c, src/util.c: Partial fixes for GUI lockups due to lots of locally-controlled objects: Moved delays in interface routine so that they'd only take effect if the interface was up and transmit was enabled (both global and per-interface transmit controls). Added a statusline() the lets us know when we're retransmitting our objects/items. Delayed transmit of our items for 30 seconds after initial startup. We will still have delays each POSIT_interval when our objects get sent: Something like 2 seconds * number of up/tx-enabled interfaces * number of objects. 2003-01-31 17:04 we7u * src/draw_symbols.c: Added code to prevent wind barbs from getting drawn if their position is off-screen. 2003-01-30 17:17 we7u * src/db.c: Adding code to assure that locally-controlled objects don't expire. 2003-01-30 16:15 we7u * src/interface_gui.c: Reducing the length of the filtering input box to 190. 2003-01-30 14:48 we7u * src/interface.c: Checking for NULL pointer for filter_string. 2003-01-30 14:09 we7u * src/: interface_gui.c, interface.c: Changed to sending empty string instead of NULL if filter_string not specified when calling add_device(). 2003-01-30 13:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.h, src/interface.c, src/interface_gui.c, src/xa_config.c: Implemented a user interface for specifying filter parameters for internet servers. 2003-01-30 11:48 kd6zwr * src/main.c: commented out some unfinished code that slipped out... 2003-01-30 11:45 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c, src/xastir.h: added toggle for skipping map index on startup, moved index-now button to map pulldown. 2003-01-29 16:12 we7u * src/db.c: Changed comments. No code changes. 2003-01-29 14:08 we7u * src/igate.c: Implemented passcode checking before sending packets to each inet server. 2003-01-29 12:14 we7u * src/: util.c, util.h: Adding hashing functions into the code. This will be used soon to verify igate transmit permissions. 2003-01-29 10:17 we7u * src/maps.c: Tweaking the Locate Map Feature code to handle GNIS files that aren't formatted correctly (missing double quotes on fields). 2003-01-28 13:12 we7u * symbols/symbols.dat: Made the 'X' smaller on the laptop. 2003-01-28 13:11 we7u * symbols/symbols.dat: Added laptop computer. Put X-windows on both of the new computers. ;-) 2003-01-28 13:05 we7u * symbols/symbols.dat: Created desktop computer symbol. 2003-01-28 12:49 we7u * symbols/symbols.dat: A better helicopter. Easier to recognize both with maps and without. 2003-01-27 23:51 we7u * symbols/symbols.dat: Second attempt at a Skywarn symbol. 2003-01-27 23:34 we7u * symbols/symbols.dat: Initial attempt at a Skywarn symbol. 2003-01-27 23:07 we7u * symbols/symbols.dat: Added blank symbols for /L, /l, and \y (desktop computer, laptop computer, Skywarn symbols). 2003-01-27 15:58 we7u * src/main.c: Tweaking the update symbol portion of Create Object/Item dialog: Invalid overlays won't update the symbol in the dialog. 2003-01-27 15:18 we7u * src/: db.c, main.c: Fixing the compressed posit overlay problems and the illegal overlay problems. 2003-01-27 13:15 we7u * src/: db.c, main.c: Fix for modify object/item dialog: Overlay characters. 2003-01-27 13:01 francais1 * symbols/symbols.dat: Shrunk box back down a bit 2003-01-27 12:08 we7u * src/db.c: Fixed Create_object_item_tx_string() such that the overlay characters for objects/items don't get lost on retransmit. 2003-01-27 10:48 we7u * symbols/symbols.dat: Made white square box larger and gave it single-pixel border. 2003-01-27 10:37 we7u * symbols/symbols.dat: Made the white circle symbol (used with overlays) bigger. 2003-01-27 00:53 we7u * symbols/symbols.dat: Changed the overlay circle (alternate table). Made it a bit bigger so that the overlayed characters are easier to read. 2003-01-26 23:13 we7u * symbols/symbols.dat: Added Incident Command Post symbol at "q" position. Square split diagonally, half white/half green. 2003-01-25 20:09 we7u * src/list_gui.c: View->Weather Stations: Didn't convert barometric pressure to inches mercury when english units selected. Now it does. 2003-01-23 20:57 we7u * src/xa_config.c: Correcting error messages for get_int() and get_long() functions. 2003-01-23 20:49 we7u * src/xa_config.c: Tweaked lower limit in xa_config.c for TIGERMAP_INTENSITY from 60 to 50. This was causing user problems, and should have been 50 to begin with. 2003-01-23 16:38 we7u * help/: help-Dutch.dat, help-English.dat, help-French.dat, help-German.dat, help-Italian.dat, help-Portuguese.dat, help-Spanish.dat: Updated copyright notice. 2003-01-23 16:34 we7u * src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/location_gui.c, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/db.c, src/db.h, AUTHORS, README, xastir.1, callpass/callpass.c, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, symbols/symbols.dat: Updating copyright notice. 2003-01-23 14:10 rzg * help/help-English.dat: Updates for most recent stations menu changes, copyright year. 2003-01-23 11:42 we7u * src/igate.c: Implemented NOGATE and RFONLY options in igate.c. If either of these are seen, the packet won't be gated into the internet. 2003-01-23 11:17 francais1 * src/main.c: Fixed up overlooking of old_data sensitiveness Removed unnecessary code 2003-01-22 17:21 francais1 * src/: main.h, main.c, db.c, xa_config.c: Added display selection for wind barb. No more storing 0,1,2 in config, split out to match the structs. 2003-01-22 17:18 francais1 * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added strings for change to weather display selection because I added wind barb display selection. 2003-01-22 12:07 we7u * src/xa_config.c: We now save/restore the filter togglebutton settings. 2003-01-20 18:12 francais1 * src/db.c: Fixed dead reckoning disappears when course or speed display disabled bug. 2003-01-18 17:09 rzg * help/help-English.dat: Updated for stations menu changes. 2003-01-17 10:28 francais1 * src/xa_config.c: Storing of speed/short and weather/temp_only was backwards 2003-01-17 09:22 we7u * src/db.c: Fixed direct stations query to also check ST_DIRECT to choose stations. Thanks Reuven for pointing that out! 2003-01-17 00:10 we7u * src/db.c: Added some comments about ST_DIRECT. 2003-01-16 22:58 we7u * src/db.c: Temporary tweak to the ST_VIATNC code: Changed from 20 to 50 the quantity of packets required from a 'net interface that will cause a reset of the ST_VIATNC bit in the station record. Later this should be changed to a timer. 2003-01-16 13:38 francais1 * src/db.c, src/main.c, src/main.h, src/xa_config.c, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys: Added Mine, Via Digi, Stations and Objects to Select 2003-01-16 10:19 francais1 * config/: language-French.sys, language-Spanish.sys: Tweaked French and Spanish a bit 2003-01-16 10:08 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changed "Select Local" to "Select Direct". 2003-01-16 09:56 we7u * config/: tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7: Added "PASSALL off" to the tnc startup files. 2003-01-16 09:22 we7u * src/: db.c, db.h: Changed ST_LOCAL flag to ST_DIRECT. Makes more sense. 2003-01-15 14:25 francais1 * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Update of data filtering and display menus 2003-01-15 12:12 we7u * src/main.c: Tweak to dead-reckoning. Moved the sec_last_dr_update variable to the main.c globals area. This should preserve the last time between runs of UpdateTime(). 2003-01-14 23:46 we7u * src/festival.c: Added some more error checking. 2003-01-14 13:08 we7u * src/: festival.h, festival.c: Fixed the non-connect to Festival Server problem. This problem existed when Festival was started up after Xastir. Now Xastir will try to connect to the server when speech is desired, but will not try a new socket connection any more often than every 60 seconds. 2003-01-14 09:19 we7u * src/maps.c: Print a warning in draw_geo_image_map() if the image file cannot be read for some reason (typically permissions problems). 2003-01-13 22:23 kd6zwr * src/main.c: Added error checking for setting my station postion from mouse popup menu. 2003-01-13 21:33 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added mouse popup menu item to set my station position 2003-01-12 22:22 we7u * src/: db.c, interface.c, interface.h, main.c: Added some debugging statements in the extract_weather functions. Added a new global string that holds the last packet processed by file read or channel_data functions. If a segfault occurs, this last packet is dumped to STDERR along with the segfault message. This might help in the future to find "killer" packets. 2003-01-12 08:22 we7u * src/maps.c: Changed wget parameters to more verbose keywords. No real code changes. 2003-01-11 18:28 rzg * help/help-English.dat, README.1ST: Updated helpfile for findu.com old code removal, minor readme changes. 2003-01-11 08:38 we7u * src/maps.c: Removed old dead findu.com code (older method of accessing it, no longer used) from maps.c 2003-01-11 08:30 we7u * src/track_gui.c: Fixed findu.com get station tracks. Was using hard-coded IP address before, now uses domain name in URL. 2003-01-09 17:15 we7u * src/db.c: Implemented a range scale display. 2003-01-08 13:55 we7u * FAQ: Added a question/answer about ImageMagick's CompressImageColormap() function call. 2003-01-07 21:13 kg4ijb * src/interface.c: Check for glibc version on socket call line ~840 2003-01-07 20:43 rzg * FAQ, README.1ST: Minor updates about -devel files, minor spacing changes to README.1ST. 2003-01-07 14:26 francais1 * Makefile.am, Makefile.in, xastir.spec.in: Removed creation of placeholder map directories. 2003-01-06 14:42 we7u * scripts/: Coordinate.pm, inf2geo.pl, permutations.pl, test_coord.pl, track-get.pl, waypoint-get.pl: Changed to inf2geo.pl to accomodate other image formats. Tweaks to other scripts regarding copyright notices only. 2003-01-06 14:22 rzg * help/help-English.dat, README.1ST: Finished off "What's new", updates to map properties help, addition of fcc-get script. 2003-01-06 09:07 kg4ijb * src/: festival.c, interface.c: remove deprecated params to socket 2003-01-06 08:54 gstueve * scripts/Makefile.am: Add helper script to retrieve FCC & RAC files for XASTIR use. 2003-01-06 08:42 gstueve * scripts/: Makefile.in, fcc-get: Add helper script to retrieve RCC & RAC data files for XASTIR use. 2003-01-05 11:54 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Adding distance/bearing on status line. 2003-01-03 10:25 we7u * src/main.c: Dead code go bye-bye. 2003-01-02 13:48 we7u * src/maps.c: Adding more parameter checking after the sscanf in the map_index restore_from_file function. 2003-01-01 21:58 we7u * README.1ST: A few updates to the map directory portions. 2003-01-01 20:08 rzg * help/help-English.dat: More updates to "What's new", added instructions for rain gauge reporting size correction. 2002-12-31 13:57 we7u * src/: draw_symbols.c, maps.c, util.c: Speeding up get_line again (don't need all the filtering anymore since the Map Chooser bug was found). Fixing get_line() calls so that the arrays are long enough to contains what's read from file. 2002-12-30 11:06 we7u * src/maps.c: Fixing segfaults that could occur if GNIS files had short lines or lines containing control characters. Now checking for NULL returns from index() calls. 2002-12-29 16:36 rzg * help/help-English.dat: More updates to "whats new" section; typo fixes. 2002-12-29 15:04 rzg * README.1ST, help/help-English.dat: Round 1 of "pre-release" changes: Reorganized and cleaned up README.1ST, updated some portions as needed. Updated helpfile for map chooser changes. Still need more README work, especially doing something with all that security stuff and perhaps the OS specific stuff. And the helpfile "Whats new" needs to be written more nicely, I started but ran out of time. 2002-12-28 15:41 kd6zwr * src/maps.c: Changed the sscanf fix... cleared the string to all nulls before sscanf. The temp string broke solaris... *sigh*. This works everywhere now?? 2002-12-28 12:55 kd6zwr * src/maps.c: Added a temp string to avoid a sscanf bug(?) to prevent junk showing up in the map chooser window. 2002-12-27 14:18 we7u * src/util.c: Fixing tabs in util.c:get_line(). 2002-12-27 12:54 we7u * src/maps.c: Looking for control characters in the routine that parses the map_index.sys file and creates the in-memory map index. 2002-12-27 11:53 we7u * src/maps.c: More error-checking w.r.t. map indexing. 2002-12-26 17:09 we7u * src/maps.c: Checking for control characters as we're saving the map_index data to disk. 2002-12-26 16:33 we7u * src/maps.c: Looking for all control characters instead of just '\r' or '\n'. Added another warning message if control chars are found. Changed some comments. 2002-12-25 07:32 we7u * src/: draw_symbols.c, main.c, maps.c: Added error checking at the points where different xbitmap files were being loaded, and where symbols.data is loaded. Xastir will now output an error message before croaking if these files are not present. 2002-12-24 17:26 we7u * src/: maps.c, util.c: More filtering changes in and around get_line(). Intended to help with the weird characters Map Chooser problem. 2002-12-24 14:27 we7u * src/maps.c: Commenting out debug printf statements. 2002-12-24 12:00 we7u * src/maps.c: More error checking: Looking for control characters in file/directory names during map indexing. 2002-12-24 08:24 we7u * src/maps.c: Added some code to spit out warning messages to STDOUT if control characters other then '\n' are found in map_index.sys. 2002-12-23 00:16 we7u * src/maps.c: Initial implementation of the draw_filled flag in the map drawing routines which can make use of it. 2002-12-22 11:24 we7u * src/maps.c: Deleting dead code. Adding comments. Set a pointer to NULL after calling a routine that might free the memory space. 2002-12-22 10:54 we7u * src/maps.c: Changed function which reads map_index.sys in from disk so that it forces a sorted order for in-memory map list. 2002-12-21 23:29 we7u * src/maps.c: More error-checking while creating map indexes. 2002-12-21 08:25 we7u * src/maps.c: Added comments. Changed a few compares to read better. No real code changes. 2002-12-21 08:08 we7u * src/maps.c: Added more error-checking and debug output to the map indexing routines. 2002-12-21 00:27 we7u * src/: main.c, maps.c: Fully functional automaps selection from the Map Chooser->Properties dialog. 2002-12-21 00:08 we7u * src/main.c: More automaps stuff. Can now tweak the value in the map_index.sys file from the Map Chooser->Properties dialog. Back-end code still has to be written to use this information. 2002-12-20 23:46 we7u * src/: main.c, maps.c, maps.h: Adding automaps enable/disable to the Map Chooser->Properties dialog. More to do yet. 2002-12-20 22:38 we7u * src/maps.c: Added some debug lines. 2002-12-20 21:40 we7u * src/main.c: Moved some of the widgets to the bottom rowcol form in the Map Properties dialog. 2002-12-20 17:18 we7u * src/: main.c, maps.h: Map Chooser->Properties now brings up new dialog which allows setting map layers and draw_filled fields. draw_filled is not used yet in the code. 2002-12-20 12:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changed to Dirs/Maps Selected in map chooser instead of just files. 2002-12-20 12:36 we7u * src/maps.c: Added some comments. 2002-12-20 12:07 we7u * src/main.c: Changing the manual map index button back to its original code, where it only updates the map index instead of re-indexing from scratch. This keeps the manually-tweaked map_level & draw_filled fields intact. The original reason for starting from scratch was to remove deleted maps. This happens anyway after two Xastir restarts, so starting the list from scratch isn't really needed anyway. 2002-12-20 11:52 we7u * src/maps.c: Fixes to re-indexing so that files and directories get good default values in the index. 2002-12-20 11:52 we7u * src/main.c: New stuff having to do with Map Chooser Properties button. Not fully implemented yet. 2002-12-20 11:51 we7u * src/maps.h: Added a prototype for a function that I need to use in main.c 2002-12-19 17:04 we7u * src/: main.c, main.h, maps.c: Initial attempt at sorting/drawing maps based on map layer. It works! Next step is to get some more GUI hooks for it so that the user can specify which maps go on which layer, and which layers to enable for drawing. 2002-12-19 12:36 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a count of how many maps are currently selected to the map chooser. Doesn't quite work the way I'd like yet, but it is useful. It shows how many maps are marked in the in-memory map index as selected. That quantity can change when you tweak things in the map chooser and then hit OK. 2002-12-18 22:03 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.h: More tweaks to the Map Chooser. Fully resizable now. Add new button at the top which will eventually be used to change map properties. Changed how the "None" button works, and renamed it to "Clear". 2002-12-15 23:56 we7u * src/maps.c: Yet another attempt to clean up garbage that some people are seeing in the map index. In this tweak I check the sscanf call to make sure that the proper number of fields have been parsed from each input line. If not, that record in the map_index is dropped. 2002-12-15 23:07 we7u * README.1ST: Tweaks by Tate, KC7ZRU. Thanks! 2002-12-15 23:03 we7u * src/main.c: Changed map re-indexing button so that it deletes the entire in-memory index, then re-creates it from scratch. It is slower than the old method, but guarantees that deleted/added maps will show up in the map chooser without have to restart Xastir to do it. 2002-12-15 21:41 we7u * src/festival.c: Change to some debug code. 2002-12-15 18:28 we7u * src/festival.c: Now doing a check in the festival code for duplicate strings. Only one string is held in the queue for 30 seconds. If the same string comes in, festival refuses to speak it. 2002-12-14 23:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added an "Expand Directories" button to the map chooser. 2002-12-14 21:34 we7u * src/: main.c, maps.c: Better implementation of map directory select/de-select in the Map Chooser. 2002-12-14 15:04 we7u * src/maps.c: A few small tweaks to how map_index strings get created for directories. 2002-12-14 00:16 we7u * src/main.c: Commented out a couple of debugging statements. 2002-12-13 23:52 we7u * src/: main.c, maps.c: First functional version of Map Chooser where clicking on a directory will select all maps below it. Still a few bugs left to squash, but it works! 2002-12-13 22:35 we7u * src/maps.c: Finished getting map directories to show up properly and in sorted order in the Map Chooser. They're selectable as well. Still have to write the code to recurse through these directories when selected/de-selected. Not fully functional yet. 2002-12-13 17:04 we7u * src/maps.c: Starting to implement storage of map directories in the map index. Not complete yet. 2002-12-13 12:04 we7u * src/main.c: Tweaks to comments. 2002-12-13 09:42 we7u * src/main.c: Including Chris Bell's new routines for directory-at-a-time map file selection. These routines are not integrated into Xastir yet. They need to be tweaked to fit into the new map_index method of map selection, and the Lesstif/Motif functions need to be combined into one function. This is a work in progress. 2002-12-10 14:51 we7u * src/db.c: Fix for dead-reckoning for compressed objects/items. 2002-12-10 14:13 we7u * FAQ: Added a note about the missing freetype library during linking. 2002-12-10 13:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a new "Re-index Maps" button to the configure menu. Useful for those instances where you've added a new map but don't want to restart Xastir in order to start using it. 2002-12-10 13:15 we7u * README.1ST: Added a note about James Jefferson's nice world map in Shapefile format. 2002-12-10 12:48 we7u * src/main.c: Fixed to map chooser. Changes now apply only to the in-dialog list until/unless the OK button is pressed. If Cancel or any other button is pressed, the changes do not take effect or get written to the selected_maps.sys disk file. 2002-12-09 09:18 we7u * README.1ST: Updating e-mail address. 2002-12-07 20:57 we7u * src/: draw_symbols.c, igate.c, maps.c, maps.h, util.c: Tweaks to help fix buffer overflows in several areas of the code. Some of them may have been caused by get_line() in util.c, which has been rewritten to prevent overflowing the string passed into it. Also added a new define: MAX_FILENAME, which is used to declare sizes of char arrays. 2002-12-07 00:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/locate_gui.c: Upon receipt of a Mic-E emergency packet: No longer bring up a popup dialog. Now bring up only a Locate Station dialog, but the titlebar has been changed to read "Emergency Locate!". 2002-11-26 16:35 we7u * src/xa_config.c: More water gage stuff. 2002-11-26 15:56 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Adding a display toggle for water gage objects. 2002-11-26 09:12 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-11-25 23:05 we7u * src/: bulletin_gui.c, db.c: Finishing up the bulletins-before-posits code. Now bulletins come up as soon as the posits for that station are received. 2002-11-25 17:10 we7u * src/: db.c, db.h: Start of trying to fix distance=0 bulletins for when posit comes in later. A bit more code to write, but this keeps track of whether or now the posit is currently known. 2002-11-25 13:19 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/bulletin_gui.c, src/main.c, src/main.h, src/xa_config.c: Something several of you have asked about in the past: A way to stop the popup and display of bulletins with zero distances. Two togglebuttons in this case control the same global variable: One toggle on the Configure->Defaults dialog, and another on the View->Bulletins dialog. 2002-11-25 10:40 rzg * help/help-English.dat: Updates for dead-reckoning, other minor changes. 2002-11-25 09:42 we7u * README.1ST: A bit more about installing festival from RPM's and changing the default voice. 2002-11-23 22:11 we7u * src/util.c: Tweaks to the speech stuff so that we don't add commas to the SSID portion of a callsign. This makes it speak -12 as "dash twelve". 2002-11-23 20:20 we7u * README.1ST: Added a blurb about festival and starting it in server mode. Useful for those that can't read the English help file (where it is also documented). 2002-11-23 08:18 we7u * src/util.c: Speech stuff now looks for a number in the text (before a dash). If found, it adds commas so that Festival will speak each letter. If not found, it feeds the string directly to Festival to let it try to pronounce it. 2002-11-23 00:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/festival.c, src/main.c, src/popup_gui.c, src/util.c, src/util.h: Changes to make Festival speak callsigns out letter by letter. 2002-11-22 17:16 we7u * scripts/inf2geo.pl: Tweaked to handle different cases for filenames, and to put the proper case into the GEO file for the GIF file. 2002-11-22 15:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Separated out more festival speech strings from the other language strings. Changed the "New Station" speech string to just "New" to speed things up a bit. 2002-11-22 11:20 we7u * README.1ST: Added the su & exit around the "make lib_install" for the Shapelib install. Thanks Bob! 2002-11-21 21:15 we7u * src/: maps.c, popup_gui.c: Code fixes for when required fonts can't be found. Error messages are output and Xastir recovers, instead of segfaulting. 2002-11-21 17:56 we7u * src/popup_gui.c: Changing to another font. 2002-11-21 17:44 we7u * src/xa_config.c: Deleting a duplicated variable. 2002-11-21 17:38 we7u * README.1ST: Added notes about the two new auto-identification methods. 2002-11-21 17:06 we7u * src/popup_gui.c: Correcting small error in variable name. 2002-11-21 16:53 we7u * src/popup_gui.c: Moved the Speech ID stuff to the beginning of the ID routine so that the spoken text and the screen ID will occur at roughly the same time. 2002-11-21 16:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/popup_gui.c, src/xa_config.c, src/xastir.h: Added station ID in the form of large text across the screen, and spoken station ID via festival. Occurs every 9.5 minutes if two new variables in the config file are enabled. 2002-11-21 10:20 we7u * src/util.c: Minor tweak to make sure that objects/items only get one hash mark added to the front of the line in the ~.xastir/config/object.log file. 2002-11-19 10:29 francais1 * src/: main.c, main.h, xa_config.c: Added "hidden" conf file value to adjust DR update rate Default is 30 s 2002-11-19 10:20 we7u * src/db.c: Fixes so that dead-reckoning and "Display Moving Stations" work properly even when we only have one position from a station. They are now classified with ST_MOVING flag if the speed is non-zero. 2002-11-19 09:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/draw_symbols.c, src/main.c, src/main.h, src/xa_config.c: Added new buttons to enable/disable the different dead-reckoning display objects. This allows users to get the display as cluttered or uncluttered as they like. 2002-11-19 09:10 we7u * src/xa_config.c: Changing default for dead-reckoning to ON. 2002-11-18 16:25 francais1 * src/: draw_symbols.c, main.c: Added call to draw_symbols in UpdateTime at least every 30 s if dead reckoning drawing is turned on. Tweaked dead reckoning graphics to draw the DR trail in a dashed line and draw an arc that gets larger as time from last posit grows until it turns into a circle. 2002-11-18 13:19 we7u * src/draw_symbols.c: Fixing the bug where weather stations hit the clear interval but wind barbs still get drawn. 2002-11-17 21:48 kd6zwr * src/main.c: added keysyms for pgup/pgdn on sun keyboards 2002-11-14 18:02 we7u * src/util.c: Code to handle disowning of object that other people take over, and to comment out our own objects from the object.log file when we delete them. This keeps us from retransmitting the objects when Xastir restarts. 2002-11-14 16:25 we7u * src/: main.c, util.c, util.h: More object stuff. More to do yet. 2002-11-14 15:50 we7u * src/: db.c, util.c, util.h: The start of code to allow disowning an object that someone else is assuming control over. Xastir already does this while running, but it doesn't write the data to the object.log file, so when it starts up, it owns the object again. 2002-11-14 14:07 we7u * src/db.c: Saving empty-string for speed instead of "0" if speed is unknown on a parsed packet. 2002-11-14 12:40 we7u * src/db.c: Unlinking DR functions from Display Course/Speed toggles. 2002-11-14 11:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Initial implementation of dead-reckoning by J. Lance Cotton, KJ5O. Thanks very much to him for doing this!!! 2002-11-13 15:31 we7u * src/maps.c: Forcing terraserver map extents in the index to be at the edges of the earth. Added more statusline messages for loading/indexing maps (more consistent now). 2002-11-13 14:13 we7u * src/maps.c: An attempt to fix the buffer overflow problems with map indexing. 2002-11-13 13:19 we7u * src/main.c: We now delete/recreate our own station record only if we change our callsign. All other changes just cause an update to the current record. 2002-11-13 12:43 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: New "Waiting for GPS data.." string. 2002-11-13 12:40 we7u * src/: db.c, interface.c, main.c, main.h: Implemented a countdown from when GPS data goes invalid. It is decremented each time a posit occurs. When it reaches zero, posits stop. Valid GPS data parsing will reset it back to the starting count. Also reduced the size of the tracked station circles in order to more easily read the station data. 2002-11-12 18:23 we7u * src/db.c: Added another blue circle for tracked stations. Now three concentric circles. 2002-11-12 18:17 we7u * src/db.c: Making a tracked station have both a yellow and red circle to make it easier to see against different map backgrounds. 2002-11-12 18:07 we7u * src/: db.c, interface.c, main.c, main.h: Added "my_position_valid" variable, initially set to 1. As soon as a GPS interface of any type is started up, this variable gets set to zero, and it holds off posits. Once the first valid GPS position is parsed, this variable is again set to 1, and posits proceed normally. As Xastir comes up, interfaces are brought up before the first posit, so if a GPS interface is enabled on startup, no posits will occur until the first GPS posit is parsed properly. This variable could be used later to disable posits when GPS data becomes unusable or stops coming in. This feature is not implemented yet though. 2002-11-12 15:23 we7u * src/db.c: Changed tracked stations circle from Red to Yellow to make it easier for partially colorblind people to see against a background of topo maps. 2002-11-12 14:56 we7u * src/db.c: Got rid of another bug off the buglist. Now only stations that are currently visible will be selected for Station Info operations. 2002-11-12 14:15 we7u * src/main.c: Changed the order of startup so that map indexing is completed before interfaces are brought up. 2002-11-12 10:56 we7u * src/maps.c: Changes intended to keep variables from going out-of-bounds. I'm attempting to get more DRG-Enhanced map formats working. These changes don't quite make them work, but they do make it better and catch some out-of-bounds problems. 2002-11-11 15:01 we7u * configure, configure.in, ltconfig: OpenBSD 3.1/IA32 patches by Yasholomew Yashinski. Thanks! 2002-11-09 18:04 kd6zwr * src/main.c: Fix for white foreground on solaris (uninitialized color) 2002-11-07 16:14 we7u * README.1ST: Added a note about MrSID file compression. 2002-11-07 16:10 we7u * README.1ST: Added some notes about DRG-E files. 2002-11-06 22:40 we7u * README.1ST: Added some "su" lines and some comments about "ginstall". 2002-11-06 15:15 we7u * FAQ: Added a section about geoTIFF's causing segfaults. 2002-11-06 12:47 we7u * README.1ST: Added a section describing the FGD file format portion that we use. 2002-11-01 16:56 we7u * src/maps.c: Changed one comment. 2002-10-31 16:27 we7u * src/maps.c: Added checks in the geoTIFF code for neat-line map boundaries being outside normal limits. If found, output warning message, reset the corner to something more reasonable, and continue on. 2002-10-31 13:52 we7u * src/: datum.h, maps.c: Converting from using proj.4 to using datum.h/datum.c in order to do our datum translations for geoTIFF maps. 2002-10-30 13:40 francais1 * src/: draw_symbols.c, main.c, xastir.h: Added support for 25% and 12.5% stipples when drawing station ambiguity. 2002-10-30 13:38 francais1 * symbols/: 13pct.xbm, 25pct.xbm, Makefile.am, Makefile.in: Added pixmaps for 25% and 12.5% stipples 2002-10-30 11:08 we7u * src/: db.c, draw_symbols.c, main.c: Fixed some conversion problems for speed/wind speed. Added some notes. Wind barbs are not shown properly in knots instead of mph. 2002-10-29 14:26 we7u * src/db.c: Tweaks to the wind direction/wind speed decoding for weather stations. We were missing speed/direction for many weather packets. Many more wind barbs are now showing up. 2002-10-28 22:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added a new toggle to the Defaults dialog for enabling/disabling warnings for modifier keys. 2002-10-25 15:04 we7u * README.1ST: Changing some notes regarding map permissions and running as the root user. 2002-10-25 13:34 we7u * README.1ST: Added a note about map and map directory permissions. Added warnings regarding running programs as the root user. 2002-10-24 17:32 rzg * help/help-English.dat: Updates for the Map and Station menu changes. 2002-10-23 16:12 we7u * src/draw_symbols.c: Cleanup of debug code & comments for the wind barb stuff. 2002-10-23 13:28 we7u * src/: db.c, draw_symbols.c, draw_symbols.h, main.c: Wind Barb implementation. Enable/Disable togglebutton has yet to be added to disable these. 2002-10-22 15:16 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-10-22 14:37 we7u * help/help-English.dat: Another item for your todo list. 2002-10-22 14:12 we7u * src/maps.c: Tweak to weather alert code to compensate for NULL fields in the NOAA shapefiles. Weather alerts should now appear in the proper places even if using newer NOAA files. 2002-10-21 23:35 rzg * README.1ST: Oops, didn't mean to revert that stuff... 2002-10-21 23:29 rzg * README.1ST, FAQ, help/help-English.dat: Minor fixes/updates to docs. 2002-10-20 22:53 francais1 * src/db.c: ST_VIATNC is what I really wanted... 2002-10-20 22:26 we7u * src/interface.c: Moved a variable inside the proper #ifdef statements. It was causing a compiler warning on systems without kernel AX.25 interface support. 2002-10-20 21:30 francais1 * src/: main.c, maps.c, maps.h: Enabled +/= and - to change the grid size a bit. 2002-10-20 20:15 francais1 * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Expanded "Display Stations" into "Display Local Stations" and "Display Non-Local Stations" 2002-10-20 18:06 francais1 * src/: db.c, interface.c, interface_gui.c: First pass at relay digipeating over an ax25 interface. Look for the define I_WANT_TO_TRY_AX25_RELAY_DIGIPEAT in db.c and interface_gui.c 2002-10-19 12:06 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added an ID string to the status line for the periods when no traffic is coming in. If the ID string doesn't appear for 9 minutes straight, it is forced onto the statusline for a few seconds in order to meet ID requirements. This is useful for beaming an Xastir image over amateur fast-scan television. Tweaked the Configure->Station callsign block so that all characters of a full callsign plus SSID are displayed. Tweaked the weather symbol display code so that " " and "..." are not taken to be a zero reading. 2002-10-18 15:42 we7u * src/maps.c: Changes in the GNIS map-reading code to accomodate the lack of consistency in how the GNIS files are formatted. 2002-10-18 14:04 we7u * README.1ST: Added a note from Chris about GNIS file. 2002-10-18 12:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Broke up Stations menu into submenus. 2002-10-18 10:13 we7u * src/main.c: Set default ON for new togglebuttons on stations menu. 2002-10-17 22:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Initial attempt at some station/object display filtering. What is coded so far works, but most of the variables are not saved in the config file yet. May need more togglebuttons & variables implemented yet. 2002-10-17 15:41 we7u * AUTHORS: Minor cleanups and added a few contributors. 2002-10-17 15:23 we7u * README.1ST: Move "Previous Install Notes" section to a later point in the file. 2002-10-17 15:05 we7u * src/db.c: Tweaks to get rid of compiler warnings for Debian/S390. Changed char's to int's and got rid of some casts. 2002-10-17 12:13 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-10-16 14:10 we7u * src/db.c: Added draw_symbol_filtered() function. Will eventually add code to this function which implements display filtering. 2002-10-15 14:28 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Implemented different colors for tropical storm/depression and hurricane packets, for the three different wind speeds: Green = gale force wind radius, yellow = tropical storm wind radius, red = hurricane wind radius. 2002-10-15 13:38 we7u * src/db.c: Converted storm circles from nautical miles to miles before calling draw_pod_circle. Ranges are now correct. Added a couple of comments as well regarding things yet to be done. 2002-10-11 16:25 we7u * src/wx.c: Added a comment about Dallas rain gauge. 2002-10-11 12:55 we7u * src/db.c: Initial attempt at drawing circles around storm objects (radius of winds). Need to convert from nautical miles to miles and perhaps change to a different method of drawing, but this works for now. 2002-10-11 12:54 we7u * src/wx.c: Commented out a debug line. 2002-10-11 12:53 we7u * src/draw_symbols.c: Added some comments. 2002-10-10 15:56 we7u * src/wx.c: Wind speed for Dallas one-wire WX station. 2002-10-10 15:21 we7u * src/wx.c: Correction to temperature conversion for Dallas WX station. 2002-10-10 15:19 we7u * src/wx.c: Support for wind direction for Dallas WX station (using OWW daemon for the data feed). 2002-10-10 13:40 we7u * src/interface.c: Now handle 0x00 characters in port_read, for the case where the One-Wire Weather daemon ("OWW") sends them to us. Temperature from a Dallas one-wire station is now initially coded and appears to be working. 2002-10-10 13:38 we7u * src/wx.c: Changed some comments and put one message under debug_level control. 2002-10-10 13:05 francais1 * src/util.c: phg_decode was missing the phg circle radius/2 stuff put into phg_decode. 2002-10-10 01:48 we7u * src/: db.h, wx.c: Initial support for Dallas One-Wire weather station. Xastir gets it's data from the OWW server. We currently only parse out the temperature, and it appears we only do that once when the network port is brought up. More functionality to be added later. 2002-10-08 22:52 we7u * src/: main.h, maps.c, maps.h, track_gui.c: Fixed bug where TrackMe button didn't get disabled when tracking was cleared from the menus. Map indexing now removes indexes for deleted files. Another ImageMagick API change is now handled in our code. 2002-10-08 21:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: We now check for modifier keys when the third mouse button press is detected and dump out a warning message asking the user to turn off the modifier keys. 2002-10-04 00:20 we7u * src/db.c: More correct parsing of Storm Data. 2002-10-03 17:31 we7u * src/db.c: Commenting out debug statements. 2002-10-03 17:29 we7u * src/: db.c, db.h: The start of decoding storm data. More to do in terms of units conversion and display, but the basic packet decoding is coded and working. 2002-10-03 16:06 we7u * src/maps.c: Added a comment. 2002-10-03 11:35 we7u * src/: maps.c, track_gui.c: Small tweaks to wget error messages. 2002-10-03 11:25 we7u * src/: main.c, maps.c, maps.h: Updates to map indexing. Starting to work as intended now. 2002-10-02 16:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c, src/xa_config.c, src/xastir.h: Added a Disable Raster Map togglebutton to the maps menu. Added "Indexing" text to the statusline as we're indexing maps. 2002-10-02 15:28 we7u * src/maps.c: Changed auto_maps to use the in-memory map index. Lot's of tweaks to sort the map index. Now use the .geo filenames instead of the http/ftp URL's. Got rid of shx/dbf filenames (using shp instead). This got rid of the triple-drawing of shapefiles that was ocurring with automaps. Added statusline() calls to all of the draw functions. 2002-10-01 10:43 we7u * src/maps.c: Added more error output for geoTIFF's, where proj may not have been installed correctly. 2002-09-30 16:50 we7u * src/interface_gui.c: Minor correction. This window was WAY too long when I defined 30 interfaces. The new length is more reasonable. 2002-09-30 16:06 we7u * src/: interface.h, interface_gui.c, main.c: Upp'ed the number of interface to 15. Tweaked the GUI and other portions of the code to handle whatever MAX_IFACE_DEVICES is set to. Xastir should theoretically be able to handle any number of interfaces now, but it's only been tested so far up to 15. 2002-09-30 00:19 we7u * README.1ST: Added a note about the 24kgrid file available from gisdatadepot. 2002-09-29 23:41 we7u * README.1ST: Added a more specific path for getting GNIS datafiles. 2002-09-29 22:04 we7u * README.1ST: Added a few more sources of Shapefile maps. 2002-09-26 16:11 we7u * src/maps.c: Fixes for Tigermap and GEO file segfaults. Saw segfaults with Tigermaps when "wget" returned a zero-length file. These changes fix this problem. 2002-09-26 13:39 we7u * src/db.c: Limiting the new togglebutton to work only on objects containing weather, not on all objects. 2002-09-26 13:29 we7u * src/: db.c, main.c: A better logical relation between the togglebuttons for the new "Display WX Object/Item" button. 2002-09-26 12:39 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Minor change to Display Weather Object strings. 2002-09-26 12:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added a new toggle for enable/disabling weather objects. 2002-09-25 15:23 we7u * src/wx_gui.c: Widening some fields by one character width in Own Weather Data dialog. 2002-09-25 15:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/wx_gui.c: Changing barometric pressure display in inches Mercury to have two digits after the decimal point. 2002-09-25 01:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/wx.c, src/wx.h, src/wx_gui.c: Implemented English/Metric barometric pressure for Own Weather Station dialog and for Station Info dialog. 2002-09-25 00:49 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added another string for weather stuff. 2002-09-24 16:49 we7u * src/maps.c: Just adding some blank lines to delineate the different functions. More real code changes to come later. 2002-09-24 13:11 we7u * src/db.c: Better handling of weather stations and weather objects. We now try to parse the course/speed field _and_ the 'c' and 's' fields in all cases, and can handle some of the different field positions that some of the RAWS weather objects present to us. 2002-09-24 10:34 we7u * src/db.c: Changed wx_fuel_moisture so that a 00 reading equates to 100%. 2002-09-23 23:48 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h: Added parsing of Fuel Temperature and Fuel Moisture for RAWS weather objects, and the corresponding display in the Station Info dialog. 2002-09-23 22:53 we7u * src/db.c: Added some comments. 2002-09-23 11:46 we7u * help/help-English.dat: _Very_ minor spelling fixes. 2002-09-23 11:40 we7u * src/maps.c: Changes to the lat/long gridlines by Thierry Leconte: "Now, the code draw solid line and 3 types of dashed lines. Solid line is, as previously, for equator and Greenwich meridian. The 3 dashed line corespond to locator coord scheme : 1st dasher line for big square (2 first letters) 2nd dashed line for the 2 numbers 3rd dashed line for small square (2 last letter). Depending of the zooming, the code could draw 1,2 or the 3 line types." We might wish to change the sizes of the boxes, but the ideas behind it and the implementation are great! Thanks Thierry! 2002-09-23 11:29 rzg * help/help-English.dat: Updates for object persistance and a few more on the new features list to be documented at some point. I still exist. :-) 2002-09-23 10:38 we7u * src/: maps.c, util.c: Fixes by Tom Russo for map indexing of GNIS files and for reading in zero-length files. Thanks Tom! 2002-09-19 15:52 we7u * src/main.c: Changes by Thierry Leconte which make degrees/minutes symbols appear in the status line, and add the Maidenhead grid locator to it as well. Small changes by we7u to tweak the widths of the textfields on the status line. 2002-09-19 14:13 we7u * src/wx.c: More changes for Peet Bros. U2K weather station decoding by David L. Norris. 2002-09-19 13:57 we7u * src/: main.c, main.h, maps.c, xa_config.c: Getting rid of WIN_MAP variables once and for all. 2002-09-19 13:49 we7u * src/db.c: More careful string copying of callsigns in a couple of places. There was a possibility of overrunning the destination string before. 2002-09-19 13:27 we7u * src/db.c: Adjusting buffer lengths to handle longer packets. 2002-09-19 12:28 we7u * src/: main.h, xastir.h: Change to allow u2k complete record mode (long packets) to get through the decoding functions. 2002-09-19 12:16 we7u * src/wx.c: Another small tweak to rain totals for u2k. 2002-09-19 11:12 we7u * src/wx.c: Changes for Peet Bros. U2K weather station decoding by David L. Norris. 2002-09-19 09:32 we7u * src/maps.c: Commenting out the map index printf's in maps.c 2002-09-19 01:08 we7u * src/main.c: Adding new language string for TrackMe button. 2002-09-19 01:03 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added new language string for TrackMe button. 2002-09-19 00:56 we7u * src/: main.c, track_gui.c, track_gui.h, xa_config.c: Implemented new TrackMe button on the main window. State is saved in config file so that Xastir starts up in the correct mode. 2002-09-18 15:48 we7u * src/: main.c, maps.c, xa_config.c: Added more map types to the VECTOR button on map chooser. Now selects ".map", ".gnis", ".pdb", and ".shp" files. Changed default name of "winmaps.sys" file to "selected_maps.sys". This last change will only take effect on new installations, or if the winmaps.sys file is deleted. 2002-09-18 14:21 we7u * src/: main.c, maps.c: Map indexing, saving/restoring from files. This version is more space-efficient. We could do more speedups by doing a sort and binary search through the index, or using a hash. 2002-09-18 12:35 we7u * src/maps.c: Small tweak to correct code which creates the empty map index file. 2002-09-18 12:30 we7u * src/maps.c: Killing off the saving of the map index for now. Plan on implementing a more space-efficient storage. 2002-09-18 12:17 we7u * src/: maps.h, main.c, maps.c: Now saving/restoring the map index to a file. 2002-09-18 11:41 we7u * src/: main.c, main.h, maps.c, maps.h, xa_config.c: Initial implementation of map indexing, still need to save/restore the map index linked list to a file. Currently the indexing occurs _after_ the first map draw, then succeeding map draws check the index which speeds things up considerably. The plan is to write the index to a file, read it in _before_ the first map draw, and then re-index only when new files appear or files are changed in the map directory. 2002-09-12 10:48 we7u * src/main.c: Added the Station Last Heard button into the Sensitive enable/disable for Symbols in the menu. It was getting grey'ed out and not returning to the Sensitive state as the Symbols Enable button was toggled. 2002-09-12 09:56 we7u * src/maps.c: Fixes to draw_shapefile_map() to set a default line width, for cases where specific maps are not recognized later in the code. The problem was that other areas in the drawing code (probably tracklines) where causing map lines to get drawn in double or triple width at times. 2002-09-10 16:35 we7u * src/maps.c: Added a default line width setting to the start of the polyline drawing portion of draw_shapefile_map(). This is an attempt to get rid of the double line-widths that are sometimes seen on the screen. 2002-09-10 16:14 we7u * src/db.c: Fixing the new track detector for the save track function. 2002-09-10 15:14 we7u * src/: db.c, db.h: A bit of housekeeping. Renaming the TrackRow2 struct to TrackRow, since the old TrackRow is now deleted from the code. 2002-09-10 12:22 we7u * src/: db.h, db.c: Fixes for station track storage. 2002-09-10 10:04 we7u * src/main.c: Creating the .xastir/tracklogs directory automatically on startup. 2002-09-09 16:29 we7u * src/maps.c: Tweak to handle parsing of newer format bounding coordinates from USGS .fgd files. 2002-09-03 09:23 francais1 * src/list_gui.c: Bug 604044 All station names were ghosted. Fixed. 2002-08-29 17:44 we7u * src/maps.c: Changed some comments. 2002-08-29 14:01 we7u * src/main.c: Changing language list to alphabetical. 2002-08-29 08:49 we7u * src/: bulletin_gui.c, db.c, util.c: Putting several debug printf's under debug_level control. 2002-08-28 13:41 we7u * src/: db.c, util.c: Fix for bulletins popping up that are out of range. We were computing the distance from our station based on the destination callsign (BLNx) instead of the originating callsign. 2002-08-27 15:43 we7u * src/: util.h, util.c: Added higher precision timers in order to time code sections. 2002-08-27 15:42 we7u * config/language-Dutch.sys: Changed by Han Sytsma, PE1FAM. 2002-08-26 14:52 we7u * scripts/: coord-convert.pl, permutations.pl, test_coord.pl: Modifying each script to add a path to /usr/local/lib in order to find the Coordinate.pm module. 2002-08-26 12:08 we7u * src/db.c: Added a few comments. 2002-08-24 11:52 kd6zwr * src/maps.c: Explicitly defined shorts as unsigned to fix wrapping problems with palm maps. 2002-08-23 10:06 we7u * README.1ST: Added a note about Tiger 2000 maps converted to Shapefiles. 2002-08-22 15:43 we7u * src/maps.c: Added some casts. 2002-08-22 14:58 we7u * README.1ST: Updated the fcc/rac call lookup installation instructions. 2002-08-22 13:58 we7u * src/maps.c: More comments. 2002-08-22 12:47 we7u * src/maps.c: More comments. 2002-08-22 12:12 we7u * scripts/: Makefile.am, Makefile.in: Adding coord-convert.pl and permutations.pl to install. 2002-08-22 11:33 we7u * src/maps.c: Changing some comments. No code changes. 2002-08-22 09:51 we7u * src/maps.c: Adding some comments to the palm map routine. 2002-08-22 09:43 we7u * src/maps.c: Changed a single-letter variable to two letters to make it easier to grep for in the code. 2002-08-21 17:19 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c, main.c: Fixes for bulletins popping up. Now waits 15 seconds to see if a posit comes in before attempting to pop up the bulletins dialog. Added filtering for characters output by an extract_multipoints debug message. 2002-08-21 11:24 we7u * src/list_gui.c: Now grey out the object/item name as well if it has been deleted. In the View->Object & Item dialogs. 2002-08-21 11:17 we7u * src/db.c: Putting out debug message in order to debug possible bulletin problem. 2002-08-21 11:16 we7u * src/list_gui.c: We now show deleted objects/items in the "View" dialogs as ghosted. 2002-08-20 15:07 kd6zwr * src/main.c: Bumped up the test for debug level dialog. 2002-08-16 15:54 we7u * FAQ: More minor tweaks to the same section. 2002-08-16 15:50 we7u * FAQ: Minor addition to the "why can't I see stations" paragraph. 2002-08-15 16:57 we7u * src/maps.c: Moved the USGS Quad labels left by one square. They appear to be in the correct places now. 2002-08-15 14:27 we7u * config/tnc-startup.paccomm: New startup file for Pac-Comm TNC's with version 5.x firmware. 2002-08-15 10:22 we7u * scripts/coord-convert.pl: Added the capability to handle "48N 122W" and similar inputs. Fixed a bug in DD MM.MM conversions. 2002-08-14 15:04 we7u * src/db.c: An attempt to prevent Emergency popups about the same callsign from appearing more often than every 30 minutes. 2002-08-14 13:51 we7u * scripts/: coord-convert.pl, permutations.pl: Adding a blank line between user input and output lines. 2002-08-14 11:21 we7u * scripts/permutations.pl: And handling yet another format... 2002-08-14 11:15 we7u * scripts/permutations.pl: Tweaks to more properly format some inputs. 2002-08-14 10:55 we7u * scripts/permutations.pl: Tweaks to allow shorter lat/lon strings to be processed. 2002-08-14 10:12 we7u * scripts/permutations.pl: Added the capability to write APRS Items to a log file that can be sucked in by Xastir. 2002-08-14 09:52 we7u * src/db.c: Minor tweak to get rid of compiler warning. 2002-08-14 08:49 francais1 * src/util.c: Nasty lat/lon to/from UTM conversion bug. (Wasn't referencing correct ellipsoid.) Also made last 2 characters of grid square location lowercase since that seems more common. 2002-08-14 08:49 francais1 * src/main.c: Nasty lat/lon to/from UTM conversion bug. (Wasn't referencing correct ellipsoid.) 2002-08-13 17:12 we7u * scripts/permutations.pl: New script which will show various permutations for a lat/lon or UTM input. Eventually plan to have this script write a log file containing objects so that Xastir can plot each of the positions. This will be useful in quickly determining which of the formats is within the area of interest. Developed this for Search & Rescue applications. 2002-08-13 16:51 we7u * scripts/coord-convert.pl: Added a range check for the Easting value. Not exact, but better than nothing. 2002-08-13 15:34 we7u * scripts/coord-convert.pl: Added capability to use UTM as the input coordinate. 2002-08-13 14:36 we7u * scripts/: Coordinate.pm, test_coord.pl: Getting the dates right for the copyright. 2002-08-13 14:34 we7u * scripts/: Coordinate.pm, coord-convert.pl, test_coord.pl: Tweaks to headers. 2002-08-13 14:01 we7u * src/db.c: Commenting out debug statement. 2002-08-13 13:47 we7u * src/db.c: Fixed Mic-E decoding problem having to do with position ambiguity. We have to specifically test for 'L' in the destination field as it doesn't match the general bit patterns. Stupid spec anyway. 2002-08-13 11:39 we7u * src/: db.c, db.h, draw_symbols.c, draw_symbols.h: Severe storm objects by Gerry Wheeler, KG4NBB. Dale Huguley, KG5QD's weather server (on the 'net) generates severe storm objects and boundaries based on NWS data. These objects are now decoded and drawn by Gerry's new code additions. 2002-08-12 17:03 we7u * scripts/: Coordinate.pm, coord-convert.pl, test_coord.pl: Utility for converting between coordinates, written in Perl. Also has UMS coordinates. 2002-08-12 12:04 we7u * src/maps.c: Pre-pending the quad index to the quad name. 2002-08-12 11:36 we7u * src/maps.c: Fix for some labels on quad overlay shapefile. 2002-08-11 09:57 we7u * README.1ST: Changed the URL where the Mac OS X instructions reside. 2002-08-09 17:34 we7u * src/maps.c: Nicer labels for the quad names. 2002-08-09 17:26 we7u * src/maps.c: Initial support for USGS Quad overlay shapefile. 2002-08-09 16:33 we7u * README.1ST: A bit more about ldconfig. 2002-08-08 23:33 we7u * src/: util.c, util.h, wx.c: Changes to 30-second timestamps in logfiles: Now closely emulate the date/time string that the date(1) command generates. 2002-08-06 16:14 we7u * src/util.c: Getting rid of a message that appears if the .xastir/config/object.log file doesn't exist. 2002-08-06 13:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a clear button for the object/item history file. 2002-08-06 13:00 we7u * src/: main.c, util.c, util.h, xastir.h: Implementation of persistent objects/items. Each new, deleted, or moved object/item is logged to "~/.xastir/config/object.log". This file is read in and each line processed on startup. This will also show tracklines for moved objects as each change is logged to the file. 2002-08-06 11:33 we7u * src/db.c: Adding "AA:" to the beginning of auto-response messages. 2002-08-06 09:52 francais1 * src/maps.c: IsPseudoClass in ImageMagick 5.3.1 doesn't quite act like I would have thought. Changed to different check. 2002-08-05 15:29 we7u * src/: messages_gui.c, view_message_gui.c: More tweaks regarding fonts. Seems we can set foreground color but not background on a couple of widgets. Trying to set background color causes a segfault. 2002-08-05 15:07 we7u * src/: messages_gui.c, view_message_gui.c: Move segfault fixes in new code. 2002-08-05 15:05 we7u * src/view_message_gui.c: Fix for segfault in newly introduced code. 2002-08-05 13:48 we7u * src/: bulletin_gui.c, draw_symbols.c, location_gui.c, main.c, messages_gui.c, track_gui.c, view_message_gui.c, xastir.h: Added defines for foreground and background font colors. This and the associated code changes should help to alleviate the problem where font colors would accidentally change during runtime due to color-ls being run in the starting Xterm. 2002-07-26 09:35 we7u * help/help-English.dat: Very minor changes to the new scripts section. 2002-07-26 09:30 we7u * src/messages_gui.c: Put another message under debug_level control. 2002-07-26 08:45 rzg * help/help-English.dat: Added scripts section, minor update to new features list. 2002-07-25 22:24 we7u * src/messages_gui.c: Commenting out some debug messages. 2002-07-25 20:29 we7u * src/: db.c, igate.c, igate.h, main.c: Implemented SENT and HEARD queues for igating->RF. Dupes are now eliminated. This includes if another igate beat us to getting a packet on RF: In that case we don't add to the traffic on RF by sending it out too. 2002-07-24 12:58 we7u * src/db.c: Fix for igating: We were testing the ST_VIATNC flag for a station first to see if it had been heard via a TNC interface. This flag gets reset if the last 20 packets were heard from non-TNC interfaces. We now check the heard_via_tnc_last_time timestamp to see if it's nonzero. This timestamp does _not_ get set to 0. The code in heard_via_tnc_in_past_hour() should work better for igating now. 2002-07-23 15:04 we7u * src/: interface_gui.c, xa_config.c: Changing txtail default value to from 10ms to 30ms. Should be proper for 1200 baud. 2002-07-23 14:37 we7u * README.1ST: Added Lindows to the list. 2002-07-23 14:27 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Turned "Full Duplex" KISS parameter into a togglebutton. 2002-07-23 13:43 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added TxTail parameter to the KISS properties dialog. 2002-07-23 13:07 we7u * src/messages_gui.c: Putting more debug messages under debug_level control. 2002-07-22 19:41 rzg * help/help-English.dat: Added mention of RELAY digipeating and fixed a formatting thing. 2002-07-22 11:08 we7u * configure, configure.in: Bumping it to version 1.1.3. Getting ready for another development release. 2002-07-22 10:41 we7u * src/: db.c, interface_gui.c: Commenting out debug message. Making Relay Digipeat togglebuttons insensitive until the code to implement them is functional. 2002-07-20 00:44 we7u * src/db.c: Don't relay from KISS interface if transmit for that interface is turned off. 2002-07-20 00:31 we7u * src/interface_gui.c: Changes to make RELAY digipeat insensitive when transmit is disabled for that interface. 2002-07-19 23:50 we7u * src/interface.c: Commenting out another debug statement. 2002-07-19 23:48 we7u * src/interface.c: Fixes to AX.25 interfaces that were broken earlier by KISS TNC changes. 2002-07-19 17:02 we7u * src/interface.c: Changes to serial lockfiles. Now closes port before removing lock. Attempts to close port and remove lock if open fails for any number of reasons. 2002-07-19 15:19 we7u * src/interface.c: Fixes for errant long packets. Code had the wrong number for the length of the incoming strings. 2002-07-19 13:51 we7u * src/: db.c, interface.c: Found an off-by-one error in incoming_data_length. Changed a lot of comments w.r.t. KISS interfaces. 2002-07-19 01:06 we7u * src/: db.c, db.h, interface.c, interface.h, main.c: More work on RELAY digipeating for Serial KISS TNC interfaces. Getting closer, but this version is still non-functional. 2002-07-18 17:02 we7u * src/: db.c, db.h, main.c: More preparation for later coding of the RELAY digipeat function. Not implemented yet. 2002-07-18 16:49 we7u * src/: db.c, main.c: More comments. 2002-07-18 16:48 we7u * src/interface.c: Fixing another double-lock problem. 2002-07-18 16:36 we7u * src/main.c: Added an important comment. 2002-07-18 16:34 we7u * src/interface.c: Fixing a double-lock problem that I introduced earlier today. 2002-07-18 14:55 we7u * src/interface_gui.c: Adding a debug_level statement in that was missing. 2002-07-18 14:47 we7u * src/interface_gui.c: Adding relay_digipeat stuff to the AX.25 interface GUI. 2002-07-18 14:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/interface.h, src/interface_gui.c, src/xa_config.c: Preliminary code including GUI support for RELAY digipeating on Serial KISS TNC interfaces. The back-end code is not implemented yet, so right now it looks pretty but doesn't do anything. The plan is to add similar support for AX.25 kernel interfaces. Regular serial TNC interfaces and NET interfaces don't need this capability. For regular serial TNC's RELAY digipeating is turned on/off in the config file for that interface. 2002-07-18 13:01 we7u * help/help-English.dat: Removed the serial port settings from the Serial KISS TNC descriptions. The port is set to 8N1 by default now and cannot be changed. 2002-07-18 12:59 we7u * src/interface_gui.c: Changed interface properties dialog when dealing with Serial KISS TNC interfaces: No longer is the user presented with serial parameter choices which are not allowed to be changed anyway. 2002-07-18 12:39 we7u * help/help-English.dat: Changed KISS interface description to agree with the code, which forces the N81 option for serial port parameters now. 2002-07-18 12:37 we7u * src/interface_gui.c: Forcing KISS interfaces to N81 for the serial port parameters. 2002-07-18 12:17 we7u * help/help-English.dat: Just spelling fixes. 2002-07-18 12:14 we7u * help/help-English.dat: A few minor additions/corrections to the KISS, TNC, and AX.25 interface descriptions. 2002-07-18 12:04 we7u * src/interface.c: Added some locks where a few were missing. Added code to send the KISS parameters down to the TNC when the port is first opened. 2002-07-18 10:45 rzg * help/help-English.dat: Updates for serial KISS TNC, message paths, igate paths, and more.. 2002-07-18 09:31 we7u * src/: db.c, db.h, interface.c, interface.h, interface_gui.c, main.c, messages_gui.c: Reorganized KISS parameter widgets in the dialog. Changed to string,length instead of relying on the terminating zero in the string for transmitting strings. This is due to the fact that KISS packets can have 0x00 in them as data. Fixed the problems with non-posit packet transmission and the Serial KISS TNC interface. 2002-07-17 18:01 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added kiss parameters to the properties dialog. 2002-07-17 16:17 we7u * src/main.c: Better behaved positioning of dialogs. They won't get positioned quite as far down the screen now. 2002-07-17 16:06 we7u * src/igate.c: Reformatted all of the igating routines. Added a specific check so that we don't re-inject TCPIP or TCPXX packets back into the internet (we don't want looping). The routines are much more understandable now and should be easier to maintain. 2002-07-17 13:54 we7u * src/interface.c: Changed/added comments. Deleted the section of code in port_read() that looked for AX.25 flag characters, as KISS packets should not normally contain them. We instead will try breaking apart the KISS packets based on \n and \r characters. 2002-07-17 13:05 we7u * src/: db.c, db.h: Changing to unsigned char for one parameter so that we can check all eight bits of each char. 2002-07-17 13:01 we7u * src/db.c: Lots of comment changes. Added check code to the decoding functions to look for and correct concatenated KISS packets. Currently the tacked-on packets will get deleted. This should get fixed in later revisions. 2002-07-17 12:25 we7u * src/interface.c: Reformatted, changed/added comments. No code changes. 2002-07-17 02:04 we7u * src/interface.c: Initial code to implement Serial KISS TNC transmit. 2002-07-16 17:00 we7u * src/interface.c: More preparation for doing KISS TNC transmit. Not finished yet. 2002-07-16 15:33 we7u * src/interface.c: Tweak to check for NULL in igate_path. Lot's of comment changes. 2002-07-16 14:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Fixed language string for KISS TNC dialog. Added comments. 2002-07-16 14:09 we7u * src/interface.c: A few more small tweaks to help with closing Serial KISS TNC interfaces. 2002-07-16 11:26 we7u * src/db.c: Added some comments. 2002-07-16 09:47 we7u * src/: db.c, db.h, interface.c, interface_gui.c, main.c: Initial implementation of Serial KISS TNC support. This one is receive-only. Still have to write the code to generate the outgoing AX.25 header for transmitting. This one may be unstable yet, but the instability should only affect Xastir instances with this port enabled. 2002-07-15 16:25 we7u * src/interface.c: Commented out some debugging code. 2002-07-15 16:24 we7u * src/: igate.c, interface.h, interface_gui.c, xa_config.c, main.c, interface.c: The start of code to implement serial port KISS tnc functionality (without using kernel-mode AX.25 ports). Not functional yet. 2002-07-15 16:03 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Just starting to add Serial KISS TNC capability. Not functional yet. 2002-07-15 01:02 we7u * src/interface.c: Fixed one problem with igate_path. Added a bunch of comments, reformatted some code, changed some variable names. 2002-07-13 10:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/main.c, src/messages.c, src/messages.h, src/messages_gui.c, src/wx.c, src/xastir.h: Implemented reverse path for messaging. Xastir now tries to figure out a reasonable return path when doing messaging. 2002-07-12 16:59 we7u * src/messages_gui.c: Adding some code in preparation for setting up individual return paths for messaging. This code figures out the return path from the last path received for that station, including dropping "RELAY" callsigns and asterisks and converting WIDEn-N callsigns to their original glory. Converts TRACE and TRACEn-N callsigns to WIDE and WIDEn-N as well. 2002-07-12 14:09 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c, src/messages.c, src/wx.c, src/xa_config.c: Implemented separate unproto path for igating. Change it via the properties dialog for affected interfaces. If nothing entered, it will round-robin between the other three interfaces or select a default path. 2002-07-12 12:15 we7u * src/db.c: Now have red circle around tracked station. 2002-07-12 11:08 we7u * src/: db.c, main.c: Added Maidenhead Grid Locator output to the Coordinate Calculator. 2002-07-12 09:52 we7u * src/main.c: Added mnemonics keys to the right mouse button menu. Now if you select it via the Maps menu you can still navigate through it via keyboard. Note that some of the options won't work properly without a mouse pointer pointing to an object on the screen, like Station Info. For those options needing to snag the mouse pointer, it appears to use whatever point the mouse pointer is on (as usual). If the pointer is outside the drawing area, all bets are off. 2002-07-11 17:20 we7u * src/db.c: Proper rounding of course when saving track data. 2002-07-11 16:54 we7u * src/db.c: Tweaking altitude/speed/course displays to skip over the first trackpoint, which is the same as our current data. We now look at the next oldest trackpoint to try to pull out slightly older data for display purposes. 2002-07-11 16:31 we7u * help/help-English.dat: A few changes to the SmartBeaconing parameter descriptions. 2002-07-11 16:22 we7u * src/db.c: Decoupling speed/course from each other for display purposes. 2002-07-11 16:10 we7u * src/util.c: Reducing PHG circles by 1/2, per Bob Bruninga's recommendations. 2002-07-11 15:46 we7u * src/db.c: Skipping first tracklog entry when filling in the Station Info dialog. It's the same as the first line or "Last Position". 2002-07-11 15:07 we7u * src/util.c: Small change to valid_path() to allow "qAC" and similar q-codes to pass through. This is a new addition from Dale Heatherington to the aprsd server for anti-looping purposes. 2002-07-11 14:45 we7u * src/db.c: Changed minimum length check for GGA/RMC strings and put one debug message inside debug_level logic. 2002-07-11 14:36 we7u * src/db.c: More general code for parsing RMC and GGA sentences. Now allows any number of digits after the decimal point for the lat/long fields. 2002-07-11 12:51 we7u * src/db.c: Tweak to make bad Mic-E positions not draw tracks. 2002-07-11 09:03 rzg * help/help-English.dat: Updates to new features list, added smartbeaconing help, other minor stuff. 2002-07-09 15:38 we7u * src/db.c: Expire code for trackpoints. Currently uses the station expire variable for choosing when to expire each trackpoint. Called from draw_trail() for each station. 2002-07-09 14:12 we7u * src/maps.c: Now outputs warning messages for Shapefile maps that have bad lat/lon values. This lets the user know which map files or which shapes within the file have problems. 2002-07-09 13:00 we7u * src/interface.c: Searching for excessively long packets earlier in the process. Now we drop them on the floor before the decode routines. 2002-07-09 11:12 we7u * src/db.c: Tweaked a debug line to output more data. 2002-07-09 10:55 we7u * src/: db.c, gps.c, interface.c, interface.h, main.c, util.c, wx.c: String lengths can be MAX_DEVICE_BUFFER length, currently defined to be 4096 characters, when going into the decode routines. These are fixes to handle these long line lengths in a graceful manner. 2002-07-08 20:17 rzg * src/db.c: Moving a newline in debugging code so it won't get lost. 2002-07-08 18:02 kd6zwr * src/maps.c: One more GNIS icon - parks. 2002-07-08 15:43 we7u * src/: alert.c, db.c, draw_symbols.c, interface.c, main.c, maps.c, messages.c, view_message_gui.c: Changing a bunch of comments. Mostly removing "we7u" bookmarks. 2002-07-07 18:30 rzg * README.1ST: Weather shapefiles are moving... 2002-07-04 11:26 we7u * src/: db.c, db.h, list_gui.c: Changes which implement dynamically-allocated tracklogs. Expiration and function which writes track to file need to be worked on yet. 2002-07-03 23:28 we7u * src/db.c: Slight reformatting and added a few comments. No real code changes. 2002-07-03 17:03 we7u * src/db.c: Commenting out some debug statements. 2002-07-03 16:59 we7u * src/db.c: Added a few comments. 2002-07-03 16:46 we7u * src/db.c: Found that the first trackpoint was getting skipped when displaying in Station Info dialog. Fixed it. We also now look in the first tracklog point for course/speed/altitude if any of these parameters are missing in the current data. Found other problems in tracklog indexing in db.c that need to be fixed yet. 2002-07-03 12:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/maps.c, src/xa_config.c: Added a new togglebutton that enables bulletin popup for new bulletins. Moved the smartbeacon enable button to its dialog. 2002-07-03 11:22 we7u * src/db.c: Reverting back to old Bulletin method for now. New method doesn't work right if bulletin received w/no posit, then posit is received later. 2002-07-03 11:14 we7u * README.1ST: Added a blurb about LD_LIBRARY_PATH variable being ignored when running Xastir as SUID root. 2002-07-03 11:10 we7u * src/: bulletin_gui.c, db.c: Fixed bulletins so that they don't pop up if distance is zero, unless the range setting is set to zero. It was getting much too annoying the other way when connected to a cached network feed. With the new code these things will cause bulletins to pop up: Distance non-zero and within range setting. Range setting set to zero. The user can also bring up the View->Bulletins dialog and it will still show the zero-range bulletins in any case. 2002-07-03 09:09 francais1 * src/maps.c: Applied, slightly tweaked and tested patch from Derrick Brashear which adds support for different PHOTOMETRIC geotiffs. 2002-07-02 16:25 we7u * src/: db.c, util.c, util.h: Added Maidenhead grid locators to Station Info dialog. Code by dl9sau which was derived from Wampes util/qth.c code by dk5sg. 2002-07-02 14:31 we7u * src/maps.c: Added more detailed debug messages for the case where lat/lon to be converted is outside the proper ranges. 2002-07-02 14:30 we7u * src/alert.c: Quieting some debug messages having to do with compressed weather alerts (which aren't implemented yet). 2002-07-02 12:40 we7u * src/main.c: Tweaked TigerMap config dialog so that strings in different languages would cause a resize of the dialog, and the dialog would be smaller/easier to use with smaller screen resolutions. 2002-07-02 11:10 n0vh * src/: main.c, maps.c, xa_config.c, xastir.h: Added code to allow the user to set the timeout for getting tigermaps from the menu. 2002-06-28 14:03 we7u * src/maps.c: Patch for corrupt fgd files by Derrick J Brashear. 2002-06-28 13:44 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h: Separated out storage and display of comments/status. 2002-06-28 11:18 we7u * src/maps.c: Added an 'X' symbol and a nicely-drawn label for waypoing shapefiles. 2002-06-28 10:47 we7u * src/maps.c: Changes to make waypoint Shapefiles appear properly in Xastir. 2002-06-27 20:30 n0vh * src/main.c: More minor updates. 2002-06-27 20:21 n0vh * src/: main.c, track_gui.c: Clean up some of the tigermap menu items and reformatted them. 2002-06-27 13:12 we7u * README.1ST: Added notes regarding ld.so.cache to the Shapelib section. 2002-06-26 10:34 we7u * src/maps.c: Fix for missing IMAGESIZE tag in .geo file: We output an error message and skip loading that file. Someday we may wish to try to find out the imagesize via calls to the imagemagick or xpm libraries. 2002-06-26 09:46 we7u * src/db.c: Bulletins no longer cause a refresh of the Send Message dialogs. 2002-06-26 08:50 francais1 * src/: list_gui.c, list_gui.h, xa_config.c: Added a number of lists definition to the end of the list number definitions so that the code doesn't need touching every time you add a new list. Moved list number definitions to list_gui.h so that I can see them from xa_config.c. 2002-06-25 17:20 we7u * src/db.h: Added a line for is_my_call(). 2002-06-25 17:13 we7u * src/: list_gui.c, main.c, xa_config.c: New list for viewing objects/items that we own. 2002-06-25 17:12 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: New strings for new list. 2002-06-25 16:45 we7u * help/help-English.dat: Spelling. 2002-06-25 16:28 rzg * help/help-English.dat: Updated helpfile for recent changes. 2002-06-25 15:03 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c: Fixes for annoying bulletins. It should only pop up the bulletin dialog now when new bulletins come in that are within range. It's possible to receive a bulletin without having a posit from that station, then get a posit, making it outside the range. In this case you may get a popup without knowing why. It's better than what it was doing before though. 2002-06-25 12:41 we7u * src/: list_gui.c, main.c, xa_config.c: Added "View->Objects & Items" list. 2002-06-25 12:33 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added string for new View->Objects & Items dialog. 2002-06-24 15:40 we7u * src/draw_symbols.c: Changed DF beam-heading objects to draw in red3. Using stippling the lines were not visible on some map backgrounds. Also narrowed the lines for pod_circles (not fully implemented yet). 2002-06-24 12:28 we7u * src/main.c: Added comments. No code changes. 2002-06-24 12:27 we7u * config/language-Portuguese.sys: Updates by David Quental, CT1DRB. Thanks! 2002-06-22 11:01 n0vh * src/track_gui.c: Update GUI so that the length of the track downloaded from FINDU can be selected. 2002-06-21 20:28 n0vh * src/maps.c: Commented all the findu code out from maps.c since it's now done from track_gui.c. It will be removed in the future. 2002-06-21 14:20 we7u * src/: draw_symbols.c, draw_symbols.h: Added draw_pod_circle() function. It has yet to be tied to a GUI anywhere. 2002-06-21 12:36 we7u * src/db.c: Added some comments. 2002-06-21 12:36 we7u * src/util.c: Added a comment. 2002-06-21 12:21 we7u * src/db.c: Leave my_last_speed in knots so it is consistent throughout the code. 2002-06-21 12:18 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Converted more strings to use langcode(). 2002-06-21 12:17 we7u * src/interface.c: Added some comments. 2002-06-21 12:15 we7u * src/gps.c: Added a commented-out debug statement. 2002-06-21 12:15 we7u * src/: draw_symbols.c, main.h: Added a comment. 2002-06-21 07:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Converted Coordinate Calculator to use langcode() strings. 2002-06-21 07:35 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added langcode() strings for the new Configure->SmartBeaconing dialog. 2002-06-21 07:02 we7u * src/main.c: Initial GUI for setting SmartBeaconing parameters. 2002-06-20 15:41 we7u * src/main.c: Adding bearing degrees to the Measure function. 2002-06-20 15:23 we7u * src/bulletin_gui.c: We now create the View->Bulletins dialog when bulletins come in. 2002-06-20 14:01 we7u * src/: igate.c, interface.c, messages.c: Added/modified some comments. 2002-06-20 12:47 we7u * src/interface.c: Added a 250ms delay after writing each waypoint. 2002-06-20 10:44 we7u * src/gps.c: Added some notes to the waypoint creation routine. 2002-06-20 10:36 we7u * src/gps.c: Fixed problem with lower-case characters when creating waypoints. 2002-06-19 17:17 we7u * src/: db.c, gps.c, gps.h, interface.c, interface.h: For those of you with Garmin GPS units: Set up the audio proximity alarm range for some distance around your station and Xastir will now create waypoints for each APRS station/object/item that it hears within that range. They'll appear on your Garmin map display as waypoints. Enjoy! You can delete the waypoints by type. They appear as the circle with the 'X' in the middle. You may want to change other waypoints to some other type before you play with this new Xastir feature. 2002-06-19 10:53 we7u * src/db.c: Fixed remove_leading_spaces() as it didn't work at all as coded. It liked to truncate after the first word. Also fixed some malloc sizes added recently. 2002-06-19 10:44 francais1 * src/db.c: strlen, not sizeof 2002-06-18 17:06 we7u * src/: db.c, db.h, list_gui.c: Additional memory savings for the node_path variable in the station database. Changed it to a pointer and allocate exact space for the string when stored or updated. 2002-06-18 16:19 we7u * src/: db.c, db.h, list_gui.c, main.c: More space savings. Turned comment into a pointer in the station record and allocate just the space we need for it. 2002-06-18 15:21 we7u * src/: db.c, db.h, list_gui.c, main.c: Changed to dynamically-allocated linked list of comment strings in the station database. This results in memory savings due to no empty strings being stored for stations without comment fields. It also shows all status and comment strings that have been seen for each station now in the Station Info dialog. We'll have loads of fun tracking MIC-E expansion on the internet servers now! 2002-06-18 11:55 we7u * src/draw_symbols.c: Simplifying the logic a bit. Same general idea. 2002-06-18 11:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added "(tm)" everywhere "SmartBeaconing" was listed. 2002-06-18 11:07 we7u * AUTHORS, README.1ST: Notes and credit for the SmartBeaconing(tm) algorithm added. 2002-06-18 10:58 we7u * src/db.c: Changes to comments only. 2002-06-18 10:35 we7u * src/: db.c, draw_symbols.c: Changed they symbol time-since-heard color to white if over 24 hours. Added a bunch of comments for SmartBeaconing. 2002-06-17 16:16 we7u * src/db.c: Minor comment change. 2002-06-17 15:13 we7u * src/: db.c, main.c: Commenting out debug printf's. Changed some other comments. 2002-06-17 14:40 we7u * src/db.c: More comments. Another tweak to SmartBeaconing: If we've sped up a bit the code will now bring the next beacon in closer (in time), instead of waiting for the next slow beacon to reset to the slower interval. 2002-06-17 14:16 we7u * src/db.c: Added a few SmartBeaconing comments. 2002-06-17 13:11 we7u * src/: db.c, main.c: Another few SmartBeaconing tweaks. Setting defaults for variables to prevent multiple beacons as we get started. 2002-06-17 12:19 we7u * src/: db.c, main.c: A few SmartBeaconing tweaks. Commented out the experimental SmartBeaconing tweaks that caused a beacon when entering/exiting stop mode. Changed how other SmartBeaconing math was done. 2002-06-17 11:42 we7u * src/draw_symbols.c: Added color-coding for time-since-last-heard display. Green for 0-29 mins, Yellow for 30-59 minutes, Red for 60 mins to infinity. This is to help keep track of which stations are active and which haven't been heard for a while. 2002-06-17 10:16 we7u * src/db.c: Moved the "reversed symbol" message into a debug level. 2002-06-14 17:19 we7u * src/xa_config.c: Tweaking SmartBeaconing defaults to something more reasonable. 2002-06-14 15:51 we7u * src/xa_config.c: Saving SmartBeaconing parameters (all 7) in the config file. 2002-06-14 15:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c: Added Enable SmartBeaconing togglebutton, language strings for it, and save its state in the config file. More to do. 2002-06-14 14:15 we7u * src/: db.c, main.c, main.h: The beginnings of SmartBeaconing support. The working code is in there but the GUI interface is not coded yet. 2002-06-14 10:58 we7u * src/draw_symbols.c: Changed "time since last report" display to show "hr" and "min" based on time. 2002-06-13 16:42 we7u * src/db.c: Fix for compressed object/item comments getting eaten. 2002-06-13 15:53 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Added "Display Last Report Time" option to stations menu. 2002-06-13 14:07 we7u * src/db.c: Final fix for trail expiring on active objects/items. 2002-06-13 12:22 we7u * src/db.c: Fixes which check for locally controlled object/item which has moved. If it has, update the time-sorting of the record and update the timestamp in the station record. This should fix the problem where an expired object, when moved, stays ghosted. 2002-06-13 11:47 we7u * src/messages_gui.c: Making Send Message dialog wide enough so that spec-compliant-length messages won't wrap to a new line. 2002-06-13 11:21 we7u * src/: alert.c, maps.c: Converting a few more snprintf's to xastir_snprintf's. This change is necessary for those systems that don't have snprintf in their libraries. 2002-06-12 17:12 we7u * src/db.c: Added some notes regarding expiration of objects. 2002-06-12 16:29 we7u * src/: db.c, main.c, util.c: More fixes for compressed objects/items. Speed/course seem to be working now. 2002-06-12 16:23 we7u * help/help-English.dat: Minor changes regarding compressed objects/items. 2002-06-12 15:57 rzg * help/help-English.dat: Updates wrt. compressed objects/posits, and satellite ack mode. 2002-06-12 14:52 we7u * src/: db.c, main.c, util.c: A few fixes for compressed position objects/items. Adding course/speed to compressed objects/items as well. 2002-06-10 17:08 we7u * src/main.c: A minor tweak the position ambiguity togglebuttons having to do with switching compressed mode on and off. 2002-06-10 16:52 we7u * src/db.c: Disabling position ambiguity on receive end if a compressed posit is received for that station. 2002-06-10 16:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Moved the compressed_posit togglebutton to the Configure->Station dialog. Added a compress_objects_items togglebutton to the Configure->Defaults dialog. 2002-06-10 15:02 we7u * src/main.c: Fixes to give increased resolution for lat/lon when using compressed packets for objects/items. 2002-06-10 14:43 we7u * src/: db.c, util.c: Fixed compressed positions so that we can take advantage of the higher resolution. 2002-06-08 12:05 n0vh * src/xa_config.c: Added some missing #ifdef statements for tigermap data in the config file 2002-06-07 18:34 we7u * src/: db.c, main.c: Initial support for transmitting objects/items with compressed positions. They're not displaying in the proper positions on the map yet though. 2002-06-07 13:48 we7u * src/interface.c: Added debugging into to interface.c. Changed the way that we run through all interfaces when transmitting. 2002-06-07 13:42 we7u * src/util.c: Added support for lat/lon string conversions where we have more digits after the decimal point. 2002-06-07 11:10 we7u * src/: db.c, xastir.h: Bring up Locate Station window if an Emergency message is received. The operator has a choice whether to center on the station or just dismiss the dialog. 2002-06-07 09:48 n0vh * src/main.c: Load Tigermaps prior to disk maps so disk maps can be overlayed if desired. 2002-06-07 08:52 n0vh * src/main.c: Disable all maps now also functions with new TigerMaps routines. 2002-06-06 18:40 n0vh * src/maps.c: More code cleanup in the tigermap section. Still some optimizations to go. 2002-06-06 18:12 n0vh * src/xa_config.c: Updated to save the tiger_flag and tigermap_intensity in the users config file. 2002-06-06 17:02 we7u * src/db.c: Added a popup dialog for MIC-E emergency messages. Displays the callsign of the station in trouble. 2002-06-06 15:03 we7u * src/: messages.c, xa_config.c: Moved range checking for message_counter to xa_config. More efficient. Only needs to be done once when starting up. 2002-06-06 14:45 we7u * src/: messages.c, xa_config.c, xastir.h: Converted message_counter to a string. Changed message sequence numbers to be 2 characters within this range: 0-9A-Za-z. This prevents lockups when messaging with APRS+ stations. 2002-06-06 14:43 we7u * src/db.c: Removed old code. 2002-06-06 11:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/xastir.h: Implemented satellite ack mode, where the Reply/Ack protocol is used to send ack's through satellites, and ack's like "ack001" are disabled entirely. 2002-06-06 10:03 we7u * src/: db.c, db.h, messages.c: Changes which implement full Reply/Ack protocol. This should speed up messaging dramatically when involved in live QSO's with the APRS programs that support this protocol. This lists currently includes aprsDOS, APRS+, and Xastir. 2002-06-05 13:28 we7u * src/: db.c, db.h, messages.c: Marking timed-out messages in Send Message dialog properly. Small changes to Reply/Ack sequence numbers. 2002-06-04 16:13 we7u * src/: messages.c, xa_config.c: Switching to base-90 for message sequence numbers (all the way to lower-case 'z'). Also tweaked xa_config.c to help us avoid the message_counter rollover problem. 2002-06-04 15:47 we7u * src/messages.c: Changed from base-91 to base-89 format for message sequence numbers. This is to avoid use of the '{' character within the sequence. 2002-06-04 15:25 we7u * src/messages.c: Converted outgoing sequence numbers to 2-character base-91 encoding. Added a trailing '}' character to signify that we're Reply-Ack protocol capable. 2002-06-04 14:32 we7u * src/messages.c: Had to take out the '}' from the sequence number as it messed things up. 2002-06-04 14:20 we7u * src/: db.c, messages.c: Message sequence numbers are saved through restarts now. Added more comments. 2002-06-04 13:27 we7u * src/db.c: Changed several comments. Decoding of Reply/Ack protocol (free-ride ACK's) is now tested and working. This really speeds up live messaging. When encoding of the free-ride ACK's is implemented as well it'll speed up messaging even more. 2002-06-03 17:50 rzg * README.1ST, help/help-English.dat: Updates for tigermap changes and minor bits I missed in the previous update. 2002-06-03 13:30 we7u * src/db.c: Minor changes to Reply/Ack's. 2002-06-03 13:14 we7u * src/db.c: The beginnings of Reply/Ack protocol decode. Not fully tested. Encode not implemented yet. 2002-06-03 09:45 francais1 * src/maps.c: Fixed up imagemagick_options struct a bit. Removed some imagemagick_options stuff from draw_tiger_map because it is not being setup since there is no .geo file. Fixed draw_tiger_map intensity/levels bug. 2002-06-03 09:21 we7u * src/maps.c: Changing some line widths and colors back to what we had before the weekend. We're not trying to duplicate the TigerMap servers colors or look-and-feel. We need more subdued colors so that symbols and tracks show up better on top of the maps. The line widths are necessary in order to more quickly identify major roads without having to rely only on color. 2002-06-03 09:18 francais1 * src/maps.c: Removed extraneous ifdef 2002-06-03 08:38 we7u * src/gps.c: Fixes for decoding GPS NMEA sentences where there are 4 digits after the decimal point. Garmin GPS-35 and the NavMan both put out an extra digit. 2002-06-03 07:59 we7u * src/main.c: Fixed segfault bug in Config_tiger. 2002-06-03 07:23 we7u * src/maps.c: Added another #ifdef around a LevelImage() call. 2002-06-02 14:59 n0vh * config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/maps.c, src/xastir.h: Made more updates to support tigermap menu item. A file is no longer required. Also, I made display of tigermaps a separate subroutine. This should probably be done with some of the other items in draw_geo_image_map as well. N0VH 2002-06-02 14:54 n0vh * config/language-Dutch.sys: Made more updates to support tigermap menu item. A file is no longer required. Also, I made display of tigermaps a separate subroutine. This should probably be done with some of the other items in draw_geo_image_map as well. N0VH 2002-06-01 12:00 n0vh * src/: main.c, maps.c: Added Tigermap menu support. 2002-06-01 11:59 n0vh * src/xastir.h: Added some external vars to support Tigermap menus. 2002-06-01 11:54 n0vh * config/language-Spanish.sys: Added items to support Tigermap menus. 2002-06-01 11:52 n0vh * config/language-Italian.sys: Added items to support Tigermap menu. 2002-06-01 11:50 n0vh * config/: language-French.sys, language-German.sys, language-Portuguese.sys: Added items to support Tigermap menus. 2002-06-01 11:49 n0vh * config/language-English.sys: Added items to support Tigermap configuration menus. 2002-06-01 11:47 n0vh * config/language-Dutch.sys: Added new lines to support the Tigermap configuration menus. 2002-06-01 11:46 n0vh * README.1ST: Removed reference to putting TIGERMAP in a .geo file which no longer works. 2002-05-31 17:32 we7u * src/db.c: Initial attempt to handle Reply/Ack messaging protocol (on the receive side only). Only implemented for APRS messaging, not UI-View messaging. 2002-05-31 14:24 we7u * src/db.c: Fixes for last_ack timer. We now refuse to send ack's or auto_answer messages any faster than every 30 seconds, even if multiple interfaces are sending us copies of the same message. 2002-05-31 12:36 we7u * src/maps.c: Simplified the print properties dialog. Commented out unused options. 2002-05-30 08:04 n0vh * src/igate.c: More cleanup of the status messages written to the console. 2002-05-29 21:32 n0vh * src/igate.c: Cleaned up some of the status messages by adding a newline to the end. 2002-05-29 17:07 francais1 * src/maps.c: Imagemagick drawing speedup for some cases. 2002-05-29 16:59 francais1 * src/: util.c, util.h: Added a simple function to roughly time code execution. 2002-05-28 09:48 we7u * src/xa_config.c: Patch for incorrect lat/long limits by Henk de Groot, PE1DNN. Thanks Henk! 2002-05-24 17:07 we7u * src/: db.c, db.h: Attempting to get rid of duplicate ack's and autoreply messages. This attempt is at least partially successful. 2002-05-24 15:01 we7u * src/: db.c, util.c: Fixed spelling error in util.c. Fixes for incorrect sorting in Send Message window for the case where the remote client has restarted and is re-using sequence numbers: Xastir will now replace the older messages in the database and update the timestamp, which keeps the proper ordering for a QSO. Messages older than 8 hours with the same text will also get replaced and get a new timestamp. 2002-05-22 14:05 we7u * src/: gps.c, interface.c, interface_gui.c, xa_config.c: Mods for CYGWIN by Charles Suprin, AA1VS. 2002-05-21 14:33 we7u * src/db.c: Getting rid of unneeded extra message_update() calls. 2002-05-21 12:27 we7u * src/db.c: More messaging fixes. 2002-05-21 12:02 we7u * src/: messages_gui.c, db.c: Fixes for text corruption in Send Message window. Needs further testing. 2002-05-21 10:19 we7u * src/: util.c, view_message_gui.c: Fixing distance calculation such that it returns 0.0 if we haven't heard a posit from the remote station yet. 2002-05-21 09:18 we7u * src/view_message_gui.c: View->Messages history dump now obeys the distance limit set at the top of the form. 2002-05-20 14:49 we7u * src/: view_message_gui.c, xa_config.c: We now dump all currently active messages out to the view->messages window when it's first opened. Different format, but still useful. The format is easily tweaked later. Also changed the default VIEW_MESSAGE_LIMIT to 10000. This can be tweaked by the user in the ~/.xastir/xastir.cnf file. Max allowed by the code is now 99999. 2002-05-18 00:06 kd6zwr * src/maps.c: Draw symbols for GNIS files. 2002-05-17 16:55 we7u * src/interface.c: Temporary fix for CYGWIN. Disables use of HSP adapter. Better fix needs to be implemented. 2002-05-17 16:52 we7u * src/interface_gui.c: Mods for CYGWIN. 2002-05-17 15:56 we7u * src/: main.c, messages_gui.c: Added as another method to send a message in the Send Message dialog. 2002-05-17 15:26 we7u * src/db.c: Quick check for a zero time in the message database. If found, fill in with current time and print out a warning. 2002-05-17 14:14 we7u * src/db.c: Only cause a Send Message dialog update on the first ack. Subsequent ack's cause no update. 2002-05-17 11:37 we7u * src/db.c: Update message windows only when the first message or the first ack comes in, or when the message doesn't match the same sequence number message already stored. This helps to reduce flashing of the messages windows due to multiple copies of ack's/messages being received. 2002-05-17 00:01 we7u * src/db.c: Changes to eliminate dupes in Send Message dialog. Also changes to keep the message sequence more normal. 2002-05-16 16:29 we7u * src/: db.c, interface.c: Fixes for reverse video instantly on sending a message, before it's acked. 2002-05-16 15:35 we7u * src/db.c: Messaging fixes. Outstanding packets are now reverse video. 2002-05-16 14:47 we7u * src/: db.c, db.h, messages.c: The start of visual indicators for unacked messages. Not completely working yet, but doesn't break functionality either. 2002-05-16 09:38 we7u * src/: gps.c, interface_gui.c: Fixes for Mac OS X (no strptime call), and for non-linux systems. The "Set System Clock from GPS Data?" togglebutton should be grey'ed out now for non-linux systems. 2002-05-14 20:26 rzg * help/help-English.dat: Updated/rewrote .geo section for n7tap's new additions. 2002-05-14 11:56 francais1 * src/maps.c: Backed out previous change. 2002-05-14 09:56 n0vh * src/maps.c: [no log message] 2002-05-10 17:22 we7u * src/messages_gui.c: Allowing multiple messages to be queued up without having to wait for an ack for each one. 2002-05-10 17:21 we7u * src/messages.c: Allowing multiple messages to get queued up without having to wait for an ack for each one. 2002-05-10 17:20 we7u * src/db.c: Reformatted one line. No code changes. 2002-05-10 15:50 we7u * src/: messages.c, messages.h: Slightly better timing of messaging. Also free's up the queue after a message times out. More work to be done. 2002-05-10 15:22 we7u * src/db.c: Added some notes about a bug in messaging. 2002-05-10 08:08 francais1 * src/main.c: Added a missing if defined HAVE_IMAGEMAGICK 2002-05-09 22:59 we7u * src/: db.c, main.c, messages.c, messages_gui.c: Messaging in the Send Message dialog are now sorted by time. The window is also resizable now in both directions. The 5-second update of the window has been replaced by code which updates the window whenever new messages arrive. 2002-05-09 16:34 francais1 * src/maps.c: Fixes for older imagemagick versions. 2002-05-09 15:29 francais1 * src/: color.c, color.h, main.c, maps.c, maps.h, xa_config.c: Sped up drawing of DirectColor images on a DirectColor screen. It was very slow because it called XAllocColor for every pixel in a jpeg. It now uses saved information on the default display visual to pack the RGB into the correct bits for the pixel. I did this because I was finding some nasty color effects with the image intensity settings. I decided to leave image intensity around for geotiffs, but now use gamma correction from Imagemagick for all other image formats that go through imagemagick. There can now be a gamma setting in each .geo file and there is an overall adjustment which will subtract or add to the individual image gamma. While I was at it, I enabled the ability to specify several of the imagemagick enhancement functions in .geo files. 2002-05-09 14:31 we7u * src/main.c: Filling the drawing area with grey right away. Gets rid of garbage that shows up on the screen sometimes when starting Xastir. 2002-05-09 13:28 we7u * xastir.spec.in, scripts/Makefile.am, scripts/Makefile.in: Tweaks to make the appropriate scripts get installed in /usr/local/bin, with the appropriate execute permissions. 2002-05-09 13:07 we7u * help/help-English.dat: Correcting spelling of "finger". 2002-05-09 13:04 we7u * Makefile.am, Makefile.in: Adding the scripts directory as a target of the Makefiles. 2002-05-09 12:58 rzg * README, README.1ST, help/help-English.dat: Assorted helpfile updates: point shapefiles, weather stipples, and random work on README. 2002-05-09 12:55 rzg * FAQ: Changes "XASTIR" to "Xastir" to match other docs. 2002-05-09 12:34 we7u * configure, configure.in, xastir.spec.in: Tweaks to install scripts into /usr/local/xastir/script/ directory. 2002-05-09 12:33 we7u * scripts/: Makefile.am, Makefile.in: Adding Makefiles to install scripts into /usr/local/xastir/scripts/ directory. 2002-05-08 13:52 we7u * scripts/waypoint-get.pl: Here's the companion script to track-get.pl. This one will snag all of the waypoints out of a Garmin GPS and create an APRS item out of each one. The resulting file can be read in by Xastir as a log file to make the waypoints appear on the map screen. 2002-05-08 12:48 we7u * scripts/track-get.pl: Added another message at the end. 2002-05-08 12:38 we7u * src/: db.c, main.c, main.h: Fixes for some compiler warnings, by Chris Bell, KD6ZWR. 2002-05-08 12:04 we7u * scripts/track-get.pl: New Perl script which can fetch the tracklog from a Garmin GPS, then create a log file which can be read by Xastir. Read in the log file and you'll have a track on Xastir's map screen. Needs tweaks to Xastir in order to view more than 100 points of the track at a time. 2002-05-07 22:45 we7u * src/maps.c: GNIS code fixes by Chris Bell, KD6ZWR. 2002-05-07 11:40 we7u * src/: main.c, maps.h: Xastir will now do a PNG snapshot every time the "Enable PNG Snapshots" button is re-enabled. This beats waiting 5 minutes for the next snapshot while you're experimenting with things. 2002-05-06 22:19 we7u * src/maps.c: First implementation of Point-type Shapefiles. Seems to work fine so far. 2002-05-06 16:04 we7u * src/db.c: Reformatting a warning message to make sure that we only output printable chars to STDOUT. 2002-05-06 15:01 we7u * src/: db.c, util.c: Fixes for AEA formatted headers. They now should get converted properly to TAPR-2 style headers. What was missing was the re-arranging of the callsigns in the header to the correct order. 2002-05-05 17:53 we7u * src/maps.c: Changing default color for pedestrian trails, used if later code doesn't set the color explicitly. 2002-05-04 09:55 we7u * src/xa_config.c: Another tweak to limits checking. 2002-05-03 22:38 we7u * src/xa_config.c: Tweaking the value limits for list window sizes. 2002-05-03 16:52 we7u * src/maps.c: Fixing a segfault for non Tiger-based Shapefiles (like the NOAA interstates file). 2002-05-03 15:58 we7u * src/maps.c: Fix for incorrect line colors at times for Shapefiles. We also make city borders narrower as we zoom out. 2002-05-03 15:16 francais1 * src/list_gui.c: Added mouse scroll wheel support to list dialogs. Uses standard button4/5 method no modifier moves 2 lines shift moves 1 line control moves 10 lines 2002-05-03 13:52 we7u * src/maps.c: Changing colors of cities and borders around/between cities. 2002-05-03 12:28 we7u * src/maps.c: More subdued colors for the major roads. Cranked the width down a bit too. 2002-05-03 12:14 we7u * src/maps.c: Setting up more default colors. Pedestrian trails are now red. Dashed lines for trails, 4WD roads, ferry crossings. Glaciers are now white. 2002-05-03 10:22 we7u * src/maps.c: Getting rid of compiler warning by adding "color.h" as an include file. This is needed for the GetPixelByName() call I added. 2002-05-03 09:57 we7u * src/maps.c: Cleaning up properly with warning message for Point and Multipoint Shapefiles, which aren't implemented yet in Xastir. 2002-05-02 16:53 we7u * src/maps.c: This ones for Ken: Download and select plc00 files from GeographyNetwork to get the "designated places" boundaries filled in with PaleGoldenrod color. The code will also label these areas. Create the following subdirectories to get the layering right: county (cty00) designated_places (plc00) h2o (lkH and wat) misc (lkC) rail (lkB) roads (lkA) 2002-05-02 14:25 we7u * src/maps.c: Changing water back to Steel Blue. 2002-05-02 13:58 we7u * src/maps.c: More comments. Shortened another string "State Route" to "State" that occurs in the ESRI Tiger/Line Shapefiles. Changed the county polygon back to gray so that tracks show up better. 2002-05-02 12:28 we7u * src/maps.c: Added comments. Made some optimizations in the Shapefile code. Shortened some labels that get drawn. 2002-05-01 20:28 rzg * README.1ST: Update to README.1ST with more shapefile locations and other minor edits. 2002-05-01 15:43 we7u * src/maps.c: Changing how many labels appear at certain zoom levels with Shapefiles. 2002-05-01 15:12 we7u * src/maps.c: Optimization: Only doing floating point operations for label rotation when we know we're going to be drawing the label. Changes by Chris Bell to help alleviate upside-down labels. 2002-05-01 14:23 we7u * src/maps.c: Rotated labels for Shapefile maps. This be a good thing! 2002-05-01 12:11 we7u * src/maps.c: Better label drawing. Quantities of identical labels drawn in the viewport are now determined by zoom level. 2002-04-30 17:08 we7u * src/db.c: Fixing directed query responses. They now show up in a popup window. 2002-04-30 15:53 we7u * src/: main.c, xa_config.c, xa_config.h: get_int() and get_long() now check for min/max values, and assign a default value if the number is outside this range. Also prints a warning message if it has to assign the default. 2002-04-30 13:50 we7u * src/maps.c: Changing the levels at which smaller roads and labels for those roads get drawn. All roads are drawn at zoom 64 and lower. Labels for small roads start showing up at zoom 16 and lower. 2002-04-30 11:57 we7u * src/maps.c: Converting back to "convert" without path until we get configure support for figuring out the path. 2002-04-30 11:31 we7u * src/maps.c: Adding another path to convert. 2002-04-30 11:30 we7u * src/maps.c: Added path to "convert" command. Added checks around system() command. 2002-04-29 17:02 we7u * src/maps.c: Fixed some conversion problems when converting to screen coordinate system. 2002-04-29 10:40 we7u * src/maps.c: Implemented map levels for the Shapefile code. The togglebutton in the Maps menu now works for Shapefiles. 2002-04-27 16:47 we7u * src/maps.c: Setting up more zoom levels for Shapefile roads. 2002-04-27 16:03 we7u * src/maps.c: Created linked list for Shapelib labels already drawn. Keeps us from drawing 50 labels that all say the same thing. Added some zoom levels for labels of various types. 2002-04-27 12:52 we7u * src/maps.c: Getting rid of lesser roads at zoom levels 100 and above. 2002-04-27 07:59 we7u * src/maps.c: Reducing the width of water until I can figure out how Tigermap decided to determine their width. 2002-04-26 23:39 we7u * src/maps.c: A few color & width changes for shapefile maps. 2002-04-26 16:51 we7u * src/maps.c: Setting number of lanes (line width) for Tiger and Mapshots maps. 2002-04-26 11:27 we7u * src/maps.c: Changed paths to a brown color. 2002-04-26 11:14 we7u * src/maps.c: Corrected some of the headings. Split railroads out as a separate flag and a new color. 2002-04-26 10:16 we7u * src/: main.c, main.h, xa_config.c: Created a #define in main.h for enabling/disabling the "Transmit Raw WX data" togglebutton. The #define enabling this button is commented out. Most likely the only people interested in this button would be people debugging code for certain Peet Bros. weather stations where the raw data from them is allowed over the air by the APRS spec. 2002-04-26 08:53 francais1 * src/: main.c, maps.h, xa_config.c: Make map intensity menu show up in the correct cases. 2002-04-26 08:50 francais1 * src/maps.c: Make GNIS labels more readable 2002-04-25 16:04 we7u * src/maps.c: Fixing up mapshots maps for rivers/lakes. Also being proactive in trying to eliminate possible future segfaults in the Shapelib code. 2002-04-25 14:23 we7u * src/maps.c: Label fix for mapshots.com roads. 2002-04-25 13:18 we7u * src/maps.c: Changed fill color for land masses from darkgray to grey73 (a bit lighter, and the same color as the menus). 2002-04-25 11:56 we7u * src/maps.c: Added shapefile decoding of colors/types for mapshots.com county maps made from tiger data. 2002-04-25 10:52 we7u * src/maps.c: Added some comments. 2002-04-25 00:00 we7u * src/: maps.c, maps.h: Fixes for Shapefile segfaults: Can't retrieve a field that's higher than fieldcount, else segfault. 2002-04-24 16:00 we7u * src/: maps.c, maps.h: Fix for segfaults in Shapefiles. 2002-04-24 15:23 francais1 * src/maps.c: Tweaked some color problems with turning labels on. Tweaked river drawing slightly. 2002-04-24 15:09 francais1 * src/maps.c: Made gnis map files draw regardless of the labels setting since a gnis map is all labels, so if you picked it, you want it drawn, period. 2002-04-24 14:23 we7u * src/maps.c: Adding missing free() calls in draw_shapefile_map(). 2002-04-24 13:06 we7u * src/maps.c: Fixing segfault problem with Shapefile maps. 2002-04-24 11:28 francais1 * src/maps.c: IMHO, I've improved the guessing of what shapefile we are dealing with and also the drawing colors and style... 2002-04-24 11:24 francais1 * src/: draw_symbols.c, main.c, xastir.h: Changed name of pixmap_stipple to pixmap_2x2_stipple and made it load from an xbm 2002-04-24 11:23 we7u * src/maps.c: Minor change to get rid of compiler warning. Changed static variable to non-static. 2002-04-24 11:08 francais1 * symbols/: 2x2.xbm, Makefile.am, Makefile.in: Added bitmap for 50% stipple 2002-04-24 10:51 francais1 * src/: util.c, util.h: A couple new functions that will be useful for UTM grid 2002-04-24 10:50 francais1 * src/main.c: Added SteelBlue for drawing lakes, rivers (plain blue seemed pretty harsh and SteelBlue is a background color as well, so that it can be the ocean) 2002-04-24 09:58 we7u * src/xa_config.c: Commented out annoying debug statements that get in the way each time. 2002-04-24 09:54 we7u * src/: alert.h, maps.c: Speedups for weather alerts. Once we know what the bounding rectangle is for an alert, we stuff it into the alert struct. load_alert_maps() then uses that info to determine whether a shape is within the viewport, without having to snag that info from the Shapefile each time. 2002-04-24 09:20 we7u * src/maps.c: Removed old code. Put in warning printf for old weather alert stuff in routine that doesn't handle it anymore. Changed some comments. 2002-04-24 08:41 francais1 * src/maps.c: Added equator and central meridian drawing as a black line when a grid is asked for. Teasing for utm grid drawing. 2002-04-24 01:06 we7u * src/: alert.c, alert.h, maps.c: Added "index" field to alert records, initially set to -1. This gets filled in with the index into the Shapefile when the shape is searched for. This dramatically speeds up drawing of weather alerts 'cuz the search is skipped on the 2nd and later uses of the alert. 2002-04-23 23:03 francais1 * src/: main.c, maps.c, xastir.h: Initial support for using stipples for weather alerts with a description of the alert event. 2002-04-23 22:57 francais1 * symbols/: Makefile.am, Makefile.in, alert.xbm, flood.xbm, snow.xbm, tornado.xbm, wind.xbm, winter_wx.xbm, wntr_strm.xbm: Added bitmap files for use as weather map stipples 2002-04-23 22:08 francais1 * src/maps.c: Fixed indentation 2002-04-23 17:01 we7u * src/wx_gui.c: Detailed weather alerts now show up in their own resizable dialog. 2002-04-23 16:39 francais1 * src/main.c: Added support for zooming in and out with buttons 6 & 7 and for panning up and down with the scroll wheel. 2002-04-23 00:31 we7u * src/: alert.c, wx_gui.c: Cleaning up some debug messages I put in for the weather alert code. 2002-04-22 23:32 we7u * src/wx_gui.c: Added the capability to finger the weather server by double-clicking on a weather alert line in the View->Weather Alerts dialog. The output currently appears in the xterm that you start Xastir from. 2002-04-22 23:14 we7u * src/wx_gui.c: Changed View->Weather Alerts dialog to single-select mode. Added a callback and callback function for the double-click operation. 2002-04-22 22:46 we7u * src/wx_gui.c: Changed View->Weather Alerts dialog so that it can be resized. 2002-04-22 22:16 we7u * src/: alert.c, alert.h, db.c, wx_gui.c: Decoded SKY alerts. They now get associated with the proper weather alert packets. Tweaked View->Weather Alerts dialog to display them properly and added a horizontal scrollbar to that dialog. 2002-04-22 17:03 rzg * FAQ: Fixed the numbering.... 2002-04-22 16:57 rzg * FAQ, README.1ST, help/help-English.dat: Updates to FAQ, README.1ST. and help=English.dat, mostly with regard to the weather alert changeover to shapefile format. 2002-04-22 14:08 we7u * src/alert.c: Fix to weather alerts. Expired alerts will now be removed from the View->Weather Alert dialog after they've been expired more than one hour. 2002-04-22 09:57 we7u * src/alert.c: The start of adding "CIVIL" as another weather alert. Not completely functional yet. Also added more of Dale Hugueley's comments. 2002-04-22 09:47 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. Thanks! 2002-04-20 21:26 we7u * src/db.c: Slight reformatting. 2002-04-20 15:13 we7u * src/alert.c: Took out last patch. New alerts will now create a new entry, even if there is a cancel with the same zone that was received earlier. 2002-04-20 12:23 we7u * src/maps.c: Fix for changing line widths on shapefile maps. 2002-04-20 10:48 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. Thanks! 2002-04-20 10:34 we7u * README.1ST: Updated the APRS Server list. 2002-04-19 21:16 we7u * src/: alert.c, maps.c: Fixes for weather alerts. CANCL packets are starting to work now. 2002-04-19 16:27 we7u * src/: alert.c, alert.h, maps.c: Changed global variable "alert_tag" to "alert_status" so that it won't be confused with the alert struct "alert_tag" field. Added loads of comments. 2002-04-19 13:58 we7u * src/alert.c: More comments. 2002-04-19 12:30 we7u * src/alert.c: Updated some comments. 2002-04-19 09:29 we7u * src/wx_gui.c: Slight reformatting of View->Weather Alerts dialog. 2002-04-19 00:11 we7u * src/wx_gui.c: Reformatted View->Weather Alerts dialog slightly: Shorter lines and easier to read. 2002-04-18 23:42 we7u * src/: alert.c, alert.h, wx_gui.c: Added issue date/time to weather alerts and View->Weather Alerts dialog. 2002-04-18 21:42 we7u * xastir.1: Minor tweaks to eliminate redundancy, shorten the copyright years, make the words flow better. 2002-04-18 17:38 rzg * xastir.1: Minor formatting changes to look more manpage-like. 2002-04-18 16:39 we7u * src/maps.c: Speedup for weather alerts. Skip searching through Shapefiles if we already have a filename for the alert. 2002-04-18 15:59 we7u * xastir.1: Added the "-i" flag (private colormap) to the man page. 2002-04-18 15:46 francais1 * src/: main.c, maps.c: I don't believe we need to check if it is a symbolic link when we use stat, because it will follow the link. 2002-04-18 15:28 we7u * src/: color.c, db.c, main.c, maps.c, xa_config.c, xastir.h: Private colormap changes by Chris Bell, KD6ZWR. Change to weather alert timing by WE7U. 2002-04-18 12:58 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-04-18 09:11 we7u * src/maps.c: Corrected some comments. Corrected some filename prefixes. Added the capability to use symbolic linked files as weather alerts (I think, not fully tested yet). 2002-04-18 09:10 we7u * src/wx_gui.c: Added "Expired:" tag to expired weather alerts in the View->Weather Alerts dialog. 2002-04-18 09:09 we7u * src/main.c: Added the capability to read symbolic links as maps (I think). Not fully tested yet. 2002-04-18 09:08 we7u * src/alert.c: Added some comments. 2002-04-17 16:57 we7u * src/alert.c: Changed some comments. 2002-04-17 16:48 we7u * src/: alert.c, main.c, maps.c, xa_config.c: More weather alert tweaks, including the beginning of compressed weather alert decoding. 2002-04-17 13:58 we7u * src/wx_gui.c: Reformatted weather alert expire date/time in View->Weather Alerts dialog. 2002-04-17 13:52 we7u * src/: alert.c, wx_gui.c: Fixed parsing problem for weather alerts where objects after a space were being parsed as new alerts. 2002-04-17 12:58 we7u * src/: alert.c, alert.h, db.c, wx_gui.c: Changing View->Weather Alerts dialog so that it displays the data we'll need for fingering the weather server to get additional data about a particular alert. 2002-04-17 11:36 we7u * src/maps.c: Fix for weather alerts disappearing at different zoom levels or while panning around. The problem had to do with the alert getting marked as being outside the viewport, then they wouldn't be looked at again. 2002-04-16 18:02 we7u * src/maps.c: closedir() to go with the opendir(). ;-) 2002-04-16 16:17 we7u * src/maps.c: Fixes for "too many open files" in shapefile weather alerts. 2002-04-16 14:16 we7u * src/: alert.c, db.c, maps.c: Fixes to regular shapefile maps. Cleanup after shapefile weather alert additions. 2002-04-16 12:44 we7u * src/maps.c: Fixes for county weather warning alerts. 2002-04-16 11:34 we7u * src/: alert.c, maps.c, xa_config.c: Shapefile wx alert changes. Starting to work for zones. More work to do on other types. 2002-04-16 09:17 we7u * src/maps.c: Fix for Shapefile weather alerts. Nearly there now. 2002-04-16 02:19 we7u * src/maps.c: More shapefile wx alert changes. 2002-04-16 01:03 we7u * src/maps.c: More weather alert shapefile coding done. 2002-04-15 21:30 we7u * src/maps.c: We now figure out the complete filename starting with the first few characters of the shapefile. We look in the directory to figure out a match for the zone. This should make it so that we can update the shapefiles at any time and won't have to change any configuration or code in order to use the new files. 2002-04-15 20:30 we7u * src/maps.c: Initial decoding for the different types of weather alerts. Soon we'll be able to match up real filenames to the zones and start drawing them. 2002-04-15 17:07 we7u * src/maps.c: Added some more comments. 2002-04-15 16:04 we7u * src/: alert.c, db.c, maps.c: I'm breaking the weather alerts by checking in this code, but have tagged the "stable" repository with a "we7u-safe" tag, so we can recover if things get broken too badly. Forward we go! I've also released xastir-1.1.2 in the development area of the Files section on SourceForge. That is the "we7u-safe" tagged version of the sources. 2002-04-12 15:49 we7u * src/wx.c: Changing to capital 'X' for the weather-station-type designator in our transmitted weather reports, per Bob Bruninga's ok on the APRSSPEC mailing list, 04/12/2002. 2002-04-12 14:50 we7u * src/maps.c: Shapefile wx alert small changes. We're not there yet. 2002-04-12 12:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Tweaked one popup message. 2002-04-12 11:11 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: We now allow four different symbols for weather stations, but print a warning if trying to use an NWS symbol. If trying to run a weather station with a different symbol, the software will set the symbol to the standard weather symbol automatically. 2002-04-11 23:04 we7u * src/alert.c: Changed some comments. 2002-04-11 16:02 we7u * src/alert.c: More comments. 2002-04-11 14:49 we7u * src/alert.c: More comments. 2002-04-11 12:58 we7u * src/alert.c: Changed a comment. 2002-04-11 12:58 we7u * src/alert.c: Changed some comments. 2002-04-11 12:53 we7u * src/alert.c: More comments. 2002-04-11 12:52 we7u * src/alert.c: More comments added. 2002-04-11 12:46 we7u * src/alert.c: More comments added. 2002-04-11 12:01 we7u * src/alert.c: More comments. 2002-04-11 11:40 we7u * src/alert.c: More comments. 2002-04-11 11:27 we7u * src/alert.c: Reformatted some of the code, added comments. Preparing for Shapefile weather alert coding. 2002-04-11 10:13 we7u * src/alert.c: Fixed possible string overrun. Added a few comments. 2002-04-10 21:28 we7u * xastir.1: Updates by Jose Marte, HI8GN. 2002-04-10 16:59 we7u * src/alert.c: Added more comments. 2002-04-10 16:02 we7u * src/alert.c: Added a bunch of comments. 2002-04-10 14:35 we7u * src/db.c: Changed one output message to make it more correct. 2002-04-10 13:03 we7u * src/util.c: Fixing a compile warning for MacOS X. 2002-04-10 12:58 we7u * src/lang.c: Fixing a warning which shows up while compiling on MacOS X. 2002-04-10 12:00 we7u * Makefile.am, Makefile.in: Changed to more standard way of specifying man pages. 2002-04-10 10:21 we7u * configure, configure.in, src/wx.c: Bumped up to version number 1.1.2 to more easily see who's running the latest weather code. Added some comments to wx.c 2002-04-09 23:28 we7u * src/wx.c: Adding more casts back in. 2002-04-09 23:04 we7u * src/wx.c: Adding some necessary casts back in to the weather code. 2002-04-09 21:53 we7u * Makefile.am, Makefile.in: Tweaked Makefiles to install new Xastir man page. 2002-04-09 21:41 we7u * xastir.1: A few small tweaks. 2002-04-09 21:33 we7u * xastir.1: Initial man page by Jose R. Marte A., HI8GN. 2002-04-09 21:33 we7u * xastir.spec.in: Man page added by Jose R. Marte A., HI8GN. 2002-04-09 21:30 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2002-04-09 21:23 we7u * help/help-Spanish.dat: Updates by Jose R. Marte A., HI8GN. 2002-04-09 16:04 we7u * src/wx.c: Commented out the Peet Brothers U2000 Complete Record Mode parsing of today's rain total. It conflicts with the more generic method of calling compute_rain() from the incrementing long-term rain total. 2002-04-09 15:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/wx.c, src/xa_config.c: Preparation for correcting rain gauge measurements for various types of weather stations. 2002-04-09 13:34 we7u * src/: interface_gui.c, main.c: Moving "default:" cases to end of switch statements. 2002-04-09 09:35 francais1 * src/main.c: Force redraw on coordinate system change. This will make sense when I check in the UTM grid code. 2002-04-09 02:25 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/wx.c: Code to handle different types of rain gauges. Nearly complete. 2002-04-09 00:51 we7u * src/: db.c, wx.c: Added some comments. 2002-04-08 23:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added code to force the symbol to one of the two weather symbols that are legal in the APRS spec, for the cases where we're transmitting weather data. 2002-04-08 14:15 rzg * help/help-English.dat: Minor helpfile update. 2002-04-08 13:29 we7u * src/: main.c, main.h, maps.c: Fixed zooming-by-dragging, a mouse operation, so that the entire box that is dragged will appear in the final view. 2002-04-08 11:57 we7u * src/wx.c: Preparing to tweak Peet Bros code for 0.1mm and 0.01" rain gauges. No real code changes yet. 2002-04-07 11:48 we7u * config/language-Spanish.sys: Deleted duplicate lines. 2002-04-06 11:47 we7u * config/language-Italian.sys: Updated to correspond more closely with the English language file. 2002-04-06 11:11 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Spanish.sys: Keeping the other language files in sync with the English file. 2002-04-06 10:56 we7u * config/language-Portuguese.sys: Adding some missing strings. 2002-04-06 10:11 we7u * help/: Makefile.am, Makefile.in: Portuguese help file stuff. 2002-04-06 10:09 we7u * xastir.spec.in, help/help-Portuguese.dat, src/main.c: Potuguese help file stuff. 2002-04-06 09:56 we7u * config/Makefile.in: Adding Portuguese language. 2002-04-06 09:53 we7u * README.1ST, xastir.spec.in, config/Makefile.am, config/language-English.sys, config/language-Portuguese.sys, src/main.c: Tweaks to add Portuguese language to Xastir. 2002-04-06 08:06 we7u * config/language-Portuguese.sys: Thanks to David Quental for tranlating the language file to Portuguese! 2002-04-05 19:31 we7u * src/main.c: Tweak to make gps interval time switch as soon as the user changes it in the default menu. 2002-04-05 14:50 we7u * src/: main.c, main.h, maps.c: Modifying zooming in with the mouse such that it now figures out whether most of the mouse movement was in the horizontal or in the vertical direction, then computes the new zoom level based on that. Previous to this change zooming was calculated based only on vertical movement. 2002-04-05 11:14 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Changed the final exit label. 2002-04-05 08:25 gstueve * src/db.c: Reintroduce groups to the land of messaging. 2002-04-04 16:59 we7u * src/main.c: Tweaked one hotkey string that I forgot to. 2002-04-04 16:41 we7u * src/main.c: Fixed Map Chooser so that the list approriately shows what was most recently selected/de-selected via the buttons. 2002-04-04 15:37 we7u * src/main.c: Mapped the coordinate calculator to a button in the maps menu. 2002-04-04 01:39 we7u * src/main.c: Changed "About" text to say 1999-2002. 2002-04-04 01:24 we7u * src/db.c: Changed Station_data() code so that it's not destroyed and re-created each time if "Automatic Updates" are enabled. Broke out code that filled in the text into a separate function. 2002-04-03 23:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Implemented "Exit Now!" submenu off the File->Exit menu to make it harder to exit the program by mistake. It takes a deliberate effort now to do so. 2002-04-03 23:10 we7u * src/main.c: Changed Map Chooser so that only the OK and Cancel buttons will dismiss the dialog. 2002-04-03 22:56 we7u * src/maps.c: First attempt to make Shapefiles more bulletproof. Missing fields shouldn't cause segfaults anymore. 2002-04-02 23:13 we7u * src/rac_data.c: Added a popup to the RAC data search for the case where the callsign isn't found. 2002-04-02 22:25 we7u * src/fcc_data.c: Fixed severe wait when a U.S. callsign is not in the database. Also added a popup for the cases where the callsign isn't found. 2002-04-02 14:01 we7u * src/main.c: Coordinate calculator OK button is now grey'ed out until a successful calculation occurs. 2002-04-02 13:44 we7u * src/main.c: Added some debug_level statements for some printf's. 2002-04-02 13:37 we7u * src/main.c: Fixed truncation problems affecting accuracy in the last digits for the Coordinate Calculator dialog. 2002-04-02 13:21 we7u * src/main.c: Most of the coordinate calculator stuff is working now. Still a few minor truncation problems to track down and fix. 2002-04-02 09:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Now change title on Coordinate Calculator dialog based on which dialog called us. Also changed some strings to langcode strings for Coordinate Calculator and associated code. 2002-04-02 08:55 we7u * src/main.c: Added a bunch more comments having to do with the Coordinate Calculator. 2002-04-01 23:43 we7u * src/: main.c, wx_gui.c: Added linkages between Coordinate Calculator and the calling dialogs, in both directions. 2002-04-01 15:42 we7u * src/: main.c, util.c: Fixing coordinate calculator. Got rid of rounding errors by going to fixed-point arithmetic. Added comments to util.c. 2002-04-01 14:53 we7u * src/util.c: Switched to fixed-point arithmetic for lat/lon conversions to strings. Got rid of floating-point rounding errors. 2002-04-01 14:52 we7u * src/main.c: Added space between lat/lon values on status line. More readable. 2002-04-01 13:37 we7u * src/main.c: Changed Coordinate Calculator to use higher precision DD MM SS.S format. 2002-04-01 12:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/list_gui.c, src/util.c: Changed dd mm ss format to dd mm ss.s for more precision. It's more similar now to the precision of the other formats. 2002-04-01 12:28 we7u * src/util.c: Correct some comments. 2002-03-31 23:57 we7u * src/wx.c: Updated some comments. 2002-03-31 22:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/interface.h, src/interface_gui.c, src/xa_config.c: Added KD6VPE's changes to add tenth/hundredth rain gauge types to the weather interfaces. This is to support the two types of rain gauges for Peet Brothers weather stations. This patch implements a global variable and the interface widgets needed to manipulate it, but does _not_ implement the code to do anything with the variable yet. 2002-03-30 10:00 we7u * src/main.c: Changed Coordinate Calc help text so that it is obviously not good output data. 2002-03-30 09:23 we7u * src/main.c: Added some help text output to Coordinate Calculator if the user enters something that isn't recognized. 2002-03-30 01:17 we7u * src/main.c: Very minor changes to Coordinate Calculator. No additional functionality. 2002-03-30 00:12 we7u * src/main.c: More Coordinate Calculator stuff. UTM input is working now. 2002-03-29 18:40 we7u * src/main.c: Added some simulated output for what the Coordinate Calculator should display. 2002-03-29 15:47 we7u * src/main.c: More code for the Coordinate Calculator. 2002-03-29 15:00 we7u * src/main.c: Added Coordinate_calc button to Object Create/Modify. 2002-03-29 14:45 we7u * src/main.c: More coordinate calculator code. Not functional yet. 2002-03-29 10:43 francais1 * src/alert.c: Fixed errant tabs 2002-03-28 21:53 francais1 * src/alert.c: There were several strncpy's without a following str[last] = `\0` statement. One of them caused a segfault. This whole file probably needs looking over for such problems. I fixed a few I thought need the statement or in the case of some memmove's, seemed wrong to me. 2002-03-28 16:19 we7u * src/: lang.c, main.c: Fixed langcode segfault. Fixed a lang_hotkey that was wrong. 2002-03-28 15:52 we7u * src/main.c: The beginnings of a coordinate calculator for inputting coordinates in different formats. 2002-03-28 15:31 we7u * src/list_gui.h: Knocking off a compiler warning. 2002-03-28 11:28 we7u * src/: list_gui.c, main.c: View->Mobile Stations list now updates instantly when the coordinate system is changed. 2002-03-28 11:02 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/list_gui.c: Added multiple coordinate display capability to View->Mobile Stations dialog. 2002-03-28 10:41 francais1 * src/main.c: Added calls to TrackMouse for the map-moving key events so that the position status line gets updated. 2002-03-28 10:27 francais1 * src/main.c: Commented out code that clears mouse pointer location status line when we leave Xastir window because I believe we may be trying to write down that information in another window or some such action. 2002-03-27 16:54 francais1 * src/: db.c, main.c, util.c, xastir.h: Added and enabled DDMMSS coordinate format. 2002-03-27 16:21 we7u * src/db.c: Added dd.dddd and UTM capability to the Station Info dialog as well. 2002-03-27 14:26 we7u * src/main.c: Removed unused variables. Changed some comments. 2002-03-27 13:22 we7u * src/: main.c, util.c, util.h: Created convert_xastir_to_UTM_str() function to create a UTM string. 2002-03-27 12:59 we7u * src/util.c: Added some comments. 2002-03-27 12:49 we7u * src/main.c: Enclosed some calculations used only in debug mode inside if (debug_level) construct. Added a few comments here and there. 2002-03-27 10:21 we7u * src/db.c: Fixed a problem caused by the mass update to new debug levels: The station callsign was truncated in Station Info dialog if in debug level that wasn't 0 or 1. Also changed this dialog such that the characters which make up the symbol are always visible between the symbol and the callsign, whether in debug mode or not. I want to see this information. 2002-03-27 09:38 we7u * scripts/mapfgd.pl: Updates by Derrick J. Brashear, KB3EGH, to handle 1:63360 maps. 2002-03-26 23:57 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added a File->Configure->Coordinate System menu option which allows selecting between four different methods of displaying coordinates. Currently this only modifies the status bar display. Only three of the four options are currently implemented. 2002-03-26 15:43 we7u * src/main.c: Added timestamp output to stderr on segfault. 2002-03-26 15:36 we7u * src/: util.c, util.h, wx.c: Added 30 second timestamps to each logfile. Moved hour() and minute() routines from wx.c to util.c, renamed to get_hours() and get_minutes(). Added get_seconds() routine. Added code to wx.c:cycle_weather() routine to do the logfile timestamps. Cycle_weather currently runs every 30 seconds. 2002-03-22 23:20 we7u * xastir.spec.in: Trimmed down version that still works nicely. Installs /usr/local/bin/xastir as SUID root. 2002-03-22 22:34 we7u * xastir.spec.in: Fixed for binary RPM's. 2002-03-22 14:46 we7u * xastir.spec.in: Updated link to project sources. 2002-03-22 14:33 we7u * xastir.spec.in: Corrected misspelling. 2002-03-19 08:37 we7u * config/tnc-startup.kpc3: More tweaks to the kpc3 startup file by we7u. 2002-03-18 22:00 we7u * config/tnc-startup.pico: A few more pico changes by we7u. 2002-03-18 21:41 we7u * config/: tnc-startup.aea, tnc-startup.sys: Added "echo off" to two tnc startup files. This prevents echo'ed commands from showing up in the middle of tnc data. 2002-03-18 21:25 we7u * config/tnc-startup.pico: Changes hinted at by Jeff Brenton, KA9VNV. Changed into PicoPacket syntax by Curt, WE7U. 2002-03-18 21:07 we7u * config/tnc-startup.kpc3: Added changes suggested by Jeff Brenton, KA9VNV. 2002-03-18 10:00 we7u * config/language-Italian.sys: Fixes by Marco Calistri, IK5BCU. 2002-03-15 09:39 we7u * help/help-English.dat: Fixed minor spelling errors. 2002-03-15 09:35 we7u * README.1ST: Fixed minor spelling errors. 2002-03-14 20:58 rzg * README.1ST, help/help-English.dat: Updated helpfile and README.1ST. 2002-03-13 09:22 we7u * scripts/mapfgd.pl: Fixes by Derrick J. Brashear for "k" format maps. 2002-03-12 09:00 we7u * src/maps.c: Fixing some segfaults that can occur in the geoTIFF code if certain TIFF tags aren't present in the image. Thanks to Derrick J. Brashear for pointing this out. I used his patch with modifications. 2002-03-11 15:36 we7u * config/: tnc-startup.kam, tnc-startup.kpc3, tnc-startup.sys: Changed "mfilter off" to "filter off" for kam and kpc3. Added "filter off" to tnc-startup.sys as well. Both mfilter and filter are in that file, making it work for both types of TNC's. 2002-03-11 12:53 we7u * src/lang.c: Added a bit of bulletproofing for lang.c. 2002-03-11 10:49 we7u * config/: Makefile.am, Makefile.in, tnc-startup.aea: Added tnc-startup.aea file and tweaked Makefiles to install it. 2002-03-11 10:06 we7u * config/: tnc-startup.kam, tnc-startup.kpc3, tnc-startup.sys: Adding "mfilter off" to most tnc startup files. 2002-03-11 01:17 we7u * src/interface.c: Increased inter-character delay to 25ms. PicoPacket doesn't work with 20ms. This is only for writes on serial port TNC's. 2002-03-11 00:06 we7u * config/tnc-startup.pico: Fullduplex not recognized by my PicoPacket. Fulldup is. 2002-03-10 23:39 we7u * src/interface.c: Moved character write pacing to the proper routine. 2002-03-10 23:01 we7u * src/: interface.c, main.c, main.h: Setuid patches by Jack Twilley. Serial port throttling by we7u. 2002-03-08 14:48 we7u * src/interface_gui.c: Fix for Xastir blowing up when changing properties on a serial TNC interface. 2002-03-07 15:33 we7u * config/Makefile.in: Adding PicoPacket startup file. 2002-03-07 15:31 we7u * Makefile.in: Adding backslash back in at the appropriate point. 2002-03-07 15:30 we7u * acconfig.h, config.h.in, configure: Fixes for warning when running autoheader. 2002-03-07 15:03 we7u * config/tnc-startup.pico: A few more tweaks to the picopacket startup file. 2002-03-07 12:58 we7u * src/gps.c: Changed a few variables to globals. This is to allow two different GPS sentences to update the current info, then perform a screen update using the combined data. Fixed the code so that receipt of one valid GPS sentence doesn't disable decoding of the next. 2002-03-07 12:49 we7u * config/tnc-startup.pico: Swapped the order of the GPS string captures. 2002-03-07 12:49 we7u * src/interface.c: Added some debugging statements. 2002-03-07 10:56 we7u * config/tnc-startup.pico: Proper commands for a Pico. Tested. 2002-03-07 10:55 we7u * src/interface.c: Added a delay after sending each init string to a serial TNC. This is needed to allow the TNC enough time to process the command before sending the next. 2002-03-07 08:58 we7u * Makefile.am: Adding a backslash that was erroneously deleted from Makefile.am. Thanks to Jack Twilley for pointing this out. 2002-03-06 17:02 we7u * config/: Makefile.am, tnc-startup.pico: Added a startup file for a Paccomm PicoPacket. 2002-03-06 15:58 we7u * src/gps.c: Setting the time from GPS data now requires only that a $GPRMC string be received, the OS be Linux, and that the Xastir binary must be SUID root. It no longer requires the $GPGGA sentence to set the time. 2002-03-06 13:57 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Changed 20 & 10 second GPS update rates down to 15 & 5. 2002-03-06 13:13 we7u * src/db.c: Added station trails for the local station. Improved station/trail update rate for Track-Me mode. 2002-03-06 11:48 we7u * src/db.c: Added the capability to track ourselves. Uses the Track Station facility, so the map moves when we get too near the edge of the viewport. 2002-03-06 10:11 we7u * src/interface_gui.c: Added a missing mutex unlock that was preventing getting to the properties dialog for the new interface type. 2002-03-06 01:52 we7u * src/gps.c: Blanking out fields for which we don't have actual data values. 2002-03-06 01:44 we7u * src/interface.c: Added else clause s.t. it changes the type to "aprs data" if the nmea tests fail. 2002-03-06 01:29 we7u * src/interface.c: A few small tweaks to tnc_get_data_type(). Wasn't detecting NMEA data properly. 2002-03-06 01:17 we7u * src/gps.c: Updating local position after decoding each GPRMC or GPGGA string. 2002-03-06 01:03 we7u * src/gps.c: Now updates local position when either $GPRMC or $GPGGA are received. Both are not required except for setting time. Added #ifdef __linux__ around the settime call. 2002-03-06 00:30 we7u * src/interface.c: Modified tnc_get_data_type() function so that it doesn't call the decode_ax25_line() function. The latter function is destructive to its first parameter, which is the APRS packet. It was causing the packet to be destroyed before it could be parsed and added to the database. 2002-03-06 00:27 we7u * src/db.c: Corrected spelling error in debug output. 2002-03-06 00:25 we7u * src/main.c: Added a couple of comments. 2002-03-05 23:53 we7u * src/interface_gui.c: Added "Set Time" button to two more GPS interfaces. Took it away from the "Serial TNC" interface. 2002-03-05 22:42 we7u * src/main.c: Widening the debug_level form to handle up to debug level 2047. 2002-03-05 13:28 we7u * AUTHORS, ChangeLog, DEBUG_LEVELS, Makefile.am, README.1ST, acinclude.m4, config.guess, config.sub, configure.in, install-sh, missing, mkinstalldirs, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, scripts/icontable.pl, scripts/mapblast2geo.pl, scripts/mapfgd.pl, src/datum.c, src/datum.h, src/db.c, src/draw_symbols.c, src/festival.c, src/gps.c, src/interface.c, src/interface.h, src/interface_gui.c, src/list_gui.c, src/main.c, src/maps.c, src/messages.c, src/rotated.c, src/rotated.h, src/snprintf.c, src/snprintf.h, src/util.c, src/xa_config.c: Expanded tabs. 2002-03-05 00:18 we7u * src/: db.c, db.h, gps.c, igate.c, interface.c, interface.h, interface_gui.c, lang.c, main.c, maps.c, util.c, xa_config.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. Added new interface type "Serial TNC w/GPS on AUX port", which is for Kantronics KAM, KPC3+, and Paccomm PicoPacket TNC's that respond to -E for fetching GPS strings. Added new DEBUG_LEVELS file that describes the new standard levels. Added more debug statements througout the code. Added comments for GPGGA sentence. Added "dbadd" parameter to decode_ax25_line, if it's set on return, add the data to the database. Filter "cmd:" out of incoming data. Decode time/data from GPRMC and GPGGA strings, used to set system time to GPS time. Altitude units now decoded from GPGGA strings. Changed hard-coded device numbers to ennumerated values. New black background choice. Added "char *envp[]" to parameters for main. Still needed: Set time fixes for other operating systems. Smooth time transition instead of force to new value. "Set Time" button for remaining two GPS interface types. 2002-03-04 13:41 we7u * DEBUG_LEVELS: Added by Owen DeLong : Changing to bit-mapped debug levels. This file documents what each level is for. 2002-03-04 13:36 we7u * src/: track_gui.c, wx.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. 2002-03-04 13:33 we7u * src/: alert.c, hostname.c, maps.c, messages.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. 2002-03-04 13:20 we7u * symbols/symbols.dat: Changes by Owen DeLong , KB6MER to support: New interface type. 2002-03-04 13:19 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Changes by Owen DeLong , KB6MER to support: New interface type, setting time via GPS, new Black map background color, more debugging messages. 2002-02-25 16:10 we7u * README.1ST: Minor tweaks to again test mailing list notification. 2002-02-25 16:06 we7u * README.1ST: Minor tweaks to test new mailing list. 2002-02-25 14:29 we7u * README.1ST: Added a blurb about the "--prefix" config option. 2002-02-25 12:43 francais1 * config.h.in, configure, configure.in, src/xa_config.h, src/xa_config.c: Changes to allow the use of --prefix with configure. By default should install and run from /usr/local/xastir as before. 2002-02-25 01:22 we7u * src/interface.c: Added a couple of debug messages. Fixed the AX.25 reconnect problem. Decreased several fixed waits. 2002-02-22 23:41 we7u * src/db.c: Added more debug output in decode_Mic_E function. One statement will print out even without debug mode if the symbol table and symbol characters are switched. 2002-02-19 16:28 rzg * help/help-English.dat: Updated helpfile. 2002-02-16 23:52 we7u * src/main.c: Changed "Measure" function to go to feet or meters if the total length is less than a mile or kilometer. 2002-02-16 21:21 we7u * src/util.c: FreeBSD time fix by Jack Twilley . 2002-02-15 21:51 we7u * src/main.c: Fixing the main window (actually the main popup!) so that it initially shows at the correct size, instead of resizing shortly after. 2002-02-15 15:55 we7u * src/maps.c: Fixed Shapefile maps so that they work with more shapefiles. Unknown shapes are drawn in black just like the roads. Lakes shapefiles have to start with "lk" in the filename now to be recognized and drawn as blue lakes. 2002-02-15 12:49 we7u * src/main.c: Reordering the management of the appshell popup in an attempt to get rid of the bug: "Shell widget has zero width or height" that occurs on some systems. 2002-02-14 14:37 we7u * src/xa_config.c: Changing default greying out of stations from 120 minutes down to 80 minutes. This works better for some of the satellites we can use for APRS, per Bob Bruninga's recommendations. 2002-02-14 09:33 we7u * src/: db.c, main.c, main.h, util.c, util.h, xa_config.c: Tracked station speech patches contributed by Alan Crosswell , n2ygk. 2002-02-14 09:08 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Tracked station speech patches contributed by Alan Crosswell , n2ygk. 2002-02-13 12:55 we7u * src/maps.c: Tiger map tweaks submitted by Jim Chandler, N0VH. 2002-02-13 11:14 we7u * src/wx.c: Added a comment at the top describing the weather stations we currently support. 2002-02-13 10:40 we7u * config.guess, config.sub, missing: Checking in latest versions of these files, snagged from: http://subversions.gnu.org/cgi-bin/cvsweb/autoconf/config/ 2002-02-13 09:36 we7u * configure, configure.in: Bumping the development version up to version 1.1.1 2002-02-13 08:44 we7u * missing, config.sub: Updated file sent to me by Jack Twilley . 2002-02-11 17:27 dk7in * scripts/: mapblast2geo.pl, update_langfile.pl: Old E-Mail deleted. 2002-02-11 16:08 dk7in * scripts/icontable.pl: Old E-Mail address deleted. 2002-02-11 15:21 we7u * scripts/mapfgd.pl: New script by Derrick J Brashear, KB3EGH. This one creates .fgd files from geotiff .tif files. Useful for topo maps you find on the net that don't come with .fgd files. 2002-02-11 14:22 we7u * src/maps.c: A tweak by Derrick J Brashear, KB3EGH, which avoids problems with user defined horizontal datums in geoTIFF. 2002-02-10 12:04 kg4ijb * Makefile.am: didn't get committed :/ 2002-02-10 01:06 we7u * callpass/Makefile: Removing Makefile. This is created automatically during the "configure" stage. 2002-02-09 16:56 kg4ijb * Makefile.in, configure, configure.in, callpass/Makefile, callpass/Makefile.am, callpass/Makefile.in, callpass/callpass.c, m4/Makefile.in: Moved callpass* to ./callpass. Automake doesn't handle recursives very well 2002-02-09 06:48 kg4ijb * config.h.in, configure, configure.in, m4/Makefile.in: Added config check for Xpm (hack) untill I can do something better. 2002-02-09 06:14 kg4ijb * configure, configure.in, m4/Makefile.in: updated release information 2002-02-07 20:45 kg4ijb * m4/Makefile.in: rebuilds 2002-02-06 16:58 we7u * Makefile.am: Added a forgotten root-level Makefile.am file. 2002-02-05 16:59 we7u * help/: help-English.dat, help-Dutch.dat, help-French.dat, help-German.dat, help-Italian.dat, help-Spanish.dat: Updated web page pointers. 2002-02-05 16:57 we7u * AUTHORS, FAQ, README, README.1ST: Updated web page pointers and CVS instructions. 2002-02-05 16:22 we7u * AUTHORS, FAQ, README, README.1ST: Tweaking web page addresses for the new sourceforge project address. 2002-02-04 21:00 we7u * src/lclint.script: Added more debug statements. Added new files to it. 2002-02-04 20:58 we7u * src/maps.c: Changed the ifdef's around that check for ImageMagick and XPM libraries. The proper pieces of code should be enabled/disabled now for whichever of these two libraries are found on the system. 2002-02-04 20:55 we7u * src/main.h: Undef'ing VERSION only when lclint is being run against the code. 2002-02-04 20:54 we7u * src/main.c: Added some debug statements. 2002-02-01 19:18 kg4ijb * src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/snprintf.h, src/snprintf.c, symbols/Makefile.am, symbols/Makefile.in, symbols/symbols.dat: Initial revision 2002-02-01 19:18 kg4ijb * src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/snprintf.h, src/snprintf.c, symbols/Makefile.am, symbols/Makefile.in, symbols/symbols.dat: rc1 intital import 2002-02-01 19:15 kg4ijb * ABOUT-NLS, AUTHORS, COPYING, ChangeLog, FAQ, INSTALL, LICENSE, Makefile.in, NEWS, README, README.1ST, TODO, UPDATES, acconfig.h, acinclude.m4, changes.txt, config.guess, config.h.in, config.sub, configure, configure.in, install-sh, missing, mkinstalldirs, placeholder, stamp-h.in, xastir.spec.in, ltconfig, ltmain.sh, config/Makefile.am, config/Makefile.in, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, config/xastir.rgb, help/Makefile.am, help/Makefile.in, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, intl/Makefile.in, intl/VERSION, intl/bindtextdom.c, intl/cat-compat.c, intl/dcgettext.c, intl/dgettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/gettext.h, intl/gettextP.h, intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c, intl/libgettext.h, intl/libintl.h, intl/linux-msg.sed, intl/loadinfo.h, intl/loadmsgcat.c, intl/localealias.c, intl/po2tbl.sed, intl/po2tbl.sed.in, intl/textdomain.c, intl/xopen-msg.sed, m4/Makefile.am, m4/Makefile.in, m4/xmhtml.m4, po/Makefile.in, po/Makefile.in.in, po/POTFILES, po/POTFILES.in, po/cat-id-tbl.c, po/en.po, po/fr.po, po/nl.po, po/stamp-cat-id, po/xastir.pot, scripts/example_objects.log, scripts/icontable.pl, scripts/inf2geo.pl, scripts/mapblast2geo.pl, scripts/update_langfile.pl, src/Makefile.am, src/Makefile.in, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/datum.c, src/datum.h, src/db.c, src/db.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/lclint.script: Initial revision 2002-02-01 19:15 kg4ijb * ABOUT-NLS, AUTHORS, COPYING, ChangeLog, FAQ, INSTALL, LICENSE, Makefile.in, NEWS, README, README.1ST, TODO, UPDATES, acconfig.h, acinclude.m4, changes.txt, config.guess, config.h.in, config.sub, configure, configure.in, install-sh, missing, mkinstalldirs, placeholder, stamp-h.in, xastir.spec.in, ltconfig, ltmain.sh, config/Makefile.am, config/Makefile.in, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, config/xastir.rgb, help/Makefile.am, help/Makefile.in, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, intl/Makefile.in, intl/VERSION, intl/bindtextdom.c, intl/cat-compat.c, intl/dcgettext.c, intl/dgettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/gettext.h, intl/gettextP.h, intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c, intl/libgettext.h, intl/libintl.h, intl/linux-msg.sed, intl/loadinfo.h, intl/loadmsgcat.c, intl/localealias.c, intl/po2tbl.sed, intl/po2tbl.sed.in, intl/textdomain.c, intl/xopen-msg.sed, m4/Makefile.am, m4/Makefile.in, m4/xmhtml.m4, po/Makefile.in, po/Makefile.in.in, po/POTFILES, po/POTFILES.in, po/cat-id-tbl.c, po/en.po, po/fr.po, po/nl.po, po/stamp-cat-id, po/xastir.pot, scripts/example_objects.log, scripts/icontable.pl, scripts/inf2geo.pl, scripts/mapblast2geo.pl, scripts/update_langfile.pl, src/Makefile.am, src/Makefile.in, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/datum.c, src/datum.h, src/db.c, src/db.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/lclint.script: rc1 intital import Xastir-Release-2.2.2/DEBUG_LEVELS000066400000000000000000000100151501463444000161660ustar00rootroot00000000000000 This file has three parts. The first part describes the new structure for debug levels. The second part describes the debug_level definitions that were in the old code and which files they were in. The third part describes how to use use debugging at run time. The debug level structure was modified in February of 2002 by KB6MER. Questions/comments/flames can be sent to kb6mer@arrl.net Here's how things are after KB6MER tweaked it all... New Scheme: ----------- 1 General basic debugging (any system) 2 Messages, WX, Objects, and Items, Port Data Flow 4 X Object Debugging 8 X Window Object Debugging 16 Map Debugging (maps.c) 32 Language Debugging (maps.c) 64 Database Object Debugging 128 GPS Interface Detailed debugging 256 station and trail display detailed debugging 512 Map import/export function debugging 1024 Internet Transaction debugging 2048 ALOHA radius and Multipoint object debugging. 4096 Levels 4096 and above will require modification to the main.c:Change_debug_level_change_data() function to change the bounds checking, and are available for future use. ------------------------------------------------------------------ Old Scheme: ----------- Places where debug level is referenced in old code, and the levels referenced (if debug_level xx), where xx is >0, &1, etc. alert.c >0 bulletin_gui.c &1 db.c >=2 &1 &128 &32 &256 () gps.c &128 hostname.c &256 igate.c &2 interface.c &128 &2 &1 interface_gui.c &128 lang.c &32 main.c &4 <0/>255(need to change limits) &8 &128 &1 &15 maps.c &16 &2 >=2 &4 &1 &8 messages.c >1 &1 >5 messages_gui.c &2 track_gui.c >=2 util.c &1 wx.c >2 &1 xa_config.c &1 &2 ------------------------------------------------------------------ How to Use the Debug Levels Xastir debugging is turned on at run time by using the "-v" command line option and/or the File -> Configure -> Change Debug Level pull-down. As laid out above, in the source code, debugging output is turned on by a bitwise "and" (&) of the currently set DEBUG_LEVEL against a number appropriate to the module currently being executed. For example, in the "maps.c" the following lines appear: if ( debug_level & 512 ) fprintf(stderr,"Creating %s\n", xpm_filename ); The highest debug level for Xastir is 4095, and debug levels are additive. If you want to have "general basic debugging" and "GPS interface Detail" and "Map Debugging" you'd use: 1 + 128 + 512 = 641 xastir -v 641 Debug information typically is sent to "standard error" - which is normally File Descriptor #2 in Unix parlance. Using common Unix shells, such as Bash, you can "redirect" the output to be intermingled with the "standard output" (file descriptor #1). This allows you to get all of the normal output, plus all of the debug output in one stream, which can be "piped" to another command, such as grep. This can used to search for specific items in the debug output. For example, to check debug information to see whether or not map caching is working, you can turn on debug level 512, redirect stderr to stdout and the grep for map cache specific output: xastir -v 512 2>&1 |grep map_cache Another little trick, to be used when you're running programs that call other programs, or scripts that call other scripts/programs: (xastir -v 512 2>&1) | grep map_cache The parenthesis cause that portion to be run in a sub-shell, and then that sub-shell's STDERR is piped to STDOUT by the "2>&1" portion, so you get ANYTHING that went to STDERR or STDOUT from that command or anything that it calls. This is how you can get a "make" command to spit everything into one file. Of course you can also do: (xastir -v 512 2>&1) | tee xastir.log Which will pipe everything to your screen and to the xastir.log file. You could then type "tail -f xastir.log | grep map_cache" in another window and watch that subset of the error messages there. That way you won't miss anything. ------------------------------------------------------------------ Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/Davis/000077500000000000000000000000001501463444000154145ustar00rootroot00000000000000Xastir-Release-2.2.2/Davis/.vimrc000066400000000000000000000014331501463444000165360ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/Davis/AUTHORS000066400000000000000000000013401501463444000164620ustar00rootroot00000000000000 Developers and Contributions _________________________________________________________________ First, thanks go out to the great folks at the xastir team - a wonderful APRS application set and helpful folks! Thanks also to Andreas Muller, author of meteo and a great resource for information and help. Elements of this software are taken from wx200d ver 1.2 by Tim Witham, and it is modeled after that application. Finally, thanks to the MySQL folks for the key element - the database. KB8ROP Bruce Bennett bruts@adelphia.net _________________________________________________________________ Copyright (C) 2003-2004 Bruce Bennett KB8ROP Xastir-Release-2.2.2/Davis/COPYING000066400000000000000000000431271501463444000164560ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Xastir-Release-2.2.2/Davis/ChangeLog000066400000000000000000000000021501463444000171560ustar00rootroot00000000000000 Xastir-Release-2.2.2/Davis/INSTALL000066400000000000000000000220321501463444000164440ustar00rootroot00000000000000 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. Xastir-Release-2.2.2/Davis/Makefile.am000066400000000000000000000010621501463444000174470ustar00rootroot00000000000000 # # Copyright (C) 2000-2023 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src #if DAVIS #MyWX = davis #else #MyWX = #endif #noinst_PROGRAMS = $(MyWX) # DISTCLEANFILES = EXTRA_DIST = aclocal.m4 AUTHORS bootstrap.sh ChangeLog config.h.in \ config.status configure.ac COPYING INSTALL NEWS \ README bootstrap.sh MAINTAINERCLEANFILES = configure config.status aclocal.m4 \ Makefile.in Makefile config.guess config.sub install-sh \ missing ChangeLog:: Xastir-Release-2.2.2/Davis/NEWS000066400000000000000000000000011501463444000161020ustar00rootroot00000000000000 Xastir-Release-2.2.2/Davis/README000066400000000000000000000163451501463444000163050ustar00rootroot00000000000000 Copyright (C) 2004 Bruce Bennett Portions Copyright (C) 2000-2023 The Xastir Group (Modified for the Xastir project under GPL license) Davis Weather Station support for Xastir - db2APRS OVERVIEW -------- This is a bridge utility between "meteo", a Davis Weather Station data storage & display application by Andreas Muller (see http://meteo.othello.ch) and "Xastir", the APRS package for Linux (see http://www.xastir.org). It allows your Davis weather data to be used by Xastir for local station data. You will need to obtain and install Xastir, mysql and meteo as outlined in the following sections. After Xastir and meteo are in working order, this utility can be run as a daemon to provide weather data to Xastir (or any other APRS-format application). "db2APRS" watches for new weather data in the database, retrieves the new data, formats it in APRS "position less" ASCII format and makes it available on a TCP port of your choosing. Xastir is capable of reading this data (see note under Xastir installation). INSTALLATION ------------ Steps in order: 1) Install mysql - initial tested version mysql-3.23.58 although version 4 is released and has some significant improvements - and version 4 *should* work (to be tested yet). If you use an RPM or DPK binary-image version, be sure to add the mysql-devel headers. For the latest image-version, see http://www.mysql.com and follow the links to the downloads. I used mysql-3.23.58-pc-linux-i686.tar.gz from that site. 2) Install meteo - tested versions meteo-0.9.4 and meteo-0.9.8 Version 0.9.9 is available and based on the change documented will work. See the instructions for installing & then setting up meteo that come with the tar ball. Obtain the latest meteo at http://meteo.othello.ch - the setup is rather involved but worth the efort. Some SQL/XML skills can help here, but are not absolutely required... 3) Install or update your installation for Xastir to the latest version ("http://github.com/Xastir/Xastir" project Xastir) 4) Install db2APRS - version 0.1.2 See instructions below. SETTINGS & STARTUP ------------------ 1) mysql - it is recommended by mysql to set up passwords, but for this usage it doesn't matter. In fact, it's a bit of a pain. TODO - db2APRS has the annoying fault of clearly displaying the password used for the mysql database for anyone to see via 'ps -ef'. Start mysqld before db2APRS, meteo and Xastir in your boot-time initializations. 2) meteo - my testing used a one minute data accumulation rate. Thirty seconds would more closely match Xastir, but the database growth rate would be twice as fast (about 600 Mbytes/year at 30 sec rate). Set your desired rate using the meteopoll command line options. I run the full meteopoll package with averaging, graphs and meteodequeue - but the only *required* element is meteopoll. Start the meteopoll daemon after mysqld is up. (meteodequeue is recommended - see the doc's that come with meteo and man pages). 3) db2APRS - see "db2APRS RUN OPTIONS" below. Start this daemon after mysqld and before Xastir. When meteopoll isn't running, you will get old weather data, time stamped by Xastir as new data. 4) xastir - start this last, if you are auto-opening the WX port. Set the weather port as a network weather station on "localhost", port number as chosen in "db2APRS RUN OPTIONS" (default is 1313). Make sure your station is set to one of the "w/weather data" and your Icon is set to a weather Icon. db2APRS RUN OPTIONS ------------------- The db2APRS utility takes standard short & long command line options, which can be displayed by "db2APRS -?". Here's the list: -h --help Show help info and exit. -v --verbose Useful with the -n switch, for trouble-shooting, not for normal operation. Tells you more than you really wanted to know, but I recommend that you use this switch while you try to initially set up db2APRS. -c --cport [port#] Choose which TCP/IP port data comes out from. If not used, port number 1313 is the default. HINT: "telnet localhost [port#]" is a handy way to verify db2APRS operation. -s --sensor [sensor group#] Indicate what group of sensors are the outdoor ones. If not supplied, sensor number 1 is the default. HINT: Tables "station" and "sensor" in the meteo database control what your "sensor" (which means sensor group) definitions are for your "station". -u --user [database user] Username for mysql database connection. If unspecfied defaults to "meteo" (which is per the meteo setup intended to be a read-only account for meteo). -p --password [db passwd] Password for mysql connection. If unspecfied, no password is supplied. NOTE: this password is unfortunately visible to anyone on your system running 'ps -ef'. TO BE FIXED. -b --database [database] Database name for mysql connection. If not supplied the default is "meteo". -n --nodaemon Run in the fore-ground as a program. Useful for debugging or initial setup, when used with -v. -r --repeat Keep going till killed - if not specified, one pass is performed and then db2APRS exits. The only case where this switch is *not* used is during initial setup/debug. Typical example: "./db2APRS -r -u meteo -p meteo" for normal use or "./db2APRS -r -n -v -u test -p password" for debugging. OPERATIONAL DETAILS ------------------- db2APRS connects to the specified mysql database, extracts the latest timestamp and compares it to the last timestamp it read. If newer, the outdoor weather data (extception: air pressure is taken as indoor=outdoor) bearing this timestamp is extracted and formatted in the APRS "position less" string format with a Davis and X-APRS tag on the end. Any connecting client is given this string at 25 second intervals, after new database entries are checked for. This daemon could run on any networked Linux machine instead of the machine hosting Xastir, if desired (it's a good way around lack of processing power, disk space or serial ports!). Note that the db2APRS daemon keeps providing data to Xastir even when no new entries in the database have been made. This could lead to errors in the timestamp on the data that Xastir is transmitting. BUILD db2APRS ------------- It's the usual: $ cd xastir/Davis $ ./bootstrap.sh $ ./configure $ make $ su -c 'make install' ACKNOWLEDGEMENTS & AUTHORS -------------------------- db2APRS is the product of Bruce Bennett, callsign KB8ROP It is freely available at no charge under the GNU GENERAL PUBLIC LICENSE (see "COPYING" document) NO WARRANTY, expressed or implied, use at your own risk. Please feel free to contact me with test results & comments at the above EMAIL address Code portions and style taken from wx200d by Tim Witham , et. al. meteo is the work of Andreas Muller , et. al. mysql is the product of MySQL - see http://www.mysql.com for team details. and finally, Xastir is the brain child of Frank Giannandrea et. al. (see http://www.xastir.org for current EMAIL addresses) Xastir-Release-2.2.2/Davis/bootstrap.sh000077500000000000000000000010011501463444000177600ustar00rootroot00000000000000#!/bin/sh -e # # # Copyright (C) 2000-2023 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.2/Davis/configure.ac000077500000000000000000000037641501463444000177170ustar00rootroot00000000000000# # Copyright (C) 2004 Bruce Bennett # Portions Copyright (C) 2000-2023 The Xastir Group # (Modified for the Xastir project under GPL license) # # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) AC_INIT(db2APRS, 0.2.0, bruts@adelphia.net) AM_INIT_AUTOMAKE(db2APRS, 0.2.0) AC_CONFIG_SRCDIR([src/db2APRS.c]) AM_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_INSTALL AC_PROG_CC # Checks for libraries. # Use MySQL's script for library config, if available MYSQL_CONFIG=mysql_config AC_MSG_CHECKING(for a fully installed MySQL) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then MYSQL_VERSION=`${MYSQL_CONFIG} --version` MYSQL_LIBS=`${MYSQL_CONFIG} --libs` LIBS=`${MYSQL_CONFIG} --libs` MYSQL_CFLAGS=`${MYSQL_CONFIG} --cflags` CFLAGS="$CFLAGS $MYSQL_CFLAGS" AC_SUBST(MYSQL_LIBS) AC_SUBST(MYSQL_CFLAGS) AC_MSG_RESULT(...found ${MYSQL_VERSION}) else AC_MSG_RESULT(MySQL is not fully installed) AC_MSG_CHECKING(if there at least are the needed MySQL client libs) AC_CHECK_LIB(mysqlclient,mysql_close) if test $ac_cv_lib_mysqlclient_mysql_close = no; then AC_MSG_ERROR(*** No MySQL client library found - See README ***) else AC_MSG_RESULT(found a usable libmysqlclient) fi fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then AC_MSG_RESULT(mysql.h path defined in CFLAGS) else AC_CHECK_HEADERS([mysql.h],MYSQL_INC="yes",AC_MSG_ERROR(*** MySQL include file mysql.h not found - See README ***)) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME # Checks for library functions. AC_FUNC_FORK AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_STRTOD AC_CHECK_FUNCS([memset select socket strrchr strtol]) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT Xastir-Release-2.2.2/Davis/src/000077500000000000000000000000001501463444000162035ustar00rootroot00000000000000Xastir-Release-2.2.2/Davis/src/.vimrc000066400000000000000000000014331501463444000173250ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/Davis/src/Makefile.am000066400000000000000000000003011501463444000202310ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # bin_PROGRAMS = db2APRS noinst_PROGRAMS = db2APRS_SOURCES = \ db2APRS.c defs.h db2APRS_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.2/Davis/src/db2APRS.c000066400000000000000000001113241501463444000175060ustar00rootroot00000000000000/****************************************************************** * * * Copyright (C) 2004 Bruce Bennett * Portions Copyright (C) 2000-2023 The Xastir Group * * (see the files README and COPYING for more details) * * This file implements all of the database to APRS daemon. * * Davis/Data Base Weather --> APRS Weather Intended use: Create & provide APRS style packet string without position information from MySQL database weather information stored there by meteo-0.9.4 (See http://meteo.othello.ch for source) to xastir-1.2.1 (See http://www.xastir.org for source) Note: "meteo-0.9.x" is a weather data accumulator aimed at Davis weather stations, which stores weather data in a mysql database. It is configured in two places, an XML file (default name meteo.xml) and in the database named in the XML file (default database name is "meteo") Output is to the ip hostname:port required in the command line. ACKNOWLEDGEMENTS: Elements of this software are taken from wx200d ver 1.2 by Tim Witham , and it is modeled after that application. *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXARGS 20 /* maximum CGI args to parse */ #define TMPLEN 128 /* max length of CGI */ #define BUFLEN 32 /* max length of hostname:port */ #define POLL_INTERVAL 90 // default polling interval #define VALID_WINDDIR 0x001 #define VALID_WINDSPD 0x002 #define VALID_WINDGST 0x004 #define VALID_TEMP 0x008 #define VALID_RAIN 0x010 #define VALID_RAIN24H 0x020 #define VALID_HUMIDITY 0x040 #define VALID_AIRPRESS 0x080 #define VALID_RAINDAY 0x100 #define MTPS2MPH 2.2369 #define DEGC2DEGF 1.8 #define MM2IN100TH 3.937 #define INHG2HPA10TH 338.638 #define OUTDOOR_SENSOR 1 //---From the static table "mfield", which really should be dynamically read here--- // (but then I couldn't use a switch statement) #define TEMPERATURE 0 #define TEMPERATURE_MIN 1 #define TEMPERATURE_MAX 2 #define HUMIDITY 10 #define HUMIDITY_MIN 11 #define HUMIDITY_MAX 12 #define WETNESS 20 #define WETNESS_MIN 21 #define WETNESS_MAX 22 #define AIR_PRESSURE 30 #define AIR_PRESSURE_MIN 31 #define AIR_PRESSURE_MAX 32 #define SOLAR 40 #define UV 41 #define RAIN 50 // note: "51" is really rain total #define RAIN_PER_DAY 51 #define RAIN_PER_HOUR 52 #define WIND_SPEED 60 #define WIND_DIRECTION 61 #define WIND_GUST 62 #define WIND_X 63 #define WIND_Y 64 #define MOISTURE 70 #define WATERLEVEL 71 #define WATERLEVEL_MIN 72 #define WATERLEVEL_MAX 73 #define BATTERY 110 #define TRANSMITTER 111 #define DURATION 120 #define SAMPLES 121 struct dbinfo { char user[30]; char pswrd[15]; char name[30]; } db; char *progname; char *query; int *current = 0; int opt; MYSQL mysql; // Yeah, globals... MYSQL_RES *result; MYSQL_ROW row; char last_timestamp[20]; char last_datetime[20]; char death_msg[120]; int debug_level; char wxAPRShost[BUFLEN]; int wxAPRSport = PORT; int outdoor_instr = OUTDOOR_SENSOR; /****************************************************************** 1/4/2003 Usage brief *******************************************************************/ void usage(int ret) { if (query) { printf("Content-type: text/plain\nStatus: 200\n\n"); } printf("usage: %s [options] \n",progname); printf("VERSION: %s\n",VERSION); printf(" -h --help show this help and exit\n"); printf(" -v --verbose debugging info --> stderr\n"); printf(" -c --cport [port#] IP port for data output\n"); printf(" -s --sensor [sensor group#] from meteo, your OUTDOOR sensor set\n"); printf(" -u --user [database user] username for mysql - default meteo\n"); printf(" -p --password [db passwd] password for mysql - default none\n"); printf(" -b --database [database] database name - default meteo\n"); printf(" -n --nodaemon do not run as daemon\n"); printf(" -r --repeat keep running\n"); printf(" -i --interval [seconds] polling interval\n"); printf(" -m --metric data base is in metric units\n"); printf("options may be uniquely abbreviated; units are as defined in APRS\n"); printf("Specification 1.0.1 for positionless weather data (English/hPa).\n"); exit(ret); } /****************************************************************** 1/2/2003 Make an APRS string out of WX data *******************************************************************/ int APRS_str(char *APRS_buf, char *datetime, double winddir, double windspeed, double windgust, double temp, double rain1hr, double rain24hr, double rainday, double humidity, double airpressure, unsigned int valid_data_flgs, int Metric_Data) { int intval; char pbuf[10]; if (APRS_buf == NULL) { if (debug_level & 1) { fprintf(stderr,"err: Null string buffer for APRS string.\n"); } return -1; // Ooo!! *****Nasty Bad Exit Point Here**** } //timestamp first sprintf(APRS_buf, "_%s",datetime); // if (valid_data_flgs & VALID_WINDDIR) { intval = (winddir + 0.5); // rounding to whole degrees if (intval > 360) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction > 360\n"); } sprintf(APRS_buf, "c..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction negative\n"); } sprintf(APRS_buf, "c..."); } else { sprintf(pbuf, "c%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind direction flagged as invalid\n"); } sprintf(pbuf, "c..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDSPD) { if (Metric_Data) { intval = (windspeed*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windspeed + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind speed > 600 MPH\n"); } sprintf(pbuf, "s..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "s..."); } else { sprintf(pbuf, "s%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "s..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDGST) { if (Metric_Data) { intval = (windgust*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windgust + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind gust > 600 MPH\n"); } sprintf(pbuf, "g..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "g..."); } else { sprintf(pbuf, "g%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "g..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_TEMP) { if (Metric_Data) { intval = ((temp)*DEGC2DEGF + 0.5)+32; // converting & rounding to whole Deg F } else { intval = (temp + 0.5); // rounding to whole Deg F } if (intval > 200) // Let's be reasonable here - boiling? { if (debug_level & 1) { fprintf(stderr,"err: Temperature > 200 Deg F\n"); } sprintf(pbuf, "t..."); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Temperature < -99 Deg F\n"); } sprintf(pbuf, "t..."); } else { if (intval < 0) { sprintf(pbuf,"t%0.2d",intval); } else { sprintf(pbuf, "t%0.3d", intval); } } } else { if (debug_level & 1) { fprintf(stderr,"info: Temperature flagged as invalid\n"); } sprintf(pbuf, "t..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN) { if (Metric_Data) { intval = ((rain1hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain1hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // 10 in/hr? Garden Hose -> rain gauge? { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr > 9.99 inch\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "r%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN24H) { if (Metric_Data) { intval = ((rain24hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain24hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain in 24 hours { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/24Hr > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "p999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "p%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/24Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAINDAY) { if (Metric_Data) { intval = ((rainday)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rainday*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain per day { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/day > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "P999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/day negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "P%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/day flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_HUMIDITY) { intval = (humidity + 0.5); // rounding to whole percent if (intval > 100) // Unlike the space shuttle engines, 100 % is max { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported > 100%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 1) { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported < 1%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { if (intval == 100) // Report 100% as 'h00' { intval = 0; } sprintf(pbuf, "h%0.2d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Humidity flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_AIRPRESS) { if (Metric_Data) { intval = (airpressure*10.0 + 0.5); // rounding to whole tenth of a hPa } else { intval = (airpressure*INHG2HPA10TH + 0.5); // convering In-Hg to 1/10 hPa and rounding } if (intval > 20000) //two atmospheres - about 29 PSIA { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported > 2 Atmospheres%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported negative%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "b%0.5d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Air Pressure flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); strcat(APRS_buf,"xDvs\n"); // add X aprs and Davis WX station ID's and if (debug_level & 1) { fprintf(stderr,"\ninfo: APRS Version of WX - %s\n\n",APRS_buf); } return strlen(APRS_buf); } /****************************************************************** 1/2/2003 Get the latest set of Weather Data from the Data Base *******************************************************************/ int Get_Latest_WX( double *winddir, double *windspeed, double *windgust, double *temp, double *rain1hr, double *rain24hr, double *rainday, double *humidity, double *airpressure, unsigned int *valid_data_flgs) { long last_hour_timestamp; long int last_24_timestamp; long int last_day_timestamp; char query_buffer[240]; int nrows, row_cnt, item_count; int found_sensor; long local_offset; // could be as big as 12 hrs times 3600 seconds... // Find latest, see if it's new to us // --new to us is a simple timestamp follower, so upon startup // it will always read one set of data, assuming any exists if (mysql_query(&mysql, "SELECT MAX(timekey) from sdata")) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (mysql_num_rows(result) != 1 ) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: number of results %d\n", mysql_num_rows(result)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } row = mysql_fetch_row(result); if ( row[0] == NULL ) { sprintf(death_msg,"err: NULL result for timestamp query\n"); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } // if no new data, exit with zero status if (!strncmp(last_timestamp, row[0], 11)) { if (debug_level & 1) { fprintf(stderr,"info: No new weather data recorded - exiting: no data\n"); } // release query buffer mysql_free_result(result); return 0; } strcpy(last_timestamp, row[0]); // For next pass & following query if ( debug_level & 1) { fprintf(stdout,"Timestamp: %s\n",last_timestamp); } // release query buffer mysql_free_result(result); sprintf(query_buffer,"SELECT value,sensorid,fieldid,from_unixtime(timekey,'%%m%%d%%H%%i%%S') FROM sdata WHERE timekey = %s", last_timestamp); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((nrows=mysql_num_rows(result)) < 1 ) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: number of results %d\n",nrows); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } else { if (debug_level & 1) { fprintf(stderr,"info: Latest Weather Data query: number of types of readings %d\n",nrows); } } *valid_data_flgs = 0; item_count = 0; for (row_cnt = 0; row_cnt < nrows; row_cnt++) { row = mysql_fetch_row(result); strcpy(last_datetime,row[3]); if (atoi(row[1]) == outdoor_instr) // sensors are really groups of data { found_sensor = atoi(row[1]); if (debug_level & 1) { fprintf(stderr,"info: found an outdoor sensor: (%d) ",found_sensor); } switch (atoi(row[2])) // type of reading { case WIND_DIRECTION : *winddir = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDDIR; item_count++; if (debug_level & 1) { fprintf(stderr,"wind direction %f\n ",*winddir); } break; case WIND_SPEED : *windspeed = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDSPD; item_count++; if (debug_level & 1) { fprintf(stderr,"wind speed %f\n ",*windspeed); } break; case WIND_GUST : *windgust = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDGST; item_count++; if (debug_level & 1) { fprintf(stderr,"wind gust speed %f\n ",*windgust); } break; case TEMPERATURE : *temp = strtod(row[0],NULL); *valid_data_flgs |= VALID_TEMP; item_count++; if (debug_level & 1) { fprintf(stderr,"temperature %f\n ",*temp); } break; case HUMIDITY : *humidity = strtod(row[0],NULL); *valid_data_flgs |= VALID_HUMIDITY; item_count++; if (debug_level & 1) { fprintf(stderr,"humidity %f\n ",*humidity); } break; case AIR_PRESSURE : *airpressure = strtod(row[0],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } break; case RAIN_PER_DAY : if (debug_level & 1) { fprintf(stderr,"rain-per-day total (not used), now calculated...\n "); } break; case WIND_X : if (debug_level & 1) { fprintf(stderr,"wind x... not used \n"); } break; case WIND_Y : if (debug_level & 1) { fprintf(stderr,"wind y... not used \n"); } break; case DURATION : if (debug_level & 1) { fprintf(stderr,"duration... not used \n"); } break; case SAMPLES : if (debug_level & 1) { fprintf(stderr,"samples... not used \n"); } break; default : if (debug_level & 1) { fprintf(stderr,"unknown field %s\n",row[2]); } break; } } else // Must be indoor { if (debug_level & 1) { fprintf(stderr,"info: indoor sensor found\n"); } switch (atoi(row[2])) // type of reading { case AIR_PRESSURE : *airpressure = strtod(row[0],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } break; default : if (debug_level & 1) { fprintf(stderr,"unused field %s\n",row[2]); } break; } } } if (debug_level & 1) { fprintf(stderr,"loop ends\n"); } // release query buffer mysql_free_result(result); /* get rain figures */ /* */ /* hourly first */ last_hour_timestamp = atol(last_timestamp) - 3600; sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_hour_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain 1 hour query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain 1 hour store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rain1hr = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain last hour %f\n ",*rain1hr); } // *rain1hr = *rain1hr * 100; // AFTER metric conversion if needed *valid_data_flgs |= VALID_RAIN; item_count++; } else { *rain1hr = 0; *valid_data_flgs |= VALID_RAIN; //None, but valid if (debug_level & 1) { fprintf(stderr,"no rain recorded in last hour\n"); } } } // release query buffer mysql_free_result(result); /* Last 24 hours */ last_24_timestamp = atol(last_timestamp) - 86400; sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_24_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain 24 hour query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain 24 hour store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rain24hr = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain last 24 hours %f\n ",*rain24hr); } //*rain24hr = *rain24hr * 100; // After metric conversion, if needed item_count++; *valid_data_flgs |= VALID_RAIN24H; } else { *rain24hr = 0; *valid_data_flgs |= VALID_RAIN24H; // Zero is valid too if (debug_level & 1) { fprintf(stderr,"no rain recorded in last 24 hours\n"); } } } // release query buffer mysql_free_result(result); #define CALC_MIDNIGHT #ifdef CALC_MIDNIGHT // Timestamps are seconds since midnight Jan 1 1970, so an integer divide and multiply by // seconds in 24 hrs (86400) yields the latest midnight time stamp value. last_day_timestamp = (atol(last_timestamp) / 86400)*86400; if (debug_level & 1) { fprintf(stderr,"info: timestamp for prior midnight - %ld\n",last_day_timestamp); } // NOTE: Gcc warns that "found_sensor" could be uninitialized here. sprintf(query_buffer,"SELECT offset FROM station WHERE id = (SELECT stationid from sensor WHERE id = %d)", found_sensor); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: station time offset query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: station time offset store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { local_offset = atol(row[0]); if (debug_level & 1) { fprintf(stderr,"info: station time offset: %ld\n", local_offset); } } } mysql_free_result(result); #else /* since midnite */ /* we can get the timestamp for midnite from the avg table */ last_day_timestamp = 0; sprintf(query_buffer,"SELECT max(timekey) FROM avg WHERE fieldid = %d and intval = 86400", last_hour_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: midnite timekey query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: midnite timekey store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { last_day_timestamp = strtod(row[0],NULL); } } mysql_free_result(result); #endif if (last_day_timestamp > 0) { #ifndef CALC_MIDNIGHT last_day_timestamp += 115200; // add 8 hours for offset - this should really be queried #else last_day_timestamp -= local_offset; // From the database #endif sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_day_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain last day query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain last day store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rainday = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain since midnite %f\n ",*rainday); } // *rainday = *rainday * 100; // AFTER metric conversion, if needed. item_count++; *valid_data_flgs |= VALID_RAINDAY; } else { *rainday = 0; *valid_data_flgs |= VALID_RAINDAY; // None is valid... if (debug_level & 1) { fprintf(stderr,"no rain recorded in last 24 hours\n"); } } } // release query buffer (where used) mysql_free_result(result); } if (debug_level & 1) { fprintf(stderr,"info: success - Weather Data number of reading types %d\n",item_count); } return item_count; } /****************************************************************** 1/5/2003 SIGPIPE signal handler *******************************************************************/ void pipe_handler(int sig) /* */ { signal(SIGPIPE, SIG_IGN); if (sig == SIGPIPE) // client went bye-bye { shutdown(*current, 2); close(*current); *current = -1; if (debug_level & 1) { fprintf(stderr, "info: %s - TCP client timed out", progname); } } } /****************************************************************** 1/5/2003 SIGTERM signal handler *******************************************************************/ void term_handler( int UNUSED(sig) ) { if (debug_level & 1) { fprintf(stderr, "info: %s - ordered to DIE, complying", progname); } // release query buffer & close connection mysql_free_result(result); mysql_close(&mysql); exit( 0 ); } /****************************************************************** 1/2/2003 Coordinating MAIN point *******************************************************************/ int main(int argc, char **argv) { const char *flags = "Hhvnmrc:u:p:d:s:i:"; char WX_APRS[120]; int data_len = 0 ; double winddir; double windspeed; double windgust; double temp; double rain1hr; double rain24hr; double rainday; double humidity; double airpressure; unsigned int valid_data_flgs; int Metric_Dat, dsts = 0; int pid, ss, fd[CONNECTIONS]; socklen_t clen = sizeof(struct sockaddr_in); int *max = 0; int not_a_daemon = 0, repetitive = 0, tcp_wx_port = PORT; int i, index = 0; struct sockaddr_in server, client; struct in_addr bind_address; fd_set rfds; struct timeval tv; int poll_interval = POLL_INTERVAL; int dly_cnt = 1; FILE *pidfile; const char *pidfilename = "/var/run/db2APRS.pid"; struct option longopt[] = { {"help", 0, 0, 'h'}, {"refresh", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"user", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"cport", 1, 0, 'c'}, {"sensor",1, 0, 's'}, {"nodaemon", 0, 0, 'n'}, {"interval",1, 0, 'i'}, {"metric",0, 0, 'm'}, {0, 0, 0, 0} }; debug_level = 0; strcpy(db.user,"meteo"); // set default values for database access strcpy(db.name,"meteo"); memset(db.pswrd,0,15); mysql_init(&mysql); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } while ((opt = getopt_long(argc, argv, flags, longopt, &index)) != EOF) { switch (opt) /* parse command-line or CGI options */ { case 'r': repetitive = 1; break; case 'v': fprintf(stdout,"Verbose mode set:\n"); debug_level = 1; break; case 'u': // mysql username strncpy(db.user,(char *)optarg,30); break; case 'p': // mysql password strncpy(db.pswrd,(char *)optarg,15); break; case 'd': // mysql database name strncpy(db.name,(char *)optarg,30); break; case 'n': /* do not fork and become a daemon */ not_a_daemon = 1; break; case 'c': /* port to use */ tcp_wx_port = strtol(optarg, NULL, 0); break; case 's': /* sensor number for outdoor data */ outdoor_instr = atoi(optarg); break; case 'i': /* polling interval in seconds */ poll_interval = atoi(optarg); break; case 'm': // Metric data from data base Metric_Dat = 1; break; case '?': case 'h': case 'H': usage(0); break; default : usage(1); } } if (debug_level & 1) { fprintf(stdout,"Starting..."); if (repetitive) { fprintf(stdout, " forever "); } else { fprintf(stdout, " one pass only "); } fprintf(stdout," with database user=%s, password=%s, for database=%s\n", db.user, db.pswrd, db.name); if (not_a_daemon) { fprintf(stdout," as a program "); } else { fprintf(stdout," as a daemon "); } fprintf(stdout, " using TCP port %d\n",tcp_wx_port); fprintf(stdout, "an with an outdoor sensor group number of %d\n",outdoor_instr); } if (!not_a_daemon) /* setup has worked; now become a daemon? */ { if ((pid = fork()) == -1) { syslog(LOG_ERR, "can't fork() to become daemon: %m"); exit(20); } else if (pid) { pidfile = fopen(pidfilename, "w"); fprintf(pidfile,"%d\n",pid); fclose(pidfile); exit (0); } syslog(LOG_ERR, "Started\n"); setsid(); for (i = 0; i < NOFILE; i++) { // NOTE: Gcc warns that "ss" could be uninitialized here. if ( i != ss) { close(i); } } } // Data base connection if (!(mysql_real_connect(&mysql, "localhost", db.user, db.pswrd, db.name, 0, NULL, 0))) { if (debug_level & 1) { fprintf(stderr,"err: Data Base connect for user:%s to database:%s failed - exiting: \n\t%s\n", db.user, db.name, mysql_error(&mysql)); } exit(9); } server.sin_family = AF_INET; bind_address.s_addr = htonl(INADDR_ANY); server.sin_addr = bind_address; server.sin_port = htons(tcp_wx_port); if ((ss = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - no socket", progname); } exit(10); } /* / April 2001 Minor change to allow quick * (re)start of daemon or client while there are pending * connections during the quit. To avoid address/port in use * error. */ i = 1; if (setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - setsockopt", progname); } } if (bind(ss, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - cannot bind to socket", progname); } exit(11); } if (listen(ss, CONNECTIONS) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - listen", progname); } exit(12); } if (debug_level & 1) { fprintf(stdout,"Sockets UP.\n"); } umask(0022); for (i = 0; i < CONNECTIONS; i++) { fd[i] = -1; } tv.tv_sec = 0; tv.tv_usec = 0; /* catch signals to close the database connection */ signal( SIGTERM, term_handler );/* termination */ #if defined(SIGPWR) /* SIGPWR is linux centric */ signal( SIGPWR, term_handler ); /* power failure */ #endif if (debug_level & 1) { fprintf(stdout,"Main Loop...\n"); } dly_cnt = 2; // initial delay do { if (!(dly_cnt--)) { dly_cnt = poll_interval; // Every 'dly_cnt' passes check for WX data update dsts = Get_Latest_WX(&winddir,&windspeed,&windgust, &temp,&rain1hr,&rain24hr,&rainday,&humidity,&airpressure, &valid_data_flgs); if ( dsts < 0 ) { if (debug_level & 1) { fprintf(stderr, "err: Get_Latest returned %d\n",dsts); } syslog(LOG_ERR,death_msg); exit(dsts); } // If no new data, make no new string either... if (dsts) { data_len = APRS_str(WX_APRS, last_datetime, winddir,windspeed,windgust, temp, rain1hr, rain24hr, rainday, humidity, airpressure, valid_data_flgs,Metric_Dat); if (!data_len) { if (debug_level & 1) { fprintf(stderr, "err: WX info formatting problem!"); } syslog(LOG_ERR,"WX Data format error\n"); exit(13); } } else { if (debug_level & 1) { fprintf(stderr,"Found no new data this pass...\n"); } } } FD_ZERO(&rfds); FD_SET(ss, &rfds); if (select(ss + 1, &rfds, NULL, NULL, &tv) > 0) { for (current = fd; (*current > 0) && (current < fd + CONNECTIONS - 1); current++); if (current > max) { max = current; } if ((*current = accept(ss, (struct sockaddr *)&client, &clen)) != -1) { write(*current, WX_APRS, data_len); } } if (dly_cnt == poll_interval) { if (debug_level & 1) { fprintf(stdout,"Updating clients:"); } for (current = fd; current <=max; current++) { if (*current > 0) { // active socket if (debug_level & 1) { fprintf(stdout," #"); } signal(SIGPIPE, pipe_handler); write(*current, WX_APRS, data_len); } } if (debug_level & 1) { fprintf(stdout," done\n"); } } sleep(1); } while (repetitive); mysql_close(&mysql); if (debug_level & 1) { fprintf(stdout,"Exiting normally.\n"); } syslog(LOG_ERR,"Terminated normally\n"); exit(0); } Xastir-Release-2.2.2/Davis/src/defs.h000066400000000000000000000011101501463444000172660ustar00rootroot00000000000000 // // Copyright (C) 2004 Bruce Bennett // Portions Copyright (C) 2000-2023 The Xastir Group // // // Dummy info here for now... // #define PORT 1313 #define CONNECTIONS 20 #define NOFILE 20 // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif Xastir-Release-2.2.2/FAQ000066400000000000000000001614261501463444000147120ustar00rootroot00000000000000 Xastir Frequently Asked Questions The latest version of this FAQ is always available from the Xastir project's Git repository on GitHub, at The Questions ------------- 1. Background 1.1 What is Xastir? 1.2 How and why was Xastir created? 1.3 Why the name "Xastir"? 1.4 OK, so how does Xastir compare to other APRS(tm) clients? 1.5 How thoroughly tested is Xastir? 1.6 Whom do I contact for support? 1.7 Where can I submit Bug reports or feature requests? 1.8 Is there any more information on Xastir? 1.9 Where can I get Xastir? 2. General Technical Questions 2.1 "Why can't I...? Why won't...work?" What to do in case of problems 2.2 How do I submit a patch to the Xastir Development Group? 2.3 What's the best hardware/operating system/... 2.4 Why isn't there a binary for my platform? 3. Building Xastir 3.1 Why do I get error messages when running "bootstrap.sh"? 3.1a Why do I get strange warnings when I run bootstrap.sh? 3.1b Why are you even using a "bootstrap.sh" script when autoreconf exists? 3.2 Why won't Xastir compile with my system's cc? 3.3 I'm using gcc and I get some compilation errors, what is wrong? 3.4 The linking stage is failing because it isn't linking in the freetype library. What to do? 3.5 During the linking stage, it's giving me "undefined reference to `CompressImageColormap'". What to do? 3.6 Some of the text looks strange, writes over itself and other user interface weirdness occurs. Why? 3.7 Why isn't ImageMagick recognized and used during Xastir's "configure" stage? 3.8 Why does compilation of map_geo or map_WMS fail with "invalid operands to binary <<" errors? 4. Running Xastir 4.1 Why do I get wrong texts in menus or other places when using a non-English language file? 4.2 I run Xastir under Linux, and I get an error about loading a shared library. 4.3 I run Xastir under Linux, and try to set up an ax25 device, but get a "Hard Fail" error on the interface. There is a "permission denied" error in the terminal from which I started Xastir. 4.4 I run Xastir, and get on the air, but nobody else sees me on their screens. 4.5 I run Xastir, and get on the air, but none of the other stations appear on my screen? 4.6 Who is this APX190 guy who all my stuff is getting sent to? Who are these RELAY, WIDE and TRACE people digipeating packets, and why are they putting different callsigns in the fields where their names used to be? Why doesn't anyone answer me when I connect to them? HELP!!! 4.7 When weather alerts come in, the counties on my map don't highlight. 4.8 I have geoTIFF support compiled and working, but when I select a map, it gives me a -38 error converting the datum, and it doesn't display in the right place. 4.9 Xastir runs slowly/loads maps slowly. 4.10 I installed a new version of lesstif, but the help menu shows the old version. 4.11 Why does Xastir seg-fault sometimes when indexing or loading geoTIFF images? 4.12 Why doesn't Xastir run on RedHat 9.0 properly? 4.13 Why do I see "Character '\55' not supported in font"? 4.14 Why do I see strong blue tinting for the maps? 4.15 My config file got munged. How do I recover? 4.16 Why can't I set my position in Xastir correctly? 4.17 Why do I get black map images when I use ImageMagick? 4.18 Why does my MacOSX machine w/USB->Serial adapters hang? 4.19 Why do NumLock/ScrollLock/CapsLock interfere with mouse/keyboard operation? 4.20 How to I redirect serial ports from one computer to another? 4.21 I have Festival compiled in, but I can't get any speech, why? 4.22 ImageMagick gives me: "no decode delegate", why? 4.23 How do I get through an http proxy server with Xastir in order to fetch maps? 4.24 Can I run multiple copies of Xastir at once? 4.25 Why doesn't Terraserver work for some locations? 4.26 Some station or config settings are not getting saved, why? 4.27 Why are my colors messed up when running via VNC? 4.28 Why are the labels missing in the Configure->Timing dialog? 4.29 Xastir can't find "xastir.rgb" or some other file. What's wrong? 4.30 Why can't I see station trails as stations move around? 4.31 Why don't the maps I installed show up in the Map Chooser? 4.32 Dialogs are tiny bullet-shaped windows with no handles. Why? 4.33 Fedora 12 right-click menus don't work. 4.34 What about using Xastir with a TNC-X with built-in USB on a Mac? 4.35 Why do I get "Bitmap not found? /usr/share/xastir/symbols/2x2.xbm" 5. Features 5.1 Why doesn't Xastir include ? 5.2 Why doesn't Xastir digipeat packets sent to the RELAY or WIDE1-1 aliases? 5.3 How do I take a snapshot of my current view? 5.4 What is that yellow circle on my map? 5.5 How can I restart Xastir remotely/from a script/command-line? The Answers ----------- 1. Background 1.1 What is Xastir? Xastir is an APRS(tm) client program that uses amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. 1.2 How and why was Xastir created? There were already several APRS(tm) client programs available to the Mac/DOS world when Frank Giannandrea, KC2GJS decided to develop a Unix client using X Window's and the Motif/LessTiff widget set. From its meager beginnings, Xastir is now a very robust client that meets the needs of the Ham community. 1.3 Why the name Xastir? Xastir is an acronym for X Amateur Station Tracking and Information Reporting. Besides it sounds much cooler that those other names ;) 1.4 OK, so how does Xastir compare to other APRS(tm) clients? Being actively developed by and for Hams, Xastir is constantly being improved upon to reflect the changing state of APRS(tm). Xastir has all the functionality you would find in any other APRS(tm) client, from any OS, and quite possibly some unique features. 1.5 How thoroughly tested is Xastir? Xastir is currently in use by hundreds of Hams from around the world. The Xastir Group maintains rigorous standards before releasing new versions of our client. When bugs do show up, we release patches and new versions as soon as they are available. 1.6 Whom do I contact for support? This FAQ may answer many of users frequent questions. However, there are two active mailing lists that users could use to help answer any other questions. Both mailing list are by subscription only and can be accessed through the Xastir web-site. See the top of this document for the addresses. You must be subscribed in order to post messages. 1.7 Where can I submit Bug reports or feature requests? The mailing lists are a good place to bring up bugs or feature requests. Note that you must be subscribed in order to post messages. See above. Another good place to document the request or bug in a more permanent manner is the GitHub tracker: http://github.com/Xastir/Xastir/issues 1.8 Is there any more information on Xastir? See the main Xastir web-site for more information. See the top of this document for the addresses. 1.9 Where can I get Xastir? Source code and binaries for several popular Linux distributions is available through the Xastir web-site 2. General Technical Questions 2.1 "Why can't I...? Why won't... work?" What to do in case of problems. If are having trouble running the Xastir software: 1. Check the FAQ! The latest version of the Xastir FAQ can be found on the Xastir web-site. See the top of this document for the addresses. 2. Ask on the "xastir" mailing list. Many Xastir users and developers can be found roaming its virtual halls, so it is suggested that you seek wisdom there. The chances are good that you'll get your question answered there. You must be subscribed in order to post messages. 2.2 How do I submit a patch to the Xastir Development Group? The Xastir Development Group encourages patches from outside developers. There are two main "types" of patches: small bug fixes and general improvements. Improvements, modifications, and additions should follow the instructions below: In general, the first course of action is to be a member of the "xastir-dev" mailing list. This indicates to the Group that you are closely following the latest developments. Your patch file should be generated using either 'diff -c' or 'diff -u' against the latest Git tree. To submit your patch, send email to the "xastir-dev" mailing list with a Subject: line that starts with [PATCH] and includes a general description of the patch. In the body of the message, the patch should be clearly described and then included at the end of the message. If the patch-file is long, you can note a URL to file itself. Use of MIME enclosures/attachments should be avoided. Be prepared to respond to any questions about your patches and possibly defend your code. If your patch results in a lot of discussion, you may be asked to submit an updated patch that incorporates all changes and suggestions. 2.3 What's the best hardware/operating system? Anything that works for "you". 2.4 Why isn't there a binary for my platform? The developers make sure that the software builds and works correctly on the platforms available to them; this does not necessarily mean that your platform is one of them. In addition, the Xastir Project is primarily source oriented, meaning that the distributing valid and build-able source code is the purpose of a release, not making sure that there is a binary package for all of the supported platforms. 3. Building Xastir 3.1 Why do I get error messages when running "bootstrap.sh"? The xastir build procedure requires automake 1.6.3 or later and autoconf 2.53 or later. Using anything older than those will not work. To be very sure of what version of autoconf and automake you're using please examine the output of "automake --version" and "autoconf --version" Do not trust your system's package management software to tell you what version is installed. Some systems install more than one different version of autoconf/automake and you can't be sure which one you're using unless you look at the actual version number reported by the tools themselves. Worse still, some systems install multiple versions of autoconf and automake and name them in ways that confuses everything (e.g. "automake19" or "autoconf253"). If that's the case on your system, you could either edit bootstrap.sh by hand to force it to find the right ones (adding paths or suffixes or whatever it takes), or you could just end-run the process and download the source code for a suitable version of automake and autoconf from www.gnu.org, use "--prefix=" options when configuring both of them, build them, and install them into someplace your system won't care about. For example, assuming you've untar'ed, say automake-1.6.3 and autoconf-2.57 into the current directory, and that xastir lives in your directory as /home/me/src/xastir: cd automake-1.6.3 ./configure --prefix=/home/me/src/xastir make install cd ../autoconf-2.57 ./configure --prefix=/home/me/src/xastir make install cd /home/me/src/xastir export PATH=/home/me/src/xastir/bin:$PATH ./bootstrap.sh This will completely bypass any odd version of automake and autoconf that your system might use, and will insulate you from incompatible changes in those installed tools if you upgrade your OS. 3.1a Why do I get strange warnings when I run bootstrap.sh The various configure.ac, acinclude.m4, and Makefile.am files that are used by Xastir's autoconf'd build process were designed for automake 1.6.3 and autoconf 2.53. Using a much more recent version than those could result in warning messages because the tools aren't strictly backward compatible. Most of these warnings are harmless. 3.1b Why are you even using a "bootstrap.sh" script when autoreconf exists? Xastir dates back to the mid- to late-1990s, when autoconf did not have "autoreconf" and developers were expected to provide a bootstrap script. Since then, non-autoconf stuff like generation of "pirate english" and "pig latin" language files got stuffed into bootstrap and was maintained there for years. So bootstrap.sh was still required and did more than "autoreconf" did. The non-autoconf stuff has since been removed from bootstrap.sh and moved into the build step where it belonged, and now bootstrap.sh and "autoreconf -i" do basically the same thing and either is acceptable. 3.2. Why won't Xastir compile with my system's cc? If Xastir won't compile on your system, it is probably due to one of the following causes: - The configure script doesn't recognize your system environment. This might be either because it's completely unknown or because the specific environment (include files, OS version, etc) isn't explicitly handled. If this happens, you may need to port the software to your OS yourself. - Your systems C compiler is garbage. Some operating systems include a default C compiler that is either not ANSI C-compliant or suffers from other deficiencies. The usual recommendation in cases like this is to acquire, install, and use gcc. - Your include files may be confused. In some cases, we have found that a compiler installation or system upgrade has left the C header files in an inconsistent state. Make sure that your include directory tree is in sync with the compiler and operating system. - You haven't installed all the necessary libraries and include files. Xastir depends on at least the X, and Motif or LessTif include files. Be sure these are installed before trying to compile the application. Many Linux distributions name these packages -dev or -devel. NOTE: If you installed ImageMagick from a binary distribution, it will be dependent on the shared libraries for the various graphics formats installed on system on which it was compiled. Be sure you have these same libraries installed, or you'll get a link error. NOTE: The ImageMagick-devel package included with RedHat 8 is missing some files needed for Xastir. The version in the beta directory on RedHat's ftp site works. A message like "*** Cannot find Motif include files" either means that you are missing the development package for Motif/OpenMotif/Lesstif, or that it is installed in a place where configure can't find it. It is recommended that you use Motif or OpenMotif instead of Lesstif, as you'll have few problems with those libraries. For SuSE 9.0, install the "openmotif-libs", "openmotif-devel", and "openmotif" packages. Other distributions have similar naming. If you have the Motif libraries and headers installed in a place where Xastir doesn't look for them, see the references to the "--with-motif-includes" and "--with-motif-libraries" configure options in the INSTALL file. - Your operating system or compiler may be out of version. Software vendors issue new releases for a reason; sometimes to add functionality, but more often to fix bugs that have been discovered. Try upgrading your compiler and/or your operating system. 3.3 I'm using gcc and I get some compilation errors, what is wrong? GCC parses your system header files and produces a modified subset which it uses for compiling. This behavior ties GCC tightly to the version of your operating system. So, for example, if you were running IRIX 5.3 when you built GCC and then upgrade to IRIX 6.2 later, you will have to rebuild GCC. Similarly for Solaris 2.4, 2.5, or 2.5.1 when you upgrade to 2.6. Sometimes you can type "gcc -v" and it will tell you the version of the operating system it was built against. If you fail to do this, then it is very likely that Xastir will fail to build. One of the most common errors is with readv, writev, or uio.h. This is not a bug with Xastir. You will need to re-install GCC. 3.4 The linking stage is failing because it isn't linking in the freetype library. What to do? This is, yet again, an ImageMagick problem. ImageMagick as installed on some systems needs this library linked in. The "Magick-config" script is supposed to supply a list of all of the libraries that ImageMagick needs, but evidently they forgot one. To get around this problem, you can add "-lfreetype" to the link line to get the compile to complete. 3.5 During the linking stage, it's giving me "undefined reference to `CompressImageColormap'". What to do? This is, yet again, an ImageMagick problem. ImageMagick decided to change their API on us again. Newer releases of Xastir work around this problem by checking the version of ImageMagick you have and changing the function call to match. 3.6 Some of the text looks strange, writes over itself and other user interface weirdness occurs. Why? This has been seen to occur due to bugs in some versions of LessTif. You may want to try OpenMotif instead if it is available for your distribution. One caveat that was found on Slackware 8.1 is the need to delete all the text in the /usr/X11R6/lib/X11/config/host.def file otherwise it still refers to the LessTif installation. 3.7 Why isn't ImageMagick recognized and used during Xastir's "configure" stage? Xastir's configure script looks for a program called Magick-config in your default PATH. If it cannot find this program, it will skip building with Magick support. The first thing you should check is whether this program exists, and whether the directory where it lives is in your PATH. You might have forgotten to install both ImageMagick and the ImageMagick-devel RPM. Another possibility is that your particular RPM's might not contain all of the library dependencies that you need, like libcms or zlib. Check carefully through "config.log" to see if the ImageMagick detection code says something like: "ld: cannot find -llcms", "ld: cannot find -lz", or "ld: cannot find -ljpeg". Install the additional libraries that it needs, and perhaps development packages for them as well. NOTE: If the "spec" file for the ImageMagick/ImageMagick-devel RPM's had the proper dependencies listed, you would have been asked to install all of the dependent libraries before you could have even installed the ImageMagick RPM's. Encourage your vendor to fix the "spec" files for those RPM's to include all dependencies. 3.8 Why does compilation of map_geo or map_WMS fail with "invalid operands to binary <<" errors? This is a problem with ImageMagick. In short, your ImageMagick installation has been built with an option incompatible with Xastir. New versions of ImageMagick include experimental support for High Dynamic Range Images (HDRI). This support changes the data type of a Quantum (pixel value) from an 8- or 16-bit integer quantity to a floating point. Xastir assumes that all pixel values are integer types, and uses operations on those values based on that assumption. You have two choices for getting around this issue: rebuild ImageMagick without HDRI support, or use GraphicsMagick instead. 4. Running Xastir 4.1 Why do I get wrong texts in menus or other places when using a non-English language file? The development is done mainly with the English language file, so other languages may not be up to date. Those texts like IC>PULDNMBC02 are placeholders for missing entries in the language file. You can add the local meaning of that string in the English language file to your language file. And send it to the Xastir development team... 4.2 I run Xastir under Linux, and I get an error about loading a shared library. Xastir uses many shared libraries, including lesstif, and perhaps libax25, libproj, libtiff, libgeotiff, libz, libjpeg, etc. These errors indicate ld.so, the Linux dynamic linker, can't find the shared libraries. * First, check that all the libraries are installed. Check the INSTALL file for the locations to get these libraries if you've accidentally removed one of them. * Run "ldd /usr/local/bin/xastir". This will print out a list of libraries that Xastir is looking for and the locations they are expected to be at. * Check that the locations of the libraries are in /etc/ld.so.conf. This should probably be set up by your Linux distribution, but if you've added new library directories after install, you'll need to add them here. This is most applicable to lesstif which installs its libraries in non-standard locations. Read the lesstif installation instructions for more information on this. (Very recent versions create symlinks in /usr/local/lib, so you probably won't need to do anything aside from running ldconfig.) * If you had a libc5 system and hand upgraded it to libc6, and are attempting to link against both libc5 and libc6 built libraries at once, stop now and recompile all your libraries against libc6. The dynamic linkers are different for libc5 and libc6 programs, and linking against libraries built with both versions is bound to cause trouble. This setup has caused many people lots of headaches. Just upgrade your distribution. 4.3 I run Xastir under Linux, and try to set up an ax25 device, but get a "Hard Fail" error on the interface. There is a "permission denied" error in the terminal from which I started Xastir. As mentioned in INSTALL and helpfile, Xastir must be setuid root to use Linux ax25. This is required because Xastir needs the ability to edit its source callsign, and use other advanced options that the Linux ax25 stack restricts to root. 4.4 I run Xastir, and get on the air, but nobody else sees me on their screens. From a software standpoint, check that you have transmitting enabled on your interface, and that the disable transmission "all" and "my position" options in the Interfaces menu are not enabled. Check that ALTNET support in File|Configure|Defaults isn't enabled. Also check that your digipeater path is set reasonably; other hams in your area could probably help with this, as the exact settings depend on your setup and on your area's network. The other possibilities are hardware problems: Is the output level on your TNC or soundcard correct? Is PTT on your radio getting triggered? Is your TXdelay set reasonably? All of these possibilities are beyond the scope of this FAQ. An easy way to determine if your hardware works correctly is to try it on conventional packet. 4.5 I run Xastir, and get on the air, but none of the other stations appear on my screen? Did you set up your TNC startup files correctly to remove any extra data from the packet headers? Are you using the correct startup file? See INSTALL. Check that the Display Incoming Data windows is actually showing data coming in. If not, check your radio's volume/squelch levels and your cabling, both between the radio/TNC and between the TNC/Computer. Check that ALTNET support in File|Configure|Defaults is disabled. If activated, it only shows stations transmitting TO the callsign listed in the box. I sometimes set it to APX or APX190 in order to see who's running Xastir/who's running the _latest_ Xastir. Set it to "WEIRD" and you'll only see those transmitting to "WEIRD". Check all of your Stations|Filter Data and Stations|Filter Display settings. "Select Stations" and "Display Symbols" must be selected. If you are using an older version of Xastir, Qxx packets are considered invalid. This is a newer addition to APRS(tm), and recent Xastir releases decode this correctly. 4.6 Who is this APX190 guy who all my stuff is getting sent to? Who are these RELAY, WIDE and TRACE people digipeating packets, and why are they putting different callsigns in the fields where their names used to be? Why doesn't anyone answer me when I connect to them? HELP!!! You must be used to conventional packet. APRS(tm) is inherently different from conventional packet. There are many online resources that explain the basics of APRS(tm), but I'll try to summarize here. APRS(tm) is an unconnected protocol, where you broadcast UI (unnumbered information) packets to the world. Since these packets aren't directed toward a specific user, the TO address of the packet is simply a summary of the software you're running. AP=APRS(tm), X=X Windowing System, 110=Version 1.10. RELAY, WIDE, TRACE, WIDEn-N, and TRACEn-N are aliases for generic digipeaters, although all but the WIDEn-N variants are now deprecated (should no longer be used). Some base stations have their TNC's configured to digipeat with the call of "WIDE1-1" (we used to use "RELAY" for these, but "WIDE1-1" has now taken its place). Newer digipeater software substitutes their own call for "WIDEn-N" to enable people to see who digipeated them. See the README.Getting-Started file for a bit more info on paths, including recommended paths for different types of stations. To talk to people, you send them messages from within Xastir, you don't "call" them like on typical packet. Most TNC's are set up to ignore classic packet "calls" so you won't get any response. When sending messages to people in your area, do check in their comments that they are people and not stand-alone digipeaters or similar. ;) Thanks to the worldwide APRSserv Internet system, you can send messages to any APRS(tm) user anywhere in the world, provided they're within range of an Igate. Most users are; if your area isn't and you have a 24/7 Internet connection, Xastir can be your area's Igate! (Please check your local laws, as Igating is illegal in some countries!) There are also experimental systems for sending messages via amateur radio satellites, but that is beyond the scope of this FAQ. 4.7 When weather alerts come in, the counties on my map don't highlight. First of all, did you download and install the new shapefile weather maps as described in the INSTALL file? (Running scripts/get-NWSdata automates this somewhat for you now) Did you compile with shapefile support? Check that Map|Enable Weather Alerts is enabled, and "Map|Disable All Maps" is _not_ selected . 4.8 I have geoTIFF support compiled and working, but when I select a map, it gives me a -38 error converting the datum, and it doesn't display in the right place. Did you install libgeotiff before libproj? This error you'll see if you ignored the note in the INSTALL file about this. Recompile libgeotiff and the problem should vanish. If this is not the case, check the datum of the geoTIFF file, and make sure it is one of the ones supported by Xastir. The listgeo program included with libgeotiff can tell you the datum of a map. 4.9 Xastir runs slowly/loads maps slowly. There are many things that can effect the speed of your Xastir software, including the speed of the computer, the amount of memory available, the number of active interfaces, the complexity/type/number of maps you use, and the options you used to compile Xastir and helper libraries. The developers aren't aware of any specific cases in which there would be performance problems; generally these are limitations of your computer. Xastir, when using only basic maps, runs reasonably on a Pentium 60. If you use higher detail maps, such as the tiger line maps suggested in README.MAPS, you'll need a faster computer to be able to load the maps quickly. Also be sure you have a few Megabytes of memory available for Xastir, because paging to disk decreases speed rapidly. If you have the Internet interface, as well as TNC's and weather stations all active at the same time, you'll see a slowdown on a slower computer. Also, if you compiled Xastir or libax25/libtiff/libgeotiff/etc with debugging (-g), recompile these software without debugging and with optimization ON (-O2). 4.10 I installed a new version of lesstif, but the help menu shows the old version. The help menu shows the version of lesstif that Xastir was compiled with, not necessarily the version you're running now. Assuming you compiled it with the new version, check that the new version is the only copy installed. If you install in /usr/local/LessTif/, the default location, be sure you remove any older version from /usr/LessTif/ or /usr/X11R6/LessTif/, as some distributions use those locations. 4.11 Why does Xastir seg-fault sometimes when indexing or loading geoTIFF images? The geoTIFF code must use an API in the TIFF code that is non-public. Unfortunately this means that the geoTIFF code must know more about TIFF than the normal application using the TIFF library. If the private TIFF include file included with the geoTIFF code doesn't match your installed version of TIFF, you can run into seg-fault problems. Solutions for this include: 1) Installing TIFF from sources, or 2) Grabbing the sources for your installed version of TIFF, copying one include file from TIFF into the geoTIFF sources and recompiling/installing geoTIFF. Either of these solutions will make the geoTIFF code recognize and use the proper structures in TIFF should prevent the seg-faulting. In the future we hope that either the geoTIFF code will become part of the TIFF code, or that the private TIFF API will become public. Either of these changes should fix this problem for good. 4.12 Why doesn't Xastir run on RedHat 9.0 properly? The RH kernels have implemented the new(er) New Posix Threading Library (NPTL) as well as back-ported many of the new bells and whistles set to appear in the 2.6.x kernels. You might experience a great improvement for apps that are heavily threaded. NPTL is supposed to be backward compatible but we have seen apps that have had problems. You can revert back to the older LinuxThreads implementation by setting the environment variable: LD_ASSUME_KERNEL= in a shell before starting the app The following versions are available: - 2.4.1 - Linuxthreads with floating stacks - 2.2.5 - Linuxthreads without floating stacks or, you can disable NPTL altogether for dynamically linked applications by using 'nosysinfo' as a boot time option. 4.13 Why do I see "Character '\55' not supported in font"? This message and similar have to do with localization and OpenMotif/ Lesstif. For most of us this is a benign message and can be ignored. If you simply can't stand it any more set LANG="C" or LANG="en_US". In RH 9 the default LANG is set to en_US.UTF-8 and this is where the warnings are coming from. A quick way to address this on RedHat 8 and 9 is to edit your /etc/sysconfig/i18n config file. I believe the original file looks like: LANG="en_US.UTF-8" SUPPORTED="en_US.UTF-8:en_US:en" SYSFONT="latarcyrheb-sun16" Change the "LANG=" line to: LANG="en_US" and reboot. With the original setting you get some weird character mappings. For example, running "man ls", all of the dashes (-) disappeared from my screen until I changed the LANG setting. 4.14 Why do I see strong blue tinting for the maps? Strong blue (or perhaps other color) tinting of the image may be due to running the display over a Hummingbird eXceed session. Try running it locally and you should see the proper colors. Try changing the eXceed session to use more bits of color. 4.15 My config file got munged. How do I recover? Xastir saves previous revisions of the config file as "xastir.cnf.1" through "xastir.cnf.3". Look for them in the ~/.xastir/config directory. Kill Xastir, then copy one of the backup files to "xastir.cnf" in order to recover your previous settings. Xastir will use the "xastir.cnf" file the next time it starts up. Older Xastir versions saved only one copy of the config file as "xastir.bak". 4.16 Why can't I set my position in Xastir correctly? If your LC_NUMERIC environment variable is set to something other than "C", it can cause commas and periods to be swapped when Xastir tries to read/write files. We've tried to address this in the latest Xastir code, forcing LC_NUMERIC="C" inside Xastir itself. Another solution is to type this when starting Xastir (from a BASH shell. If you use another type of shell, modify the syntax accordingly): export LC_NUMERIC="C"; xastir & 4.17 Why do I get black map images when I use ImageMagick? There was a bug in versions of Xastir prior to the Git version of 4 December 2009 that caused this problem if ImageMagick (or GraphicsMagick) were compiled with QuantumDepth not equal to 16 (GraphicsMagick now defaults this parameter to 8). The bug was fixed, and current versions of Xastir should not have this problem. If you are running an older version than 4 December 2009, updating will likely solve this problem for you. If you are running a version higher than 1.9.7 or a git version checked out after 4 December 2009, then the problem lies elsewhere. It may be due to bugs in your particular version of ImageMagick, but more likely it's related to the color-depth of your X-Server. If you are using 8-bit, 24-bit, or 32-bit color-depth: Try 16-bit, which is the color-depth best supported by the Xastir code. 4.18 Why does my MacOSX machine w/USB->Serial adapters hang? Use ports such as /dev/cu.usbserial0 for USB to serial adapters on MacOSX. 4.19 Why do NumLock/ScrollLock/CapsLock interfere with mouse/keyboard operation? Because they are treated as modifiers by Motif. Here's an FVWM2 document (FVWM2 is a window manager) that talks about it: http://www.fvwm.org/documentation/faq/index.php?theme=navigate See section 5.5 of that document which talks about these keys. If you type these commands and then restart your window manager it may take care of your problem, but then those keys will be disabled and you won't be able to use in other applications: xmodmap -e "clear Lock" xmodmap -e "clear Mod2" xmodmap -e "clear Mod5" 4.20 How to I redirect serial ports from one computer to another? For Linux, try a program called "remserial". It works as a client/server pair to do exactly what you want. Google should find it for you. One user was able to use a spare serial port on his windows box using "remserial" on the Linux computer and a program called "serproxy" on the windows machine. Another one I have to try for windows is comfoolery. See links below. Another option is to use a Perl script on each end to do the conversion. Yet another is to use "netcat". "man nc" or "man netcat" should tell you about it. It redirects tcpip data seamlessly under Linux. On SuSE the docs for it are in /usr/share/doc/packages/netcat. Try a command line like this: cat /dev/ttyS0 | nc -l -p 3000 or cat /dev/ttyS0 | netcat -l -p 3000 That should make a listening socket at port 3000 which listens to the /dev/ttyS0 serial port. "telnet localhost 3000" should show you any data coming in on that serial port. Connect Xastir across the network to that listening socket to get the data. If you want to put your GPS on a remote serial port, use the gpsd daemon to do it. if you wish to put your weather station on a remote serial port, investigate using OWW (for Dallas weather stations), wx200d daemon for some Radio Shack/Huger/Oregon Scientific weather stations, or Meteo daemon for Davis weather stations. You may also connect to a remote AGWPE instance for using remote TNC's/soundcards. Note that AGWPE runs only on Windows. Yet another which looks to be netcat recoded/extended: socat Comfoolery: http://www.brianpoe.com/comfoolery/ Serproxy: http://freshmeat.net/projects/serproxy/ Serproxy: http://www.lspace.nildram.co.uk/freeware.html Remserial: http://lpccomp.bc.ca/remserial/ Socat: http://www.dest-unreach.org/socat/ 4.21 I have Festival compiled in, but I can't get any speech, why? a) You must start the Festival server daemon before starting Xastir. Start it via this command : festival_server & b) If the server is running, but you get this: "festival_client: connect to server failed", then you may have some tweaks to do to your system files in order to allow Xastir (or anything else) to connect to Festival. Try this first to see whether anything can connect to Festival: telnet localhost 1314 If the server is running properly it'll let you connect. If it does, try typing: (SayText "Hello, World") If that doesn't work, check your audio mixer settings first, then proceed to c) below: c) Some people have an "/etc/hosts" file that has an incorrect line for localhost. You should have a line which has 127.0.0.1 at the start, and has "localhost" somewhere on that line as well. Like this: 127.0.0.1 localhost localhost.localdomain d) On one Debian box, it was an issue with "/etc/hosts.allow". See "man 8 tcpd" or "man 5 hosts_access" for detailed info about how to configure /etc/hosts.allow and /etc/hosts.deny. It's part of the tcpwrappers stuff that allows you to configure which hosts have access to which services on your system. 4.22 ImageMagick gives me: "no decode delegate", why? README.CYGWIN has a bit of info about this one, as it most often happens on Win32 systems. It has been seen on other systems as well though. The short answer is that you may have to set the environment variable "MAGICK_HOME" to the location where the ImageMagick modules reside. This is only necessary if ImageMagick doesn't have the location pre-compiled into it. The example for Win32 systems is: export MAGICK_HOME=/usr Added to the ~/.profile file, so that the BASH shell gets this defined each time you log in. The location "/usr" will probably be different on a non-Windows machine, so change the line above as required for your system. 4.23 How do I get through an http proxy server with Xastir in order to fetch maps? *) Install libcurl and/or wget. *) Set the HTTP_PROXY and FTP_PROXY environment variables in your ~/.profile file. Libcurl has additional options that can be set: HTTPS_PROXY, GOPHER_PROXY, and ALL_PROXY. *) Create and fill in the ~/.netrc and/or .wgetrc files with proper values. Set the permissions on it so that only you can read/write the file: "chmod 600 .netrc". Typical contents of the file are shown below: http_proxy = http://proxy.yoyodyne.com:18023/ ftp_proxy = http://proxy.yoyodyne.com:18023/ 4.24 Can I run multiple copies of Xastir at once? Yes, but you must keep the configuration directories separate for each copy by using a command-line flag. Xastir will create the new config directory and fill it with defaults if it doesn't already exist. Here's the method. Substitute your user name where it says "": xastir & # starts up first Xastir copy against ".xastir" directory xastir -c /home//.xastir2 & # starts up 2nd Xastir copy against ".xastir2" directory xastir -c /home//.xastir3 & # starts up 3rd Xastir copy against ".xastir3" directory To make the process easier if you use this method a lot, create aliases by editing your .profile (This assumes you're running BASH or Bourne shells): alias xastir2='xastir -c /home//.xastir2 &' alias xastir3='xastir -c /home//.xastir3 &' After sourcing your new .profile (The command is ". .profile" from your home directory) or logging out and back in again, you can type "xastir2" or "xastir3" as a command to start up the additional copies of Xastir. Older methods, may still be useful at times: Do this to allow more than one user to access your X display and to create additional users, each capable of running one Xastir session: xhost localhost This lets other users on your machine use the X11 display. Create another user (or two or three) using whatever facilities your system uses to do this. xterm & # Start up an xterm window in the background su 2nduser. # su to one of your new usernames xastir & # Start up Xastir as that user, in the background Optional: Set up your 1st Xastir instance with the server port enabled. Connect the 2nd instance to localhost:2023. This way one Xastir will get its feed from the other. You can start up a third Xastir in the same manner, starting with the "xterm &" command and then doing "su 3rduser" instead, then "xastir &" as that third username. Many Xastir sessions can all get their feed from one Xastir session, or they can be connected to different TNC's or server ports. 4.25 Why doesn't Terraserver work for some locations? Terraserver is based on the UTM coordinate system. If you're trying to request map images that cross a UTM zone boundary, Terraserver may not work at that location. Zoom in closer or pan left/right in order to avoid this problem. 4.26 Some station or config settings are not getting saved, why? A few of the menu settings do not get saved. This is on purpose. If you are having more serious troubles, like for instance your station location setting isn't getting saved between Xastir runs, check your LANG setting (see question 4.13 above). 4.27 Why are my colors messed up when running via VNC? VNC may have a different colormap or colordepth than the system Xastir is running on. Here is one invocation that a user used which worked. Substitute the appropriate parameters for your system of course: vncserver :5 -name melecom -depth 24 -geometry 800x600 -pixelformat rgb565 4.28 Why are the labels missing in the Configure->Timing dialog? Some versions of the Lesstif widget set have this bug. Try switching to a different version of Lesstif or switch to OpenMotif and you should see the labels again. So that you can actually operate Xastir, here's what you _should_ have seen: On the left: ------------ Posit TX Interval (min) Object/Item TX Interval (min) GPS Check Interval (sec) Dead-Reckoning Timeout (min) New Track Time (min) RINO -> Objects Interval (min), 0=Disabled Snapshot Interval (min) On the right: ------------- Station Ghosting Time (min) Station Clear Time (hours) Station Delete Time (days) Serial Inter-Char Delay (ms) New Track Interval (degrees) Internet Map Timeout (sec) A screenshot on the Wiki of this dialog: 4.29 Xastir can't find "xastir.rgb" or some other file. What's wrong? This could be one of several things. We'll check them in order: a) If you get this exact message: "Error! can not find color file: /xastir/config/xastir.rgb" Then it could be that you're not getting a variable defined on the compile line. This text or similar should appear for each file compiled: -DXASTIR_DATA_BASE=\"/usr/local/share/xastir\" If you're not seeing this, or the variable is defined to an empty string or is otherwise incorrect, you may need to upgrade/downgrade your autoconf or automake packages and rerun the Xastir install starting at the "./bootstrap.sh" stage. b) Did you run the "make install" stage as root or using "sudo" after you compiled Xastir? If not, Xastir couldn't install files it needs to run. c) Another possible problem is a corrupt or very old ~/.xastir/config/xastir.cnf file. Check for this by typing: cd mv .xastir .xastir.save xastir If it comes up ok this time, then either paths in your config file are incorrect or the config file is corrupt. If there's no change, go back to your original configuration by typing: cd rm -rf .xastir # NOTE: this will delete ~/.xastir and all contents! mv .xastir.save .xastir d) Yet another thing to check is the value in your LANG variable. It should be either "en_US" or "C" for Xastir to read/write config files correctly: echo $LANG If it is something else, start Xastir like this: export LANG=en_US; xastir -geometry -0-0 & You can create an alias in your shell for this so that you don't have to remember to type it each time. e) Perhaps you're trying to run an old Xastir executable that was compiled with different paths, or you have an LSB-Xastir installed and have compiled or installed Xastir in the normal fashion as well. Type this to see where the executable is trying to run from: which xastir -or- whereis xastir f) It's possible that your autoconf/automake packages need to be upgraded or downgraded. These packages are somewhat version dependent on each other, so it's likely that you'll have to do this upgrade or downgrade as a pair for things to work correctly. After the upgrade or downgrade, recompile Xastir starting at the "./bootstrap.sh" stage so that the configure and Makefile scripts are re-created. ./bootstrap.sh cd ../build ../Xastir/configure make Make sure that you now see a reasonable path for the XASTIR_DATA_BASE variable on each compile line. 4.30 Why can't I see station trails as stations move around? Enable Station->Filter Display->Display Trail File->Configure->Timing->"New Track Time" and "New Track Interval should be set above zero. Defaults for these are 45 and 1 respectively. If this problem and others occur, such as your latitude/longitude getting lost between runs, this might indicate a problem with your LANG variable. See question #4.26 above. 4.31 Why don't the maps I installed show up in the Map Chooser? Install the maps in the correct place, normally "/usr/local/share/xastir/maps/" or subdirectories below there. If running LSB-Xastir it's "/opt/Xastir/share/xastir/maps/". Make sure the map directories and files have read permissions for the user. Select "Map->Configure->Index: Add New Maps", then check in Map Chooser to see if the map is listed. If not, try the "Reindex ALL Maps" option. Verify that you have installed the map libraries necessary to handle the types of maps you're wishing to use: "Help->About". Also you can check the messages written to STDERR in the shell you start Xastir from. Check this file to see if map indexing found the file at all. It's the same file that Map Chooser reads to display the map selections: ~/.xastir/config/map_index.sys If the map is a raster map, you can check whether your installed ImageMagick or GraphicsMagick can display the image. For IM: display For GM: gm display If it's an internet-based map you're trying to download/display, verify in the Xterm that you have internet maps enabled using either libcurl or wget. Check manually whether curl or wget (whichever Xastir is using) can fetch a remote file. Check whether a file like ~/.xastir/tmp/map.gif or map.jpg shows up after you try to fetch a file, even if Xastir doesn't display it. See if one of the above "display" commands will display it if so. Check the File->Configure->Timing dialog for the "Internet Map Timeout" setting: Adjust it upwards if Xastir is timing out fetching the remove map. If all else fails, try removing the ~/.xastir directory and all contents. Warning: This will cause you to lose all of your personal Xastir configuration, including callsign, location, bookmarks, map levels and other map settings, etc. Once you've done this, verify that your LANG setting is either "C" or "en_US", with no additional characters in there, then start Xastir from that same shell with the correct LANG setting. Xastir should index all of your maps on startup. After it is complete, bring up the Map Chooser and all available maps should be listed. 4.32 Dialogs are tiny bullet-shaped windows with no handles. Why? This is caused by an interaction between "Motif" and "compiz". "compiz" is enabled in some versions of Ubuntu Linux with a "Desktop Effects" menu item. They changed the default to *ON* several releases ago. "compiz" is a window manager which enables eye-candy effects such as animated window opening/closing, 3-D effects, and so forth. To fix this problem, turn *OFF* "Desktop Effects" which will disable "compiz" and re-enable the default window manager. 4.33 Fedora 12 right-click menus don't work. This was a Fedora X11 bug and has been fixed. Do a "yum update" on your system to get the latest Fedora fixes. If you're having troubles with another OS, read this thread to get some insight into the problem: https://bugzilla.redhat.com/show_bug.cgi?id=543647 It appears to be a bug in the X11 server and can affect OpenMotif and Lesstif apps. I didn't read every comment though. There were definitely many dead-ends as they went along discussing it. 4.34 What about using Xastir with a TNC-X with built-in USB on a Mac? You will need the device drivers from FTDI, downloadable from their website at http://www.ftdichip.com/Drivers/VCP.htm Note: the TNC-X packet datarate is fixed at 1200 baud, however the serial communication with the computer is configurable via internal jumpers. It's been observed that setting the com port to 1200 baud results in a deaf TNC-X. Setting the com port to 9600 baud works well, however. 4.35 Why do I get "Bitmap not found? /usr/share/xastir/symbols/2x2.xbm" The problem is that you probably have previously installed a binary version of Xastir from your system's repository --- and Linux packages are set up to install files in /usr (e.g. binaries to /usr/bin, libraries to /usr/lib/, and supporting files to /usr/share). But Git xastir, like almost all source packages, installs to /usr/local (/usr/local/bin, /usr/local/lib, /usr/local/share). When you de-installed your binary package and installed the source version, it removed the /usr/ stuff and installed the files in /usr/local/. Your configuration files for Xastir still point to the old locations, and Xastir is confused because files it's expecting aren't there. You have two approaches to fix this: 1) If you have not used Xastir a lot and don't have a whole lot of custom configurations (map selections, interface properties, etc.) then you can just move your ~/.xastir/config/xastir.cnf file and let Xastir regenerate a default set-up. Many people here recommend that approach because it's just a matter of one command: mv .xastir/config/xastir.cnf .xastir/config/xastir.cnf_old But this will blow away all your customizations, so it might not be the best choice. Note that you can still glean information from the old copy of the config file to help set up the new. 2) Change all references to "/usr/" in your configuration files to "/usr/local". Most of these will be in ~/.xastir/config/xastir.cnf so it's just a matter of editing that one file and changing them all. It is always an issue when you switch from a pre-compiled linux package to a source build. 5. Features 5.1 Why doesn't Xastir include ? Probably because someone hasn't taken the time to write the feature or enough people have complained loud enough that it wasn't there. The feature set of Xastir is user/developer driven. So get busy! 5.2 Why doesn't Xastir digipeat packets sent to the RELAY or WIDE1-1 aliases? If you're running serial-port connected TNC's, the "tnc-startup.*" files that get installed in /usr/local/share/xastir/config should set up your TNC to respond to these packets. Select Interfaces->Properties, then select the interface, click Properties, then select the Setup and Shutdown files at the bottom of that dialog. When an interface is brought up the Setup file will be downloaded to the TNC. "myalias WIDE1-1" is the command most TNC's accept for defining a digipeating alias. That command or similar should be in the Setup file that you use. Use "myalias WIDE1-1" with the new path scheme discussed on APRSSIG during early April, 2005: RELAY/WIDE/TRACE/TRACEn-n are deprecated (should not be used). If you're running kernel AX.25 interfaces, then you'll need to run another package to handle digipeating on these interfaces, perhaps digi_ned. 5.3 How do I take a snapshot of my current view? You can cause a snapshot to occur by enabling Snapshot in the File menu. It takes a snapshot every five minutes starting immediately when the togglebutton is first enabled. This means you can change views and disable/enable to take an immediate snapshot each time as well. You can also send a "SIGUSR1" signal from another process and Xastir will take a snapshot. The feature was added so that someone could press a button on a web page and cause Xastir to make a new snapshot. For Example, from the shell you can do: kill -SIGUSR1 `cat ~/.xastir/xastir.pid` Snapshots will are stored under ~/.xastir/tmp/ 5.4 What is that yellow circle on my map? Somewhere around a half-hour or an hour after you start Xastir with a connected TNC, you will begin to see a yellow circle surrounding your station at some zoom levels. This is your "ALOHA Circle," the circle containing approximately the number of stations that should saturate your local APRS channel. See http://web.usna.navy.mil/~bruninga/aprs/ALOHAcir.txt for details. The short story is you should set your path so your packets don't travel farther than this circle's radius. This circle is shown when your station is in view and you are zoomed out far enough to contain the circle in the viewport. Its radius is recalculated once every half an hour from the stations you've heard on RF. Stations you hear from internet servers or other non-RF sources are not included in the calculation. The circle can be turned off from the Station->Filter Display menu but it will be enabled again each time you restart Xastir. 5.5 How can I restart Xastir remotely/from a script/command-line? Send a SIGHUP to the process. This will cause Xastir to save its configs, exit, then restart with the same environment and command-line parameters as it initially had. For Example, from the shell you can do: kill -SIGHUP `cat ~/.xastir/xastir.pid` NOTE: This SIGHUP trick doesn't work if you've configured Xastir with profiling ( "../Xastir/configure --with-profiling" ). ---------------------------------------------------------------- APRS(tm) is a Trademark of Bob Bruninga If you find other problems, or would like to point out other caveats to add to this FAQ, please point them out to the developers on the Xastir-dev mailing list. The addresses for the mailing lists may be found on the main Xastir web pages, which are listed at the top of this document. You must be subscribed in order to post messages. Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/INSTALL.md000066400000000000000000000665231501463444000160120ustar00rootroot00000000000000# Installing Xastir # This file is meant to replace the original "INSTALL" file that has been distributed with Xastir for years. General build process: 0. [Install all system packages required and any optional packages](#install-all-system-packages-required-and-any-optional-packages) 1. [Get the Xastir source code](#get-the-xastir-source-code) 2. [Bootstrap the source code to create the configure script](#bootstrap-the-source-code-to-create-the-configure-script) 3. [Create a build directory and run configure in it with any necessary options](#create-a-build-directory-and-run-configure-in-it-with-any-necessary-options) 4. [Build Xastir](#build-xastir) 5. [Install the code](#install-the-code) 6. [Start using Xastir](#start-using-xastir) 7. [Miscellaneous notes](#miscellaneous-notes) The procedure for building Xastir from source is fairly generic, and the most difficult part is assuring that you have all dependent libraries. ## Install all system packages required and any optional packages ## **The system-specific build instructions at http://xastir.org/index.php/Installation_Notes often have the exact command you need to install all required and optional packages on that system in one fell swoop, so you would do well to look at those notes before proceeding with the rest of this section.** ### Absolutely mandatory packages ### The packages you absolutely must have in order to build Xastir are: * autoconf * automake * gcc and all of its development headers * glibc and its development headers * openmotif or lesstiff and its development headers * the X11 window system and X development headers * make * git If you don't have at least these, you won't be able to build Xastir at all, and if this is all you have you'll get the most limited version of Xastir possible. On some operating systems the libraries and headers needed for compiling against them are in separate packages, and that's why we list "and its development headers" above. You should look at the system-specific build instructions at http://xastir.org/index.php/Installation_Notes for more detailed instructions on how exactly one goes about actually installing these packages if you are unfamiliar. Some of these packages may already be installed on your system by default, or may be installed in clusters by a meta package such as "build-essential" on Ubuntu, which installs the gcc compiler and all the libraries and headers it needs to function. ### Optional packages ### Installing these optional packages enables additional features in Xastir. You need both the library and development packages for any of these packages for which both are available. * gv and ghostscript (Enables map printing) * libXpm (enables creation of map snapshots for display and printing) * GraphicsMagick (Enables access to many formats of map images) * curl (Enables access to the web to download maps or other data) * shapelib (Enables display of vector maps in ESRI shapefile format) * pcre2 (Perl Compatible Regexps, enables control of how shapefile maps are displayed) * libgeotiff (Enables display of maps in Geotiff format, such as older topographic maps provided by the US Geological Survey) * ax25-apps, ax25-doc, ax25-tools, libax25 (enables Linux kernel mode AX.25 for sharing/access of KISS TNC devices) * festival (enables text-to-speech options) * Berkeley DB version 5 (enables caching of some online map imagery) or version 18.1 In some cases, there are alternatives that can provide the same features: * wget can be used instead of curl * ImageMagick 6 (NOT ImageMagick 7) can be used instead of GraphicsMagick, but GraphicsMagick is preferred * The older PCRE library (sometimes called PCRE3, even though the *current* version is PCRE2) can be used, but is long past its end of life. PCRE2 is preferred. Some of the packages listed above depend on other packages themselves, but the norm of modern package management systems is to install all the dependencies when the main package is installed. ## Get the Xastir source code ## There are two ways to get Xastir source code: 1. Get one of the source release "tarballs" from Github at https://github.com/Xastir/Xastir/releases and explode it. (Replace X.Y.Z with the release number below) ``` mkdir -p ~/src/XASTIR cp Xastir-Release-X.Y.Z.tar.gz ~/src/XASTIR cd ~/src/XASTIR tar xzvf Xastir-Release-X.Y.Z.tar.gz ``` This gets you ONLY the source code for one single release of Xastir. The source code will live in the directory `~/src/XASTIR/Xastir-Release-X.Y.Z` 2. An alternative to the above steps is to use git to download the Xastir sources: ``` mkdir -p ~/src/XASTIR cd ~/src/XASTIR git clone https://github.com/Xastir/Xastir.git ``` This will create a clone of the Xastir git repository in an "Xastir" subdirectory of the current directory. The Xastir source code will be in `~/src/XASTIR/Xastir` All done! You now have the latest development sources on your computer. Not only that, you have a complete copy of the entire project history and access to all prior releases. ## Bootstrap the source code to create the configure script ## Since Release 2.1.8 the Xastir project has not distributed source code that is ready to build out of the box, even in release tarballs. It must always be "bootstrapped" before proceeding. 1. If you are working from a tarball of source code and followed the path suggestions above: ``` cd ~/src/XASTIR/Xastir-Release-X.Y.Z ./bootstrap.sh ``` 2. If you grabbed a clone from git and followed the recommendations above: ``` cd ~/src/XASTIR/Xastir ./bootstrap.sh ``` In either case, you should see the following output: ``` > ./bootstrap.sh 5) Removing autom4te.cache directory... 4) Running aclocal... 3) Running autoheader... 2) Running autoconf... 1) Running automake... Bootstrap complete. ``` If you don't see "Bootstrap complete" at the end, it didn't work and the error messages output should guide you to the source of the problem (usually this only fails when you have not installed all the necessary autoconf/automake tools). This bootstrap procedure creates the "configure" script you need in the next step. ## Create a build directory and run configure in it with any necessary options ## In order to build Xastir, the configure script you just created must be run. Configure tries to work out what you've got installed and whether it can find all of the pieces it needs. In many cases on Linux you can get away with running it with no options at all and it'll find everything it needs. In some cases you might need to provide it with hints about where to find things like libraries and headers. And there are a number of configure options that allow you to control whether to skip some features you don't want, even if you've got all the pieces installed that would normally enable them. We strongly recommend doing configuration and building of Xastir in a "build directory" rather than right in the same directory as the source code. The reason for this is that doing so leaves the source code directory completely pristine, and only creates new stuff in the build directory. This makes it much easier to clean up and start over (you can simply delete the build directory), and also makes it easier to spot when something has accidentally been changed in the source tree. The examples below all have the same basic steps: create a new directory and move into it, then run configure in it. The only difference between them is whether you have to give any arguments to configure. ### The simplest example possible ### Create a new directory in which to build, and run configure in it: ``` mkdir ~/MyXastirBuildDirectory cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure ``` Here we're assuming you got Xastir source code from git and ran bootstrap.sh, and bootstrap.sh completed without error. This may be all you need, and if all you have done was install the minimum required libraries you should see configure exit with this message: ``` xastir X.Y.Z has been configured to use the following options and external libraries: MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : no RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : no GraphicsMagick/ImageMagick (Raster maps) .. : no pcre (Shapefile customization) ............ : no Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : no FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no xastir will be installed in /usr/local/bin. Type 'make' to build Xastir (Use 'gmake' instead on some systems). ``` If you've installed optional libraries and they were properly located by configure, then some of these "no" lines will have "yes" instead. ### Slightly more involved examples ### Some systems like to install the headers for "libgeotif" into "/usr/include/geotiff" instead of directly into "/usr/include". If that is the case, configure simply won't find them. In that case, one has to tell configure to tell the C preprocessor to add an additional place to look for header files. So on those systems one would have to do: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/include/geotiff" ``` On most Linux systems, that's the extent of the complexity you might need. ### When lots of stuff is in weird places ### Similarly, on systems like FreeBSD, third-party packages do not install *anything* into "/usr/include" or "/usr/lib" but rather into "/usr/local/lib" or "/usr/local/include". In that case, you'd have to tell the C preprocessor and linker to look in extra places, too: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ``` Note that systems like Macs often require add-on package managers like "homebrew" or "macports" which love to put headers and libraries in strange places where the C compiler and linker don't look by default. The techniques above apply there, too. You can stack up options, too, such as: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/local/include -I/some/weird/place/include" LDFLAGS="-L/usr/local/lib -L/some/weird/place/lib" ``` ### A much more involved example ### On my own system, the Berkeley DB libraries are in a weird place, and GraphicsMagick will not work with the default system C compiler at all. So in my case, I have to run configure as: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure --with-bdb-incdir=/usr/local/include/db5 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++13 LIBS="-ldb-5.3" ``` Here, I'm telling it to look in special places when looking for Berkeley DB headers and libraries, to use a specific (non-default) compiler, to use specific compiler options (CFLAGS), and to use the Berkeley DB library "libdb-5.3" (LIBS) irrespective of any other that might be found on the system. It is critically important when building with Berkeley DB that the headers in the bdb-incdir are for the same version of Berkeley DB as the most recent version present in the library directory. If one has both Berkeley DB 5 and Berkeley DB 18.1 installed, Xastir will use the most recent version present, even if one has told it to use an older set of headers. The example above forces Xastir to use the older library even if a newer one is present, because it is also using the older header files per the setting of "--with-bdb-incdir". Since db5 is now very old and deprecated on FreeBSD, I can instead build Xastir with DB version 18.1, so long as I make sure to point to the right headers: ``` cd ~/MyXastirBuildDirectory ../Xastir/configure --with-bdb-incdir=/usr/local/include/db18 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++13 ``` Here, all I've had to do is specify where the headers are. Since db18.1 is the most recent version installed configure will find and use it by default, so I don't need to specify LIBS in this case. ## Build Xastir ## Once configure has completed, has announced that it has really succeeded and that you can "make" the code, and all the options it shows as enabled are in fact the options you wanted enabled, then just build it (I'm assuming you're still in your build directory): ``` make ``` You should see a bunch of status updates about what it's doing and what file is being compiled, and when it's all done you should see no statement from "make" that it has aborted due to errors (you may see a handful of warnings, but you can safely ignore those). Once it's all done you can make a quick test to make sure a valid executable was created by typing: ``` ./src/xastir -V ``` which should respond with a version number, such as: ``` Xastir V2.1.9 (Release-2.1.8-47-g00ce2b88) ``` This particular version number indicates that we're building from a git clone, that it's Version 2.1.9, and that 47 code commits have happened since the prior release 2.1.8, and that the current git commit reference is 00ce2b88. You can ignore all that if you don't know what it means. The important thing that it produced a version number and not an error message. That's it, you've built Xastir with the options that configure said you enabled. ## Install the code ## You've built Xastir, but it still lives in your home directory somewhere. If you want it to be generally accessible on your system, you need to install it. You must be root to do this. ``` cd ~/MyXastirBuildDirectory sudo make install ``` Xastir will by default have installed itself into /usr/local/bin by this process (and its support files will generally have been installed into /usr/local/share/xastir). If you're running on a Linux system and have enabled AX.25 networking, you also need to do the following command to give the binary access to kernel AX.25 ports: ``` sudo chmod 4755 /usr/local/bin/xastir ``` ## Start using Xastir Xastir can now be run simply by typing its name at the command line. The default map (the only one you can view with the bare minimum install) is ugly and ancient, but if you enabled GraphicsMagick and curl then there are many online map options available immediately in the map chooser. I recommend `Online/OSM_tiled_mapnik.geo`. You will now have to get Xastir configured and connected to your TNC or an internet APRS server. * [Starting Xastir](#starting-xastir) * [Changing the language](#changing-the-language) * [Configuring Xastir](#configuring-xastir) * [Various ways to manipulate Xastir](#various-ways-to-manipulate-xastir) ### Starting Xastir: NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Assuming you want to start Xastir up in the English language, you can type (from an xterm window): xastir which will start up the program without giving you back a command-prompt in your xterm window (until Xastir exits), or you can type (from an xterm window): xastir & which will start Xastir in the background, giving you back your xterm for more commands. The typical way to start it is with "xastir &". Of course you can get fancier and attach it to your window manager's menus or create an icon on your desktop which starts it. Those are operating system/window manager-specific, so we won't cover how to do that here. The first time you start Xastir it will show a default map of the world plus pop up the File->Configure->Station dialog. Enter a callsign on that dialog and press the OK button. ### Changing the Language: If you want to start Xastir using some other language, you do that with command-line switches when you start Xastir. Once you use one of these switches, that language option becomes "sticky", meaning you won't have to enter that command-line switch again unless you wish to change languages. If you type "xastir -?", which is an invalid command-line option, you'll see this: ``` xastir: invalid option -- h Xastir Command line Options -c /path/dir Xastir config dir -f callsign Track callsign -i Install private Colormap -geometry WxH+X+Y Set Window Geometry -l Dutch Set the language to Dutch -l English Set the language to English -l French Set the language to French -l German Set the language to German -l Italian Set the language to Italian -l Portuguese Set the language to Portuguese -l Spanish Set the language to Spanish -l ElmerFudd Set the language to ElmerFudd -l MuppetsChef Set the language to MuppetsChef -l OldeEnglish Set the language to OldeEnglish -l PigLatin Set the language to PigLatin -l PirateEnglish Set the language to PirateEnglish -m Deselect Maps -p Disable popups -t Internal SIGSEGV handler enabled -v level Set the debug level -V Print version number and exit ``` Ignore those for now unless you need to change the Language. OK, Xastir should show up on your screen at this point. We're assuming that you're already running the X Window System environment at this point. If you're in command-line Linux/Unix only, Xastir won't run. If you've configured in ShapeLib capability, you'll need to run /usr/local/share/xastir/scripts/get-NWSdata as the root user in order to get the NOAA data files you'll need for the weather alerts. The script requires "wget" in order to work. Run this script periodically (once every six months perhaps?) to keep your weather alert maps up-to-date. If you're not in the U.S. or one of it's possessions then you can safely ignore this download. ### Configuring Xastir: * Note that the menus have a dashed line near the top. If you click on that dashed line it acts like a cut-line for the menu and detaches that menu from the main menu. You can then move that menu off to another area of your screen. You might try that with the File->Configure menu at this time. * Go to File->Configure->Station and set your callsign. Set up other parameters/comment fields on this dialog that may need setting. * Go to File->Configure->Defaults and set parameters there. You have the main parameters set now. Next is to enable some interfaces so that you can see some packets come across. Easiest might be the Internet interfaces, assuming the computer you're on has Internet access and is hooked up to it currently. * Run "callpass" in another Xterm window in order to generate your Pass-code number. Save that number as you'll need it for each Interface dialog where you might need to authenticate your callsign. Of course you can always run callpass again if you forget it! * Go to Interface->Properties then click on "Add". Click "Internet Server". Another dialog will come up that allows you to enter the Host, and the Port. Enter your Pass-code number here. People often check the "Activate on Startup?" and the "Reconnect on NET failure?" options on this box. You may also assign a comment to this interface which describes the interface better for you. Click "OK" to create the interface. If you checked "Activate on Startup?" then the interface will start as well and you'll be receiving packets. Browse "http://www.aprs2.net/" to find a reasonable set of servers to start with. Another possibility is to use "rotate.aprs2.net" port 14580, which theoretically should rotate among the available second-tier servers. See "http://www.aprs2.net" for more info. You'll need to put in a filter string, such as "r/35/-106/500" which shows you stations that are within 500km of 35dN/106dW (Thanks for that one Tom!). For additional filter settings check out: http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm * Start that interface from the Interface->Start/Stop dialog if it's not started already. You'll see icons in the lower right toggling and see callsigns in the lower left status box if packets are coming in. One thing about configuration: Most things don't get written to Xastir's config file until you choose either "File->Configure->Save Config Now!" or you exit Xastir. Map Selections however are immediate. * Creating/starting interfaces for other types of devices is similar. If you're wanting to create AX.25 kernel networking ports you'll have to refer to the HAM HOWTO documents and perhaps the linux-hams mailing list for help. For AGWPE connections refer to that AGWPE docs and mailing list. It's recommended that if you run a local TNC, you run it in KISS mode. You can do that via the Serial KISS TNC interface, or via AX.25 Kernel Networking ports. Some of the more esoteric types of interfaces may require some questions on the Xastir list. Don't be afraid to ask them as we've all been there before. ### Various ways to manipulate Xastir #### Context-Dependent Operations: The top row of this table refers to the mode of operation. The "Cursor" row describes what the cursor looks like when in that mode. Each following row describes what the operation on the left hand column performs. | | Normal | Draw-Cad | Measure | Move | |:-:|:-:|:-:|:-:|:-:| | Cursor| Arrow | Pencil | Crosshairs | Crosshairs | | LeftClick | | | | SelectObject | | LeftDrag | ZoomToArea | ZoomToArea | MeasureArea | MoveObject | | MiddleClick | ZoomOut | SetCADPoint | ZoomOut | ZoomOut | Alt-F, Alt-V, etc to bring up main menus via the keyboard. Use arrow keys to navigate menus and/or single letters corresponding to the "hot" letter (underlined letter) for each menu item. "ESC" to back out of the menu system. #### Global Operations: | Action | Function | |:--|:--| |LeftClick| Select Menu or GUI Item (when in menus or dialogs)| |LeftDblClick| FetchAlertText (when in View->Wx Alerts dialog)| |RightClick | OptionsMenu| |Home| Center the map on your home station| |PageUp| ZoomOut| |PageDown| ZoomIn| |ArrowUp| PanUp| |ArrowDown| PanDown| |ArrowLeft| PanLeft| |ArrowRight| PanRight| |"="| GridSize++| |"+"| GridSize++| |"Num+"| GridSize++| |"-"| GridSize--| |"Num-"| GridSize--| |"Space"| Activate current widget| |"Tab"| Rotate among widgets| |"Back-Tab"| Rotate among widgets backwards| #### Other Possible External Stimuli: If you send Xastir a signal (using "kill"), you can force it to perform some action based on which signal you send. * Send a SIGUSR1 to cause a snapshot to be taken. * Send a SIGHUP to cause Xastir to save/quit/restart. * Send a SIGINT, SIGQUIT, or SIGTERM to cause Xastir to quit. * Connect to TCP port 2023 if Server Port is enabled to send/receive packets. * Send to UDP port 2023 via the `xastir_udp_client` program to inject packets. ## Miscellaneous notes ### A Note About the Map Directory: The map directory (/usr/local/share/xastir/maps/) is free-form, meaning you can have links in there, subdirectories, etc. Organize it in any way that makes sense to you. From within the Map Chooser you can select a directory name, which will select every map underneath that directory, so keep that in mind while organizing your maps. ### Enabling Weather Alerts: You must have Shapelib compiled into Xastir, which also requires the PCRE2 library and its development headers to be installed. Install NOAA shapefile maps as specified in README.MAPS. These files must be installed into the /usr/local/share/xastir/Counties/ directory. You may use this script to download/install them for you: "/usr/local/share/xastir/scripts/get-NWSdata" which must be run as the root user, and requires "wget" to work. A neat trick: You can copy some of these maps into the /usr/local/share/xastir/maps directory somewhere (a new subdirectory under there is always fine), then you can select some of these maps as regular Xastir maps as well. ### Enabling FCC/RAC Callsign Lookup: Run the /usr/local/share/xastir/scripts/get-fcc-rac.pl script as root, which will download and install the proper databases into the /usr/local/share/xastir/fcc/ directory. At that point the callsign lookup features in the Station Info dialog and in the "Station->Find Station" menu option should be functional. ### Enabling Audio Alarms: Download and install sample audio files from Xastir's GitHub download site: git clone http://github.com/Xastir/xastir-sounds Copy the files to your Xastir sounds directory, for instance `/usr/local/share/xastir/sounds/` Install a command-line audio player. Call out the path/name of that player in the File->Configure->Audio Alarms dialog. Common ones are vplay and auplay, but there are many others. Enable the types of alarms you desire in that same dialog. You should be able to test it manually from a shell by typing the command in something like this: vplay filename Once you find a command that works, type it into Xastir's Audio Alarms dialog exactly the same except omit the filename. ### Enabling Synthesized Speech: This is currently available only on Linux/FreeBSD. * Install the Festival Speech Synthesizer. Configure/compile support for it into Xastir. Start up the Festival server before starting Xastir using `festival --server &`. Xastir should start up and connect to the server. Use the options in File->Configure->Speech to decide which things you'd like Xastir to speak to you about. Note that the Proximity Alert option in the File->Configure->Speech dialog uses the distances set in the File->Configure->Audio Alarms dialog. ### Enabling GPS Waypoint/Track/Route Download Support: Install GPSMan and gpsmanshp. Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. You'll see download options for each type on the Interface menu. Note that Xastir requires a version of gpsman at least as recent as 6.1. Older versions of gpsman may not work. ### Transmit Enable/Disable Options: Each interface has a separate transmit enable. The Interface menu also has a few global transmit enables. All of these must be enabled for a particular interface to transmit. Also, for Internet servers, you typically need to authenticate with the server using your callsign/pass-code before you're allowed to inject packets into the Internet stream which may get gated out to RF. If you just want to talk to other Internet users, you don't need a pass-code to authenticate to the servers. ### Igating Options: There are igating options on each local TNC interface. There are other global igating options on the File->Configure->Defaults dialog. The global option sets restrictions on all igating. ### Where stuff is kept: Per-user configurations are kept in each user's ~/.xastir directory, by default. In particular the ~/.xastir/config/xastir.cnf file is where most of the configs are kept. This directory can be optionally specified using the -c /path/dir command line option. Make sure you specify a directory, not a file! Xastir will create the directory and several subdirectories if they do not exist when you start up. A few executables are installed in /usr/local/bin/. Scripts are installed in /usr/local/share/xastir/scripts. Maps are installed in /usr/local/share/xastir/maps/. Lots of other directories are under /usr/local/share/xastir/. Xastir-Release-2.2.2/LICENSE000066400000000000000000002624041501463444000153630ustar00rootroot00000000000000----------- Xastir Source ----------- *) The majority of the Xastir source code is under the GPLv2 license. This applies also to all supporting files, images, and configure files distributed in the Xastir source repository. See the file named "COPYING" for details about the GPLv2. There are a few exceptions, noted here: *) src/datum.h and src/datum.c were derived from public domain source code. The name and copyright are listed in that file. *) src/rotated.h and src/rotated.c are available under a permissive license to "use, copy, modify, and distribute ... for any purpose and without fee" provided a copyright notice and acknowledgement appears in all copies. The license text, copyright notice, and required acknowledgement are: /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ *) src/festival.h and src/festival.c are available under a license that permits unrestricted use and distribution, so long as the copyright notice is included and attributions maintained. The required list of enumerated Xastir modifications is in src/festival.c That license, the required copyright notice, and attribution are: /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ *) The code in the src/shapelib directory is an old version of shapelib that is built and used by Xastir only if an external shapelib is not already installed on the system. This code is licensed under the LGPLv2. The LGPL terms are in src/shapelib/LICENSE.LGPL ------------------------------- Xastir scripts ------------------------------- *) Except where explicitly noted in comments, the scripts in the scripts directory are all licensed under the GPLv2. Any script without explicit license information in its comments should be presumed to be GPLv2. Some of the programs in the scripts directory are provided under other open source licenses, and the licensing information will be present in script comments, which should be consulted for details: inf2geo.pl, mapfgd.pl, overlay.pl, ozi2geo.pl, permutations.pl, ridge_radar.pl, split_gnis.bash --- These are stated to be "Released into the Public Domain" by their respective authors. ------------------------------- Additional license terms ------------------------------- Some scripts in the scripts directory use the term "LSB." These scripts are all GPLv2 licensed, and contain the following caveats in their headers: *) "Free Standards Group, FSG, Linux Standard Base, LSB, Free Standards Certified, LSB Certified and the Free Standards Certified logo are trademarks, service marks and certification marks, as appropriate, of Free Standards Group in the United States and in other countries." We are in no way representing that Xastir has been certified by the FSG. To do so costs real money. We do intend some Xastir binaries to install and run properly on LSB-3.0 compliant x86 Linux systems though. ------------------------------- Third party library licenses ------------------------------- Xastir may be built optionally with a number of third party libraries. The licenses to these third party libraries are only relevant when distributing a binary that has been built to include those libraries. The remainder of this document consists of the license terms of these various third party libraries. *) libcurl ( is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2006, Daniel Stenberg, . All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. ------------------------------- ------------------------------- *) libdb () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: The following is the license that applies to this copy of the Berkeley DB software. For a license to use the Berkeley DB software under conditions other than those described here, or to purchase support for this software, please contact Sleepycat Software by email at info@sleepycat.com, or on the Web at http://www.sleepycat.com. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /* * Copyright (c) 1990-2005 * Sleepycat Software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Redistributions in any form must be accompanied by information on * how to obtain complete source code for the DB software and any * accompanying software that uses the DB software. The source code * must either be included in the distribution or be available for no * more than the cost of distribution plus a nominal fee, and must be * freely redistributable under reasonable conditions. For an * executable file, complete source code means the source code for all * modules it contains. It does not include source code for modules or * files that typically accompany the major components of the operating * system on which the executable file runs. * * THIS SOFTWARE IS PROVIDED BY SLEEPYCAT SOFTWARE ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SLEEPYCAT SOFTWARE * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1990, 1993, 1994, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1995, 1996 * The President and Fellows of Harvard University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ ------------------------------- ------------------------------- *) GraphicsMagick () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: This file is part of the GraphicsMagick software distributed by the GraphicsMagick Group. [ Please note that the legal community considers 15 or more total lines of code or text (not necessarily contiguous) to be significant for the purposes of copyright. Repeated changes such as renaming a symbol has similar significance to changing one line of code. ] The licences which components of this software fall under are as follows. 1) In November 2002, the GraphicsMagick Group created GraphicsMagick from ImageMagick Studio's ImageMagick and applied this license: Copyright (C) 2002 GraphicsMagick Group, an organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("GraphicsMagick"), to deal in GraphicsMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of GraphicsMagick, and to permit persons to whom GraphicsMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of GraphicsMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall GraphicsMagick Group be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with GraphicsMagick or the use or other dealings in GraphicsMagick. Except as contained in this notice, the name of the GraphicsMagick Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in GraphicsMagick without prior written authorization from the GraphicsMagick Group. 2) In August 1999, ImageMagick Studio assumed the responsibility for the development of ImageMagick and applied a new license: Copyright (C) 2002 ImageMagick Studio, a non-profit organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall ImageMagick Studio be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the ImageMagick Studio shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the ImageMagick Studio. 3) From 1991 to August 1999, ImageMagick was developed and distributed by E. I. du Pont de Nemours and Company: Copyright 1999 E. I. du Pont de Nemours and Company Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall E. I. du Pont de Nemours and Company be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the E. I. du Pont de Nemours and Company shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the E. I. du Pont de Nemours and Company. 4) This copyright is limited to some code (for locating an installed Ghostscript under Windows) in the file magick/nt_base.c which was incorporated from the gsview package: Copyright (C) 2000-2002, Ghostgum Software Pty Ltd. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this file ("Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this Software, and to permit persons to whom this file is furnished to do so, subject to the following conditions: This Software is distributed with NO WARRANTY OF ANY KIND. No author or distributor accepts any responsibility for the consequences of using it, or for whether it serves any particular purpose or works at all, unless he or she says so in writing. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 5) The GraphicsMagick Base64Decode() and Base64Encode() functions are based on source code obtained from OpenSSH. This source code is distributed under the following license. Copyright (c) 2000 Markus Friedl. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6) Many of the pattern images in coders/logo.c are derived from XFig, which is distributed under the following license: FIG : Facility for Interactive Generation of figures Copyright (c) 1985-1988 by Supoj Sutanthavibul Parts Copyright (c) 1989-2000 by Brian V. Smith Parts Copyright (c) 1991 by Paul King Any party obtaining a copy of these files is granted, free of charge, a full and unrestricted irrevocable, world-wide, paid up, royalty-free, nonexclusive right and license to deal in this software and documentation files (the "Software"), including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons who receive copies from any such party to do so, with the only requirement being that this copyright notice remain intact. 7) The documentation for the composition operators is copied from the rlecomp manual page, which is authored by Rod Bogart and John W. Peterson. Rlecomp is part of the Utah Raster Toolkit distributed by the University of Michigan and the University of Utah. The copyright for this manual page is as follows: Copyright (c) 1986, University of Utah This software is copyrighted as noted below. It may be freely copied, modified, and redistributed, provided that the copyright notice is preserved on all copies. There is no warranty or other guarantee of fitness for this software, it is provided solely "as is". Bug reports or fixes may be sent to the author, who may or may not act on them as he desires. You may not include this software in a program or other software product without supplying the source, or without informing the end-user that the source is available for no extra charge. If you modify this software, you should include a notice giving the name of the person performing the modification, the date of modification, and the reason for such modification. 8) The C++ API known as "Magick++", and which resides in the Magick++ directory, is distributed under the following license: Copyright 1999 - 2003 Bob Friesenhahn Permission is hereby granted, free of charge, to any person obtaining a copy of the source files and associated documentation files ("Magick++"), to deal in Magick++ without restriction, including without limitation of the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of Magick++, and to permit persons to whom the Magick++ is furnished to do so, subject to the following conditions: This copyright notice shall be included in all copies or substantial portions of Magick++. The copyright to Magick++ is retained by its author and shall not be subsumed or replaced by any other copyright. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall Bob Friesenhahn be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with Magick++ or the use or other dealings in Magick++. 9) GraphicsMagick makes use of third-party "delegate" libraries to support certain optional features. These libraries bear their own copyrights and licenses, which may be more or less restrictive than the GraphicsMagick license. For convenience, when GraphicsMagick is bundled with (or compiled with) "delegate" libraries, a copy of the licenses for these libraries is provided in a "licenses" directory. ------------------------------- ------------------------------- *) Jasper () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: JasPer License Version 2.0 Copyright (c) 1999-2000 Image Power, Inc. Copyright (c) 1999-2000 The University of British Columbia Copyright (c) 2001-2003 Michael David Adams All rights reserved. Permission is hereby granted, free of charge, to any person (the "User") obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. The above copyright notices and this permission notice (which includes the disclaimer below) shall be included in all copies or substantial portions of the Software. 2. The name of a copyright holder shall not be used to endorse or promote products derived from the Software without specific prior written permission. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. ------------------------------- ------------------------------- *) Jpeg () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-1998, Thomas G. Lane. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. ansi2knr.c is NOT covered by the above copyright and conditions, but instead by the usual distribution terms of the Free Software Foundation; principally, that you must include source code if you redistribute it. (See the file ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part of any program generated from the IJG code, this does not limit you more than the foregoing paragraphs do. The Unix configuration script "configure" was produced with GNU Autoconf. It is copyright by the Free Software Foundation but is freely distributable. The same holds for its supporting scripts (config.guess, config.sub, ltconfig, ltmain.sh). Another support script, install-sh, is copyright by M.I.T. but is also freely distributable. It appears that the arithmetic coding option of the JPEG spec is covered by patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot legally be used without obtaining one or more licenses. For this reason, support for arithmetic coding has been removed from the free JPEG software. (Since arithmetic coding provides only a marginal gain over the unpatented Huffman mode, it is unlikely that very many implementations will support it.) So far as we are aware, there are no patent restrictions on the remaining code. The IJG distribution formerly included code to read and write GIF files. To avoid entanglement with the Unisys LZW patent, GIF reading support has been removed altogether, and the GIF writer has been simplified to produce "uncompressed GIFs". This technique does not use the LZW algorithm; the resulting GIF files are larger than usual, but are readable by all standard GIF decoders. We are required to state that "The Graphics Interchange Format(c) is the Copyright property of CompuServe Incorporated. GIF(sm) is a Service Mark property of CompuServe Incorporated." ------------------------------- ------------------------------- *) Lesstif () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: The included files COPYING and COPYING.LIB.LESSTIF, as may apply. ------------------------------- ------------------------------- *) libpng () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: This copy of the libpng notices is provided for your convenience. In case of any discrepancy between this copy and the notices in the file png.h that is included in the libpng distribution, the latter shall prevail. COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: If you modify libpng you may insert additional notices immediately following this sentence. libpng versions 1.2.6, August 15, 2004, through 1.2.14, November 28, 2006, are Copyright (c) 2004, 2006 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors Cosmin Truta libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors Simon-Pierre Cadieux Eric S. Raymond Gilles Vollant and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996, 1997 Andreas Dilger Distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. A "png_get_copyright" function is available, for convenient use in "about" boxes and the like: printf("%s",png_get_copyright(NULL)); Also, the PNG logo (in PNG format, of course) is supplied in the files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net November 28, 2006 ------------------------------- ------------------------------- *) PCRE () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Release 6 of PCRE is distributed under the terms of the "BSD" licence, as specified below. The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself. The basic library functions are written in C and are freestanding. Also included in the distribution is a set of C++ wrapper functions. THE BASIC LIBRARY FUNCTIONS --------------------------- Written by: Philip Hazel Email local part: ph10 Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2006 University of Cambridge All rights reserved. THE C++ WRAPPER FUNCTIONS ------------------------- Contributed by: Google Inc. Copyright (c) 2006, Google Inc. All rights reserved. THE "BSD" LICENCE ----------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the name * of Google Inc. nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------- ------------------------------- *) ZLIB () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: (C) 1995-2004 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. ------------------------------- ------------------------------- *) libXt.a () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: Licenses The XFree86 Project January 2002 1. XFree86 License XFree86 code without an explicit copyright is covered by the following copy- right/license: Copyright (C) 1994-2002 The XFree86 Project, Inc. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is fur- nished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the XFree86 Project shall not be used in advertising or otherwise to promote the sale, use or other deal- ings in this Software without prior written authorization from the XFree86 Project. 2. Other Licenses Portions of code are covered by the following licenses/copyrights. See indi- vidual files for the copyright dates. 2.1 X/MIT Copyrights 2.1.1 X Consortium Copyright (C) X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is fur- nished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. X Window System is a trademark of X Consortium, Inc. 2.1.2 The Open Group Copyright The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. 2.2 Berkeley-based copyrights: 2.2.1 General Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2.2.2 UCB/LBL Copyright (c) 1993 The Regents of the University of California. All rights reserved. This software was developed by the Computer Systems Engineering group at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to Berkeley. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software devel- oped by the University of California, Lawrence Berkeley Laboratory. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes soft- ware developed by the University of California, Berkeley and its con- tributors. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- CLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2.3 NVIDIA Corp Copyright (c) 1996 NVIDIA, Corp. All rights reserved. NOTICE TO USER: The source code is copyrighted under U.S. and international laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design patents pending on the design and interface of the NV chips. Users and possessors of this source code are hereby granted a nonexclusive, roy- alty-free copyright and design patent license to use this code in individual and commercial software. Any use of this source code must include, in the user documentation and internal comments to the code, notices to the end user as follows: Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and foreign countries. NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WAR- RANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAM- AGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. 2.4 GLX Public License GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License") Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby grants permission to Recipient (defined below), under Recipient's copyrights in the Original Software (defined below), to use, copy, modify, merge, pub- lish, distribute, sublicense and/or sell copies of Subject Software (defined below), and to permit persons to whom the Subject Software is furnished in accordance with this License to do the same, subject to all of the following terms and conditions, which Recipient accepts by engaging in any such use, copying, modifying, merging, publishing, distributing, sublicensing or sell- ing: 1. Definitions. (a) "Original Software" means source code of computer software code which is described in Exhibit A as Original Software. (b) "Modifications" means any addition to or deletion from the sub- stance or structure of either the Original Software or any previous Modifications. When Subject Software is released as a series of files, a Modification means (i) any addition to or deletion from the contents of a file containing Original Software or previous Modifications and (ii) any new file that contains any part of the Original Code or previous Modifications. (c) "Subject Software" means the Original Software or Modifications or the combination of the Original Software and Modifications, or portions of any of the foregoing. (d) "Recipient" means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "Recipient" includes any entity which controls, is controlled by, or is under common control with Recipient. For purposes of this definition, "control" of an entity means (a) the power, direct or indirect, to direct or manage such entity, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 2. Redistribution of Source Code Subject to These Terms. Redistributions of Subject Software in source code form must retain the notice set forth in Exhibit A, below, in every file. A copy of this License must be included in any documentation for such Subject Software where the recipients' rights relating to Subject Software are described. Recipient may distribute the source code version of Subject Software under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, and (ii) the license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of this License, which terms may not be modified or superseded by any other terms of such license. If Recipient distributes the source code version under a different license Recipient must make it absolutely clear that any terms which differ from this License are offered by Recipient alone, not by SGI. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such terms Recipient offers. 3. Redistribution in Executable Form. The notice set forth in Exhibit A must be conspicuously included in any notice in an executable version of Subject Software, related documentation or collateral in which Recipient describes the user's rights relating to the Subject Software. Recipient may distribute the executable version of Subject Software under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, and (ii) the license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of this License, which terms may not be modified or superseded by any other terms of such license. If Recipient distributes the executable version under a different license Recipient must make it absolutely clear that any terms which differ from this License are offered by Recipient alone, not by SGI. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such terms Recipient offers. 4. Termination. This License and the rights granted hereunder will terminate automatically if Recipient fails to comply with terms herein and fails to cure such breach within 30 days of the breach. Any sublicense to the Subject Software which is properly granted shall survive any termination of this License absent termination by the terms of such sublicense. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 5. No Trademark Rights. This License does not grant any rights to use any trade name, trademark or service mark whatsoever. No trade name, trademark or service mark of SGI may be used to endorse or promote products derived from the Subject Software without prior written permission of SGI. 6. No Other Rights. This License does not grant any rights with respect to the OpenGL API or to any software or hardware implementation thereof or to any other software whatsoever, nor shall any other rights or licenses not expressly granted hereunder arise by implication, estoppel or otherwise with respect to the Subject Software. Title to and ownership of the Original Soft- ware at all times remains with SGI. All rights in the Original Software not expressly granted under this License are reserved. 7. Compliance with Laws; Non-Infringement. Recipient shall comply with all applicable laws and regulations in connection with use and distribution of the Subject Software, including but not limited to, all export and import control laws and regulations of the U.S. government and other countries. Recipient may not distribute Subject Software that (i) in any way infringes (directly or contributorily) the rights (including patent, copyright, trade secret, trademark or other intellectual property rights of any kind) of any other person or entity or (ii) breaches any representation or warranty, express, implied or statutory, which under any applicable law it might be deemed to have been distributed. 8. Claims of Infringement. If Recipient at any time has knowledge of any one or more third party claims that reproduction, modification, use, distribu- tion, import or sale of Subject Software (including particular functionality or code incorporated in Subject Software) infringes the third party's intel- lectual property rights, Recipient must place in a well-identified web page bearing the title "LEGAL" a description of each such claim and a description of the party making each such claim in sufficient detail that a user of the Subject Software will know whom to contact regarding the claim. Also, upon gaining such knowledge of any such claim, Recipient must conspicuously include the URL for such web page in the Exhibit A notice required under Sec- tions 2 and 3, above, and in the text of any related documentation, license agreement or collateral in which Recipient describes end user's rights relat- ing to the Subject Software. If Recipient obtains such knowledge after it makes Subject Software available to any other person or entity, Recipient shall take other steps (such as notifying appropriate mailing lists or news- groups) reasonably calculated to inform those who received the Subject Soft- ware that new knowledge has been obtained. 9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS, MER- CHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY SER- VICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THE- ORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIA- BILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT. 11. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of Recipient's use, modification, reproduction and distribution of the Subject Software or out of any representation or warranty made by Recipient. 12. U.S. Government End Users. The Subject Software is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 13. Miscellaneous. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unen- forceable, such provision shall be reformed so as to achieve as nearly as possible the same economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any litigation relating to this License shall be subject to the exclusive jurisdiction of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of California), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a con- tract shall be construed against the drafter shall not apply to this License. Exhibit A The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13 of the GLX Public License Version 1.0 (the "License"). You may not use this file except in compliance with those sections of the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043 or at http://www.sgi.com/software/opensource/glx/license.html. Software distributed under the License is distributed on an "AS IS" basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific language governing rights and limitations under the License. The Original Software is GLX version 1.2 source code, released February, 1999. The developer of the Original Software is Silicon Graphics, Inc. Those portions of the Subject Software created by Silicon Graphics, Inc. are Copy- right (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved. 2.5 CID Font Code Public License CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License") Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI") hereby grants permission to Recipient (defined below), under SGI's copyrights in the Original Software (defined below), to use, copy, modify, merge, pub- lish, distribute, sublicense and/or sell copies of Subject Software (defined below) in both source code and executable form, and to permit persons to whom the Subject Software is furnished in accordance with this License to do the same, subject to all of the following terms and conditions, which Recipient accepts by engaging in any such use, copying, modifying, merging, publica- tion, distributing, sublicensing or selling: 1. Definitions. a. "Original Software" means source code of computer software code that is described in Exhibit A as Original Software. b. "Modifications" means any addition to or deletion from the sub- stance or structure of either the Original Software or any previous Modifications. When Subject Software is released as a series of files, a Modification means (i) any addition to or deletion from the contents of a file containing Original Software or previous Modifications and (ii) any new file that contains any part of the Original Code or previous Modifications. c. "Subject Software" means the Original Software or Modifications or the combination of the Original Software and Modifications, or portions of any of the foregoing. d. "Recipient" means an individual or a legal entity exercising rights under the terms of this License. For legal entities, "Recip- ient" includes any entity that controls, is controlled by, or is under common control with Recipient. For purposes of this defini- tion, "control" of an entity means (i) the power, direct or indi- rect, to direct or manage such entity, or (ii) ownership of fifty percent (50%) or more of the outstanding shares or beneficial own- ership of such entity. e. "Required Notice" means the notice set forth in Exhibit A to this License. f. "Accompanying Technology" means any software or other technology that is not a Modification and that is distributed or made publicly available by Recipient with the Subject Software. Separate soft- ware files that do not contain any Original Software or any previ- ous Modification shall not be deemed a Modification, even if such software files are aggregated as part of a product, or in any medium of storage, with any file that does contain Original Soft- ware or any previous Modification. 2. License Terms. All distribution of the Subject Software must be made sub- ject to the terms of this License. A copy of this License and the Required Notice must be included in any documentation for Subject Software where Recipient's rights relating to Subject Software and/or any Accompanying Tech- nology are described. Distributions of Subject Software in source code form must also include the Required Notice in every file distributed. In addition, a ReadMe file entitled "Important Legal Notice" must be distributed with each distribution of one or more files that incorporate Subject Software. That file must be included with distributions made in both source code and exe- cutable form. A copy of the License and the Required Notice must be included in that file. Recipient may distribute Accompanying Technology under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, (ii) such other license terms do not modify or supersede the terms of this License as applicable to the Subject Software, (iii) Recipient hereby indemnifies SGI for any liability incurred by SGI as a result of the distri- bution of Accompanying Technology or the use of other license terms. 3. Termination. This License and the rights granted hereunder will terminate automatically if Recipient fails to comply with terms herein and fails to cure such breach within 30 days of the breach. Any sublicense to the Subject Software that is properly granted shall survive any termination of this License absent termination by the terms of such sublicense. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 4. Trademark Rights. This License does not grant any rights to use any trade name, trademark or service mark whatsoever. No trade name, trademark or ser- vice mark of SGI may be used to endorse or promote products derived from or incorporating any Subject Software without prior written permission of SGI. 5. No Other Rights. No rights or licenses not expressly granted hereunder shall arise by implication, estoppel or otherwise. Title to and ownership of the Original Software at all times remains with SGI. All rights in the Origi- nal Software not expressly granted under this License are reserved. 6. Compliance with Laws; Non-Infringement. Recipient shall comply with all applicable laws and regulations in connection with use and distribution of the Subject Software, including but not limited to, all export and import control laws and regulations of the U.S. government and other countries. Recipient may not distribute Subject Software that (i) in any way infringes (directly or contributorily) the rights (including patent, copyright, trade secret, trademark or other intellectual property rights of any kind) of any other person or entity, or (ii) breaches any representation or warranty, express, implied or statutory, which under any applicable law it might be deemed to have been distributed. 7. Claims of Infringement. If Recipient at any time has knowledge of any one or more third party claims that reproduction, modification, use, distribu- tion, import or sale of Subject Software (including particular functionality or code incorporated in Subject Software) infringes the third party's intel- lectual property rights, Recipient must place in a well-identified web page bearing the title "LEGAL" a description of each such claim and a description of the party making each such claim in sufficient detail that a user of the Subject Software will know whom to contact regarding the claim. Also, upon gaining such knowledge of any such claim, Recipient must conspicuously include the URL for such web page in the Required Notice, and in the text of any related documentation, license agreement or collateral in which Recipient describes end user's rights relating to the Subject Software. If Recipient obtains such knowledge after it makes Subject Software available to any other person or entity, Recipient shall take other steps (such as notifying appro- priate mailing lists or newsgroups) reasonably calculated to provide such knowledge to those who received the Subject Software. 8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS, MER- CHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY SER- VICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED. 10. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold SGI and its successors and assigns harmless from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of (Recipi- ent's use, modification, reproduction and distribution of the Subject Soft- ware or out of any representation or warranty made by Recipient. 11. U.S. Government End Users. The Subject Software is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 12. Miscellaneous. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unen- forceable by any judicial or administrative authority having proper jurisdic- tion with respect thereto, such provision shall be reformed so as to achieve as nearly as possible the same economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any liti- gation relating to this License shall be subject to the exclusive jurisdic- tion of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of Cali- fornia), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation that provides that the language of a contract shall be construed against the drafter shall not apply to this License. Exhibit A Copyright (c) 1994-1999 Silicon Graphics, Inc. The contents of this file are subject to the CID Font Code Public License Version 1.0 (the "License"). You may not use this file except in compliance with the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043 or at http://www.sgi.com/software/opensource/cid/license.html Software distributed under the License is distributed on an "AS IS" basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific language governing rights and limitations under the License. The Original Software (as defined in the License) is CID font code that was developed by Silicon Graphics, Inc. Those portions of the Subject Software (as defined in the License) that were created by Silicon Graphics, Inc. are Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved. [NOTE: When using this text in connection with Subject Software delivered solely in object code form, Recipient may replace the words "this file" with "this software" in both the first and second sentences.] ******************************************************************************** XFree86's LICENSE document does not appear to be completely comprehensive. Many files appear to be licensed under the "SGI FREE SOFTWARE LICENSE B (Version 1.1 [02/22/2000])": SGI FREE SOFTWARE LICENSE B (Version 1.1 [02/22/2000]) 1. Definitions. 1.1. "Additional Notice Provisions" means such additional provisions as appear in the Notice in Original Code under the heading "Additional Notice Provisions." 1.2. "Covered Code" means the Original Code or Modifications, or any combination thereof. 1.3. "Hardware" means any physical device that accepts input, processes input, stores the results of processing, and/or provides output. 1.4. "Larger Work" means a work that combines Covered Code or portions thereof with code not governed by the terms of this License. 1.5. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.6. "License" means this document. 1.7. "Licensed Patents" means patent claims Licensable by SGI that are infringed by the use or sale of Original Code or any Modifications provided by SGI, or any combination thereof. 1.8. "Modifications" means any addition to or deletion from the substance or structure of the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to the contents of a file containing Original Code and/or addition to or deletion from the contents of a file containing previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.9. "Notice" means any notice in Original Code or Covered Code, as required by and in compliance with this License. 1.10. "Original Code" means source code of computer software code that is described in the source code Notice required by Exhibit A as Original Code, and updates and error corrections specifically thereto. 1.11. "Recipient" means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 8. For legal entities, "Recipient" includes any entity that controls, is controlled by, or is under common control with Recipient. For purposes of this definition, "control" of an entity means (a) the power, direct or indirect, to direct or manage such entity, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 1.12. "Recipient Patents" means patent claims Licensable by a Recipient that are infringed by the use or sale of Original Code or any Modifications provided by SGI, or any combination thereof. 1.13. "SGI" means Silicon Graphics, Inc. 1.14. "SGI Patents" means patent claims Licensable by SGI other than the Licensed Patents. 2. License Grant and Restrictions. 2.1. SGI License Grant. Subject to the terms of this License and any third party intellectual property claims, for the duration of intellectual property protections inherent in the Original Code, SGI hereby grants Recipient a worldwide, royalty-free, non-exclusive license, to do the following: (i) under copyrights Licensable by SGI, to reproduce, distribute, create derivative works from, and, to the extent applicable, display and perform the Original Code and/or any Modifications provided by SGI alone and/or as part of a Larger Work; and (ii) under any Licensable Patents, to make, have made, use, sell, offer for sale, import and/or otherwise transfer the Original Code and/or any Modifications provided by SGI. Recipient accepts the terms and conditions of this License by undertaking any of the aforementioned actions. The patent license shall apply to the Covered Code if, at the time any related Modification is added, such addition of the Modification causes such combination to be covered by the Licensed Patents. The patent license in Section 2.1(ii) shall not apply to any other combinations that include the Modification. No patent license is provided under SGI Patents for infringements of SGI Patents by Modifications not provided by SGI or combinations of Original Code and Modifications not provided by SGI. 2.2. Recipient License Grant. Subject to the terms of this License and any third party intellectual property claims, Recipient hereby grants SGI and any other Recipients a worldwide, royalty-free, non-exclusive license, under any Recipient Patents, to make, have made, use, sell, offer for sale, import and/or otherwise transfer the Original Code and/or any Modifications provided by SGI. 2.3. No License For Hardware Implementations. The licenses granted in Section 2.1 and 2.2 are not applicable to implementation in Hardware of the algorithms embodied in the Original Code or any Modifications provided by SGI . 3. Redistributions. 3.1. Retention of Notice/Copy of License. The Notice set forth in Exhibit A, below, must be conspicuously retained or included in any and all redistributions of Covered Code. For distributions of the Covered Code in source code form, the Notice must appear in every file that can include a text comments field; in executable form, the Notice and a copy of this License must appear in related documentation or collateral where the Recipient's rights relating to Covered Code are described. Any Additional Notice Provisions which actually appears in the Original Code must also be retained or included in any and all redistributions of Covered Code. 3.2. Alternative License. Provided that Recipient is in compliance with the terms of this License, Recipient may, so long as without derogation of any of SGI's rights in and to the Original Code, distribute the source code and/or executable version(s) of Covered Code under (1) this License; (2) a license identical to this License but for only such changes as are necessary in order to clarify Recipient's role as licensor of Modifications; and/or (3) a license of Recipient's choosing, containing terms different from this License, provided that the license terms include this Section 3 and Sections 4, 6, 7, 10, 12, and 13, which terms may not be modified or superseded by any other terms of such license. If Recipient elects to use any license other than this License, Recipient must make it absolutely clear that any of its terms which differ from this License are offered by Recipient alone, and not by SGI. It is emphasized that this License is a limited license, and, regardless of the license form employed by Recipient in accordance with this Section 3.2, Recipient may relicense only such rights, in Original Code and Modifications by SGI, as it has actually been granted by SGI in this License. 3.3. Indemnity. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such alternative license terms Recipient offers. 4. Termination. This License and the rights granted hereunder will terminate automatically if Recipient breaches any term herein and fails to cure such breach within 30 days thereof. Any sublicense to the Covered Code that is properly granted shall survive any termination of this License, absent termination by the terms of such sublicense. Provisions that, by their nature, must remain in effect beyond the termination of this License, shall survive. 5. No Trademark Or Other Rights. This License does not grant any rights to: (i) any software apart from the Covered Code, nor shall any other rights or licenses not expressly granted hereunder arise by implication, estoppel or otherwise with respect to the Covered Code; (ii) any trade name, trademark or service mark whatsoever, including without limitation any related right for purposes of endorsement or promotion of products derived from the Covered Code, without prior written permission of SGI; or (iii) any title to or ownership of the Original Code, which shall at all times remains with SGI. All rights in the Original Code not expressly granted under this License are reserved. 6. Compliance with Laws; Non-Infringement. There are various worldwide laws, regulations, and executive orders applicable to dispositions of Covered Code, including without limitation export, re-export, and import control laws, regulations, and executive orders, of the U.S. government and other countries, and Recipient is reminded it is obliged to obey such laws, regulations, and executive orders. Recipient may not distribute Covered Code that (i) in any way infringes (directly or contributorily) any intellectual property rights of any kind of any other person or entity or (ii) breaches any representation or warranty, express, implied or statutory, to which, under any applicable law, it might be deemed to have been subject. 7. Claims of Infringement. If Recipient learns of any third party claim that any disposition of Covered Code and/or functionality wholly or partially infringes the third party's intellectual property rights, Recipient will promptly notify SGI of such claim. 8. Versions of the License. SGI may publish revised and/or new versions of the License from time to time, each with a distinguishing version number. Once Covered Code has been published under a particular version of the License, Recipient may, for the duration of the license, continue to use it under the terms of that version, or choose to use such Covered Code under the terms of any subsequent version published by SGI. Subject to the provisions of Sections 3 and 4 of this License, only SGI may modify the terms applicable to Covered Code created under this License. 9. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED "AS IS." ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY IS AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT SUBJECT TO THIS DISCLAIMER. 10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES NOR LEGAL THEORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT. 11. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of Recipient's use, modification, reproduction and distribution of the Covered Code or out of any representation or warranty made by Recipient. 12. U.S. Government End Users. The Covered Code is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 13. Miscellaneous. This License represents the complete agreement concerning the its subject matter. If any provision of this License is held to be unenforceable, such provision shall be reformed so as to achieve as nearly as possible the same legal and economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any litigation relating to this License shall be subject to the exclusive jurisdiction of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of California), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation that provides that the language of a contract shall be construed against the drafter shall not apply to this License. Exhibit A License Applicability. Except to the extent portions of this file are made subject to an alternative license as permitted in the SGI Free Software License B, Version 1.1 (the "License"), the contents of this file are subject only to the provisions of the License. You may not use this file except in compliance with the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: http://oss.sgi.com/projects/FreeB Note that, as provided in the License, the Software is distributed on an "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. Original Code. The Original Code is: [name of software, version number, and release date], developed by Silicon Graphics, Inc. The Original Code is Copyright (c) [dates of first publication, as appearing in the Notice in the Original Code] Silicon Graphics, Inc. Copyright in any portions created by third parties is as indicated elsewhere herein. All Rights Reserved. Additional Notice Provisions: [such additional provisions, if any, as appear in the Notice in the Original Code under the heading "Additional Notice Provisions"] ------------------------------- ------------------------------- *) GDAL (). Not currently included in any Xastir binaries. This is a placeholder that we may use later. ------------------------------- ------------------------------- *) GV (). Not currently included in any Xastir binaries. This is a placeholder that we may use later. ------------------------------- ------------------------------- To maintain compliance with the above licenses: Hear ye, hear ye! Be it known that the sources for each of the optional libraries listed may be obtained from their normal download sites on the internet. The file you're looking at (LICENSE) is Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/LaCrosse/000077500000000000000000000000001501463444000160615ustar00rootroot00000000000000Xastir-Release-2.2.2/LaCrosse/.vimrc000066400000000000000000000014331501463444000172030ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/LaCrosse/AUTHORS000066400000000000000000000014611501463444000171330ustar00rootroot00000000000000 Developers and Contributions _________________________________________________________________ First, thanks go out to the great folks at the xastir team - a wonderful APRS application set and helpful folks! Thanks also to Andreas Muller, author of meteo and a great resource for information and help. Elements of this software are taken from wx200d ver 1.2 by Tim Witham, and it is modeled after that application. Finally, thanks to the MySQL folks for the key element - the database. N0VH Jim Chandler jim@n0vh.org KB8ROP Bruce Bennett bruts@adelphia.net _________________________________________________________________ Copyright (C) 2003-2004 Bruce Bennett KB8ROP Copyright (C) 2005 Jim Chandler N0VH Xastir-Release-2.2.2/LaCrosse/COPYING000066400000000000000000000431271501463444000171230ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Xastir-Release-2.2.2/LaCrosse/ChangeLog000066400000000000000000000000011501463444000176220ustar00rootroot00000000000000 Xastir-Release-2.2.2/LaCrosse/INSTALL000066400000000000000000000220311501463444000171100ustar00rootroot00000000000000 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. Xastir-Release-2.2.2/LaCrosse/Makefile.am000066400000000000000000000010621501463444000201140ustar00rootroot00000000000000 # # Copyright (C) 2000-2023 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src #if DAVIS #MyWX = davis #else #MyWX = #endif #noinst_PROGRAMS = $(MyWX) # DISTCLEANFILES = EXTRA_DIST = aclocal.m4 AUTHORS bootstrap.sh ChangeLog config.h.in \ config.status configure.ac COPYING INSTALL NEWS \ README bootstrap.sh MAINTAINERCLEANFILES = configure config.status aclocal.m4 \ Makefile.in Makefile config.guess config.sub install-sh \ missing ChangeLog:: Xastir-Release-2.2.2/LaCrosse/NEWS000066400000000000000000000000011501463444000165470ustar00rootroot00000000000000 Xastir-Release-2.2.2/LaCrosse/README000066400000000000000000000161201501463444000167410ustar00rootroot00000000000000 Copyright (C) 2006 Jim Chandler Portions Copyright (C) 2004 Bruce Bennett Portions Copyright (C) 2000-2023 The Xastir Group (Modified for the Xastir project under GPL license) LaCrosse WS-23xx Weather Station support for Xastir - open2300db2APRS OVERVIEW -------- This is a bridge utility between "open2300", a LaCrosse Weather Station data storage & display application by Kenneth Lavrsen (see http://www.lavrsen.dk/twiki/bin/view/Open2300/WebHome) and "Xastir", the APRS package for Linux (see http://www.xastir.org). It allows your LaCrosse WS-23xx weather data to be used by Xastir for local station data. You will need to obtain and install Xastir, mysql and open2300 as outlined in the following sections. After Xastir and open2300 are in working order, this utility can be run as a daemon to provide weather data to Xastir (or any other APRS-format application). "open2300db2APRS" watches for new weather data in the database, retrieves the new data, formats it in APRS "position less" ASCII format and makes it available on a TCP port of your choosing. Xastir is capable of reading this data (see note under Xastir installation). INSTALLATION ------------ Steps in order: 1) Install mysql - initial tested version mysql-3.23.58 although version 4 is released and has some significant improvements - and version 4 *should* work (to be tested yet). If you use an RPM or DPK binary-image version, be sure to add the mysql-devel headers. For the latest image-version, see http://www.mysql.com and follow the links to the downloads. I used mysql-3.23.58-pc-linux-i686.tar.gz from that site. 2) Install open2300 - tested version open2300-1.10 See the instructions for installing & then setting up open2300 that come with the tar ball. Obtain the latest open2300 at http://www.lavrsen.dk/twiki/bin/view/Open2300/WebHome - the setup is rather involved but worth the efort. Some SQL/XML skills can help here, but are not absolutely required... The table setup for the mySQL portion of the open2300 database can be found in the weatherdump.sql file. My database is setup for degree F, inches of Mercury, inches of rain, and windspeed in knots. 3) Install or update your installation for Xastir to the latest version ("http://github.com/Xastir/Xastir" project Xastir) 4) Install open2300db2APRS See instructions below. SETTINGS & STARTUP ------------------ 1) mysql - it is recommended by mysql to set up passwords, but for this usage it doesn't matter. In fact, it's a bit of a pain. TODO - open2300db2APRS has the annoying fault of clearly displaying the password used for the mysql database for anyone to see via 'ps -ef'. Start mysqld before open2300db2APRS, meteo and Xastir in your boot-time initializations. 2) open2300 - my testing used a five minute data accumulation rate. Thirty seconds would more closely match Xastir, but the database growth rate would be twelve as fast (about 600 Mbytes/year at 30 sec rate). I run a cronjob every five minutes that calls mysql2300 to populate the data. See the open2300 documentation. 3) open2300db2APRS - see "open2300db2APRS RUN OPTIONS" below. Start this daemon after mysqld and before Xastir. I start it with the command "open2300db2APRS -r --password 4) xastir - start this last, if you are auto-opening the WX port. Set the weather port as a network weather station on "localhost", port number as chosen in "db2APRS RUN OPTIONS" (default is 1313). Make sure your station is set to one of the "w/weather data" and your Icon is set to a weather Icon. open2300db2APRS RUN OPTIONS --------------------------- The open2300db2APRS utility takes standard short & long command line options, which can be displayed by "open2300db2APRS -?". Here's the list: -h --help Show help info and exit. -v --verbose Useful with the -n switch, for trouble-shooting, not for normal operation. Tells you more than you really wanted to know, but I recommend that you use this switch while you try to initially set up db2APRS. -c --cport [port#] Choose which TCP/IP port data comes out from. If not used, port number 1313 is the default. HINT: "telnet localhost [port#]" is a handy way to verify db2APRS operation. -u --user [database user] Username for mysql database connection. If unspecfied defaults to "meteo" (which is per the meteo setup intended to be a read-only account for meteo). -p --password [db passwd] Password for mysql connection. If unspecfied, no password is supplied. NOTE: this password is unfortunately visible to anyone on your system running 'ps -ef'. TO BE FIXED. -b --database [database] Database name for mysql connection. If not supplied the default is "meteo". -n --nodaemon Run in the fore-ground as a program. Useful for debugging or initial setup, when used with -v. -r --repeat Keep going till killed - if not specified, one pass is performed and then db2APRS exits. The only case where this switch is *not* used is during initial setup/debug. Typical example: "./open2300db2APRS -r -u open2300 -p mysql2300" for normal use or "./open2300db2APRS -r -n -v -u test -p password" for debugging. OPERATIONAL DETAILS ------------------- open2300db2APRS connects to the specified mysql database, extracts the latest timestamp and compares it to the last timestamp it read. If newer, the outdoor weather data (extception: air pressure is taken as indoor=outdoor) bearing this timestamp is extracted and formatted in the APRS "position less" string format with a Davis and X-APRS tag on the end. Any connecting client is given this string at 25 second intervals, after new database entries are checked for. This daemon could run on any networked Linux machine instead of the machine hosting Xastir, if desired (it's a good way around lack of processing power, disk space or serial ports!). Note that the open2300db2APRS daemon keeps providing data to Xastir even when no new entries in the database have been made. This could lead to errors in the timestamp on the data that Xastir is transmitting. BUILD open2300db2APRS --------------------- It's the usual: $ cd xastir/LaCrosse $ ./bootstrap.sh $ ./configure $ make $ su -c 'make install' ACKNOWLEDGEMENTS & AUTHORS -------------------------- A large portion of this work taken from db2APRS (thanks Bruce!!) db2APRS is the product of Bruce Bennett, callsign KB8ROP It is freely available at no charge under the GNU GENERAL PUBLIC LICENSE (see "COPYING" document) NO WARRANTY, expressed or implied, use at your own risk. Please feel free to contact me with test results & comments at the above EMAIL address Code portions and style taken from wx200d by Tim Witham , et. al. mysql is the product of MySQL - see http://www.mysql.com for team details. and finally, Xastir is the brain child of Frank Giannandrea et. al. (see http://www.xastir.org for current EMAIL addresses) Xastir-Release-2.2.2/LaCrosse/bootstrap.sh000077500000000000000000000010011501463444000204250ustar00rootroot00000000000000#!/bin/sh -e # # # Copyright (C) 2000-2023 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.2/LaCrosse/configure.ac000077500000000000000000000040211501463444000203470ustar00rootroot00000000000000# # Copyright (C) 2004 Bruce Bennett # Portions Copyright (C) 2000-2023 The Xastir Group # (Modified for the Xastir project under GPL license) # # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) AC_INIT(open2300db2APRS, 0.1.0, jim@n0vh.org) AM_INIT_AUTOMAKE(open2300db2APRS, 0.1.0) AC_CONFIG_SRCDIR([src/open2300db2APRS.c]) AM_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_INSTALL AC_PROG_CC # Checks for libraries. # Use MySQL's script for library config, if available MYSQL_CONFIG=mysql_config AC_MSG_CHECKING(for a fully installed MySQL) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then MYSQL_VERSION=`${MYSQL_CONFIG} --version` MYSQL_LIBS=`${MYSQL_CONFIG} --libs` LIBS=`${MYSQL_CONFIG} --libs` MYSQL_CFLAGS=`${MYSQL_CONFIG} --cflags` CFLAGS="$CFLAGS $MYSQL_CFLAGS" AC_SUBST(MYSQL_LIBS) AC_SUBST(MYSQL_CFLAGS) AC_MSG_RESULT(...found ${MYSQL_VERSION}) else AC_MSG_RESULT(MySQL is not fully installed) AC_MSG_CHECKING(if there at least are the needed MySQL client libs) AC_CHECK_LIB(mysqlclient,mysql_close) if test $ac_cv_lib_mysqlclient_mysql_close = no; then AC_MSG_ERROR(*** No MySQL client library found - See README ***) else AC_MSG_RESULT(found a usable libmysqlclient) fi fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then AC_MSG_RESULT(mysql.h path defined in CFLAGS) else AC_CHECK_HEADERS([mysql.h],MYSQL_INC="yes",AC_MSG_ERROR(*** MySQL include file mysql.h not found - See README ***)) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME # Checks for library functions. AC_FUNC_FORK AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_STRTOD AC_CHECK_FUNCS([memset select socket strrchr strtol]) AC_CONFIG_FILES([Makefile \ src/Makefile]) AC_OUTPUT Xastir-Release-2.2.2/LaCrosse/src/000077500000000000000000000000001501463444000166505ustar00rootroot00000000000000Xastir-Release-2.2.2/LaCrosse/src/.vimrc000066400000000000000000000014331501463444000177720ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/LaCrosse/src/Makefile.am000066400000000000000000000003441501463444000207050ustar00rootroot00000000000000# # # Copyright (C) 2000-2023 The Xastir Group # bin_PROGRAMS = open2300db2APRS noinst_PROGRAMS = open2300db2APRS_SOURCES = \ open2300db2APRS.c defs.h open2300db2APRS_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.2/LaCrosse/src/defs.h000066400000000000000000000011411501463444000177370ustar00rootroot00000000000000// // // Copyright (C) 2005 Jim Chandler // Portions Copyright (C) 2000-2023 The Xastir Group // // // Dummy info here for now... // #define VERSION "0.1.0" #define PORT 1313 #define CONNECTIONS 20 #define NOFILE 20 // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif Xastir-Release-2.2.2/LaCrosse/src/open2300db2APRS.c000066400000000000000000000656131501463444000213530ustar00rootroot00000000000000/****************************************************************** * * * Copyright (C) 2005 Jim Chandler * Portions Copyright (C) 2000-2023 The Xastir Group * * Portions copied from Bruce Bennett's excellent Davis WX work * * (see the files README and COPYING for more details) * * This file implements all of the database to APRS daemon. * * LaCrosse/Data Base Weather --> APRS Weather Intended use: Create & provide APRS style packet string without position information from MySQL database weather information stored there by open2300 (See http://open2300.sourceforge.net/ for source) to xastir-1.2.1 (See http://www.xastir.org for source) Note: Open2300 is a weather data accumulator aimed at LaCrosse weather stations, which stores weather data in a mysql database. Output is to the ip hostname:port required in the command line. ACKNOWLEDGEMENTS: Elements of this software are taken from wx200d ver 1.2 by Tim Witham , and it is modeled after that application and from db2APRS by Bruce Bennett . *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXARGS 20 /* maximum CGI args to parse */ #define TMPLEN 128 /* max length of CGI */ #define BUFLEN 32 /* max length of hostname:port */ #define VALID_WINDDIR 0x01 #define VALID_WINDSPD 0x02 #define VALID_WINDGST 0x04 #define VALID_TEMP 0x08 #define VALID_RAIN1HR 0x10 #define VALID_RAIN24H 0x20 #define VALID_HUMIDITY 0x40 #define VALID_AIRPRESS 0x80 #define VALID_RAINTOT 0x100 #define MTPS2MPH 2.2369 #define DEGC2DEGF 1.8 #define MM2IN100TH 3.937 #define INHG2HPA10TH 338.638 #define OUTDOOR_SENSOR 1 //---From the static table "mfield", which really should be dynamically read here--- // (but then I couldn't use a switch statement) #define TEMPERATURE 0 #define TEMPERATURE_MIN 1 #define TEMPERATURE_MAX 2 #define HUMIDITY 10 #define HUMIDITY_MIN 11 #define HUMIDITY_MAX 12 #define WETNESS 20 #define WETNESS_MIN 21 #define WETNESS_MAX 22 #define AIR_PRESSURE 30 #define AIR_PRESSURE_MIN 31 #define AIR_PRESSURE_MAX 32 #define SOLAR 40 #define UV 41 #define RAIN 50 // note: "51" is really rain total #define RAIN_PER_DAY 51 #define RAIN_PER_HOUR 52 #define WIND_SPEED 60 #define WIND_DIRECTION 61 #define WIND_GUST 62 #define WIND_X 63 #define WIND_Y 64 #define MOISTURE 70 #define WATERLEVEL 71 #define WATERLEVEL_MIN 72 #define WATERLEVEL_MAX 73 #define BATTERY 110 #define TRANSMITTER 111 #define DURATION 120 #define SAMPLES 121 struct dbinfo { char user[30]; char pswrd[15]; char name[30]; } db; char *progname; char *query; int *current = 0; int opt; MYSQL mysql; // Yeah, globals... MYSQL_RES *result; MYSQL_ROW row; char last_timestamp[20]; int debug_level; char wxAPRShost[BUFLEN]; int wxAPRSport = PORT; int outdoor_instr = OUTDOOR_SENSOR; /****************************************************************** 1/4/2003 Usage brief *******************************************************************/ void usage(int ret) { if (query) { printf("Content-type: text/plain\nStatus: 200\n\n"); } printf("usage: %s [options] \n",progname); printf("VERSION: %s\n",VERSION); printf(" -h --help show this help and exit\n"); printf(" -v --verbose debugging info --> stderr\n"); printf(" -c --cport [port#] IP port for data output\n"); printf(" -u --user [database user] username for mysql - default meteo\n"); printf(" -p --password [db passwd] password for mysql - default none\n"); printf(" -b --database [database] database name - default meteo\n"); printf(" -n --nodaemon do not run as daemon\n"); printf(" -r --repeat keep running\n"); printf("options may be uniquely abbreviated; units are as defined in APRS\n"); printf("Specification 1.0.1 for positionless weather data (English/hPa).\n"); exit(ret); } /****************************************************************** 1/2/2003 Make an APRS string out of WX data *******************************************************************/ int APRS_str(char *APRS_buf, double winddir, double windspeed, double windgust, double temp, double rain1hr, double rain24h, double raintot, double humidity, double airpressure, unsigned int valid_data_flgs, int Metric_Data) { int intval; char pbuf[10]; if (APRS_buf == NULL) { if (debug_level & 1) { fprintf(stderr,"err: Null string buffer for APRS string.\n"); } return 0; // Ooo!! *****Nasty Bad Exit Point Here**** } if (valid_data_flgs & VALID_WINDDIR) { intval = (winddir + 0.5); // rounding to whole degrees if (intval > 360) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction > 360\n"); } sprintf(APRS_buf, "c..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction negative\n"); } sprintf(APRS_buf, "c..."); } else { sprintf(APRS_buf, "c%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind direction flagged as invalid\n"); } sprintf(APRS_buf, "c..."); } if (valid_data_flgs & VALID_WINDSPD) { if (Metric_Data) { intval = (windspeed*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windspeed + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind speed > 600 MPH\n"); } sprintf(pbuf, "s..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "s..."); } else { sprintf(pbuf, "s%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "s..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDGST) { if (Metric_Data) { intval = (windgust*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windgust + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind gust > 600 MPH\n"); } sprintf(pbuf, "g..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "g..."); } else { sprintf(pbuf, "g%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind gust flagged as invalid\n"); } sprintf(pbuf, "g..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_TEMP) { if (Metric_Data) { intval = ((temp)*DEGC2DEGF + 0.5)+32; // converting & rounding to whole Deg F } else { intval = (temp + 0.5); // rounding to whole Deg F } if (intval > 200) // Let's be reasonable here - boiling? { if (debug_level & 1) { fprintf(stderr,"err: Temperature > 200 Deg F\n"); } sprintf(pbuf, "t..."); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Temperature < -99 Deg F\n"); } sprintf(pbuf, "t..."); } else { if (intval < 0) { sprintf(pbuf,"t%0.2d",intval); } else { sprintf(pbuf, "t%0.3d", intval); } } } else { if (debug_level & 1) { fprintf(stderr,"info: Temperature flagged as invalid\n"); } sprintf(pbuf, "t..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN1HR) { if (Metric_Data) { intval = ((rain1hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain1hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // 10 in/hr? Garden Hose -> rain gauge? { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr > 9.99 inch\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "r%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN24H) { if (Metric_Data) { intval = ((rain24h)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain24h*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain in 24 hours { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/24Hr > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "p999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "p%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/24Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_HUMIDITY) { intval = (humidity + 0.5); // rounding to whole percent if (intval > 100) // Unlike the space shuttle engines, 100 % is max { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported > 100%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 1) { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported < 1%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { if (intval == 100) // Report 100% as 'h00' { intval = 0; } sprintf(pbuf, "h%0.2d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Humidity flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_AIRPRESS) { if (Metric_Data) { intval = (airpressure*10.0 + 0.5); // rounding to whole tenth of a hPa } else { intval = (airpressure*INHG2HPA10TH + 0.5); // convering In-Hg to 1/10 hPa and rounding } if (intval > 20000) //two atmospheres - about 29 PSIA { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported > 2 Atmospheres%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported negative%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "b%0.5d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Air Pressure flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); // NOW THIS MAKES THE STRING NO LONGER A VALID APRS WX REPORT, but // we don't care: Xastir does NOT just transmit this string, it parses it // and re-recreates the correct string to transmit. We do this because // APRS doesn't have a "total rain" string in its weather report, but // Xastir likes to have that value around. if (valid_data_flgs & VALID_RAINTOT) { if (Metric_Data) { intval = ((raintot)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (raintot*100.0 + 0.5); // rounding to whole 1/100 inch } // Can't handle greater than 99.99 inches of total rain if (intval > 9999) { if (debug_level & 1) { fprintf(stderr,"err: total Rainfall > 99.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "T9999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: total Rainfall negative\n"); } sprintf(pbuf, "\0\0\0\0\0"); } else { sprintf(pbuf, "T%0.4d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: total Rainfall flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0\0"); } strcat(APRS_buf,pbuf); strcat(APRS_buf,"xDvs\n"); // add X aprs and LaCrosse WX station ID's and if (debug_level & 1) { fprintf(stderr,"\ninfo: APRS Version of WX - %s\n\n",APRS_buf); } return strlen(APRS_buf); } /****************************************************************** 1/2/2003 Get the latest set of Weather Data from the Data Base *******************************************************************/ int Get_Latest_WX( double *winddir, double *windspeed, double *windgust, double *temp, double *rain1hr, double *rain24h, double *raintot, double *humidity, double *airpressure, unsigned int *valid_data_flgs, int *Metric_Data) { char query_buffer[160]; int nrows, item_count; int nfields; // Find latest, see if it's new to us // --new to us is a simple timestamp follower, so upon startup // it will always read one set of data, assuming any exists if (mysql_query(&mysql, "SELECT MAX(timestamp) from weather")) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if (!(result = mysql_store_result(&mysql))) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if (mysql_num_rows(result) != 1 ) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: number of results %d\n", mysql_num_rows(result)); } // release query buffer mysql_free_result(result); return 0; } row = mysql_fetch_row(result); if ( row[0] == NULL ) { if (debug_level & 1) { fprintf(stderr,"err: NULL result for timestamp query\n"); } // release query buffer mysql_free_result(result); return 0; } // if no new data. exit with negative status if (!strncmp(last_timestamp, row[0], 14)) { if (debug_level & 1) { fprintf(stderr,"info: No new weather data recorded - exiting: negative data\n"); } // release query buffer mysql_free_result(result); return -1; } strcpy(last_timestamp, row[0]); // For next pass & following query if ( debug_level & 1) { fprintf(stdout,"Timestamp: %s\n",last_timestamp); } // release query buffer mysql_free_result(result); sprintf(query_buffer,"SELECT wind_angle, windspeed, temp_out, rain_1h, rain_24h, rel_hum_out, rel_pressure, rain_total FROM weather WHERE timestamp = %s", last_timestamp); if (mysql_query(&mysql, query_buffer)) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); } return 0; } if (!(result = mysql_store_result(&mysql))) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if ((nrows=mysql_num_rows(result)) < 1 ) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: number of results %d\n",nrows); } // release query buffer mysql_free_result(result); return 0; } else { nfields=mysql_num_fields(result); row=mysql_fetch_row(result); if (debug_level & 1) { fprintf(stderr,"info: Latest Weather Data query: number of types of readings %d\n",nfields); } } *valid_data_flgs = 0; item_count = 0; //WIND_DIRECTION : *winddir = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDDIR; item_count++; if (debug_level & 1) { fprintf(stderr,"wind direction %f\n ",*winddir); } //case WIND_SPEED : *windspeed = strtod(row[1],NULL); *windspeed = *windspeed * 1.15077945; // Convert from knots to mph *valid_data_flgs |= VALID_WINDSPD; item_count++; if (debug_level & 1) { fprintf(stderr,"wind speed %f\n ",*windspeed); } //case WIND_GUST : *windgust = strtod("0",NULL); //*valid_data_flgs |= VALID_WINDGST; No gust information from open2300 item_count++; if (debug_level & 1) { fprintf(stderr,"wind gust speed %f\n ",*windgust); } //case TEMPERATURE : *temp = strtod(row[2],NULL); *valid_data_flgs |= VALID_TEMP; item_count++; if (debug_level & 1) { fprintf(stderr,"temperature %f\n ",*temp); } //case RAIN_PER_HOUR : *rain1hr = strtod(row[3],NULL); *valid_data_flgs |= VALID_RAIN1HR; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall for 1 hr %f\n ",*rain1hr); } //case RAIN_PER_DAY : *rain24h = strtod(row[4],NULL); *valid_data_flgs |= VALID_RAIN24H; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall for 24 hrs %f\n ",*rain24h); } //case HUMIDITY : *humidity = strtod(row[5],NULL); *valid_data_flgs |= VALID_HUMIDITY; item_count++; if (debug_level & 1) { fprintf(stderr,"humidity %f\n ",*humidity); } //case AIR_PRESSURE : *airpressure = strtod(row[6],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } //case RAIN_TOTAL *raintot = strtod(row[7],NULL); *valid_data_flgs |= VALID_RAINTOT; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall since reset %f\n ",*raintot); } *Metric_Data = 0; // My station reports F, knots and inHG // release query buffer & close connection mysql_free_result(result); if (debug_level & 1) { fprintf(stderr,"info: success - Weather Data number of reading types %d\n", item_count); } return item_count; } /****************************************************************** 1/5/2003 SIGPIPE signal handler *******************************************************************/ void pipe_handler(int sig) /* */ { signal(SIGPIPE, SIG_IGN); if (sig == SIGPIPE) // client went bye-bye { shutdown(*current, 2); close(*current); *current = -1; if (debug_level & 1) { fprintf(stderr, "info: %s - TCP client timed out", progname); } } } /****************************************************************** 1/5/2003 SIGTERM signal handler *******************************************************************/ void term_handler( int UNUSED(sig) ) /* */ { if (debug_level & 1) { fprintf(stderr, "info: %s - ordered to DIE, complying", progname); } // release query buffer & close connection mysql_free_result(result); mysql_close(&mysql); exit( 0 ); } /****************************************************************** 1/2/2003 Coordinating MAIN point *******************************************************************/ int main(int argc, char **argv) { const char *flags = "Hhvnc:u:p:d:s:r"; char WX_APRS[120]; int data_len = 0 ; double winddir; double windspeed; double windgust; double temp; double rain1hr; double rain24h; double raintot; double humidity; double airpressure; unsigned int valid_data_flgs; int Metric_Data = 0, dsts = 0; int pid, s; socklen_t clen = sizeof(struct sockaddr_in); int fd[CONNECTIONS]; int *max = 0, dly_cnt = 1; int not_a_daemon = 0, repetitive = 0, tcp_wx_port = PORT; int i, index = 0; struct sockaddr_in server, client; struct in_addr bind_address; fd_set rfds; struct timeval tv; struct option longopt[] = { {"help", 0, 0, 'h'}, {"refresh", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"user", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"cport", 1, 0, 'c'}, {"nodaemon", 0, 0, 'n'}, {0, 0, 0, 0} }; debug_level = 0; strcpy(db.user,"open2300"); // set default values for database access strcpy(db.name,"open2300"); memset(db.pswrd,0,15); mysql_init(&mysql); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } while ((opt = getopt_long(argc, argv, flags, longopt, &index)) != EOF) { switch (opt) /* parse command-line or CGI options */ { case 'r': repetitive = 1; break; case 'v': fprintf(stdout,"Verbose mode set:\n"); debug_level = 1; break; case 'u': // mysql username strncpy(db.user,(char *)optarg,30); break; case 'p': // mysql password strncpy(db.pswrd,(char *)optarg,15); break; case 'd': // mysql database name strncpy(db.name,(char *)optarg,30); break; case 'n': /* do not fork and become a daemon */ not_a_daemon = 1; break; case 'c': /* port to use */ tcp_wx_port = strtol(optarg, NULL, 0); break; case '?': case 'h': case 'H': usage(0); break; default : usage(1); } } if (debug_level & 1) { fprintf(stdout,"Starting..."); if (repetitive) { fprintf(stdout, " forever "); } else { fprintf(stdout, " one pass only "); } fprintf(stdout," with database user=%s, password=%s, for database=%s\n", db.user, db.pswrd, db.name); if (not_a_daemon) { fprintf(stdout," as a program "); } else { fprintf(stdout," as a daemon "); } fprintf(stdout, " using TCP port %d\n",tcp_wx_port); } // Data base connection if (!(mysql_real_connect(&mysql, "localhost", db.user, db.pswrd, db.name, 0, NULL, 0))) { if (debug_level & 1) { fprintf(stderr,"err: Data Base connect for user:%s to database:%s failed - exiting: \n\t%s\n", db.user, db.name, mysql_error(&mysql)); } exit(9); } server.sin_family = AF_INET; bind_address.s_addr = htonl(INADDR_ANY); server.sin_addr = bind_address; server.sin_port = htons(tcp_wx_port); if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - no socket", progname); } exit(10); } /* / April 2001 Minor change to allow quick * (re)start of daemon or client while there are pending * conncections during the quit. To avoid address/port in use * error. */ i = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - setsockopt", progname); } } if (bind(s, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - cannot bind to socket", progname); } exit(11); } if (listen(s, CONNECTIONS) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - listen", progname); } exit(12); } if (debug_level & 1) { fprintf(stdout,"Sockets UP.\n"); } umask(0022); for (i = 0; i < CONNECTIONS; i++) { fd[i] = -1; } tv.tv_sec = 0; tv.tv_usec = 0; if (!not_a_daemon) /* setup has worked; now become a daemon? */ { if ((pid = fork()) == -1) { syslog(LOG_ERR, "can't fork() to become daemon: %m"); exit(20); } else if (pid) { exit (0); } setsid(); for (i = 0; i < NOFILE; i++) { if ( i != s) { close(i); } } } /* catch signals to close the database connection */ signal( SIGTERM, term_handler );/* termination */ #if defined(SIGPWR) /* SIGPWR is linux centric */ signal( SIGPWR, term_handler ); /* power failure */ #endif if (debug_level & 1) { fprintf(stdout,"Main Loop...\n"); } dly_cnt = 1; //N0VH, change back to 1 do { if (!(dly_cnt--)) { dly_cnt = 25; // Every 'dly_cnt' passes check for WX data update if ((dsts = Get_Latest_WX(&winddir,&windspeed,&windgust, &temp,&rain1hr,&rain24h,&raintot, &humidity,&airpressure, &valid_data_flgs,&Metric_Data)) !=0 ) { if ( dsts > 0 ) { data_len = APRS_str(WX_APRS, winddir,windspeed,windgust, temp, rain1hr, rain24h, raintot, humidity, airpressure, valid_data_flgs, Metric_Data); if (!data_len) { if (debug_level & 1) { fprintf(stderr, "err: WX info formatting problem!"); } exit(13); } } } else { exit(dsts); } } FD_ZERO(&rfds); FD_SET(s, &rfds); if (select(s + 1, &rfds, NULL, NULL, &tv) > 0) { for (current = fd; (*current > 0) && (current < fd + CONNECTIONS - 1); current++); if (current > max) { max = current; } if ((*current = accept(s, (struct sockaddr *)&client, &clen)) != -1) { write(*current, WX_APRS, data_len); } } if (dly_cnt == 25) { if (debug_level & 1) { fprintf(stdout,"Updating clients:"); } for (current = fd; current <=max; current++) { if (*current > 0) // active socket { if (debug_level & 1) { fprintf(stdout," #"); } signal(SIGPIPE, pipe_handler); write(*current, WX_APRS, data_len); } if (debug_level & 1) { fprintf(stdout," done\n"); } } } sleep(1); // } while (repetitive); mysql_close(&mysql); if (debug_level & 1) { fprintf(stdout,"Exiting normally.\n"); } exit(0); } Xastir-Release-2.2.2/LaCrosse/weatherdump.sql000066400000000000000000000021471501463444000211330ustar00rootroot00000000000000-- MySQL dump 8.23 -- -- Host: localhost Database: open2300 --------------------------------------------------------- -- Server version 3.23.58-log -- -- Table structure for table `weather` -- CREATE TABLE weather ( timestamp bigint(14) NOT NULL default '0', rec_date date NOT NULL default '0000-00-00', rec_time time NOT NULL default '00:00:00', temp_in decimal(4,1) NOT NULL default '0.0', temp_out decimal(4,1) NOT NULL default '0.0', dewpoint decimal(4,1) NOT NULL default '0.0', rel_hum_in tinyint(3) NOT NULL default '0', rel_hum_out tinyint(3) NOT NULL default '0', windspeed decimal(4,1) NOT NULL default '0.0', wind_angle decimal(4,1) NOT NULL default '0.0', wind_direction char(3) NOT NULL default '', wind_chill decimal(4,1) NOT NULL default '0.0', rain_1h decimal(4,2) NOT NULL default '0.00', rain_24h decimal(4,2) NOT NULL default '0.00', rain_total decimal(5,2) NOT NULL default '0.00', rel_pressure decimal(4,2) NOT NULL default '0.00', tendency varchar(7) NOT NULL default '', forecast varchar(6) NOT NULL default '', UNIQUE KEY timestamp (timestamp) ) TYPE=MyISAM; Xastir-Release-2.2.2/Makefile.am000066400000000000000000000063641501463444000164130ustar00rootroot00000000000000 # # Copyright (C) 2000-2023 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src config help scripts symbols callpass # DISTCLEANFILES = EXTRA_DIST = xastir.spec.in xastir.spec xastir-min.spec.in xastir-min.spec config.guess config.sub install-sh \ missing placeholder FAQ LICENSE README README.GIT \ README.CYGWIN CONTRIBUTING.md \ README.MAPS README.OSM_maps README.sudo testdbfawk.1 \ DEBUG_LEVELS bootstrap.sh INSTALL.md UPGRADE callpass.1 xastir.1 xastir_udp_client.1 \ worldhi.map \ Davis LaCrosse \ OSM_template \ CC_OpenStreetMap_logo.png CC_OpenStreetMap_txt.png \ COPYING COPYING.LIB.LESSTIF AUTHORS MAINTAINERCLEANFILES = configure aclocal.m4 Makefile.in Makefile \ config.guess config.sub install-sh missing mkinstalldirs \ xastir.spec xastir-min.spec countydir=${pkgdatadir}/Counties county_DATA=placeholder fccdir=${pkgdatadir}/fcc fcc_DATA=placeholder gnisdir=${pkgdatadir}/GNIS gnis_DATA=placeholder mapdir=${pkgdatadir}/maps map_DATA=worldhi.map CC_OpenStreetMap_logo.png CC_OpenStreetMap_txt.png onlinedir=${pkgdatadir}/maps/Online online_DATA=OSM_tiled_cycle.geo OSM_tiled_mapnik.geo \ OSM_tiled_fosm.geo USTigermap.geo USTigermapBorders.geo nationalmapdir=${pkgdatadir}/maps/Online/nationalmap.gov nationalmap_DATA=WMS_USGS_Hydrography.geo WMS_USGS_ImageryOnly.geo \ WMS_USGS_ImageryTopo.geo WMS_USGS_ShadedReliefOnly.geo \ WMS_USGS_Topo.geo geogratismapdir=${pkgdatadir}/maps/Online/geogratis.gc.ca geogratismap_DATA=National.geo Regional.geo Sub_national.geo Sub_regional.geo gpsdir=${pkgdatadir}/maps/GPS gps_DATA=placeholder sounddir=${pkgdatadir}/sounds sound_DATA=placeholder docdir=${prefix}/share/doc/xastir doc_DATA=AUTHORS FAQ ChangeLog LICENSE README README.GIT README.CYGWIN \ README.MAPS README.sudo COPYING INSTALL.md UPGRADE \ README.OSM_maps CONTRIBUTING.md \ COPYING.LIB.LESSTIF # It'd be nice to remove the directory and contents at # "${pkgdatadir}/doc" then install a symlink called "doc" there pointing # to "${prefix}/share/doc/xastir/". The new location for the # documentation is FHS compliant. install-exec-hook: -rm -rf $(DESTDIR)${pkgdatadir}/doc install-data-hook: cd $(DESTDIR)$(mapdir) && \ rm -f CC_OpenStreetMap.png && \ $(LN_S) CC_OpenStreetMap_logo.png CC_OpenStreetMap.png mandir=${prefix}/share/man man_MANS=xastir.1 callpass.1 xastir_udp_client.1 testdbfawk.1 # Use tiles for these maps OSM_tiled_cycle.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL http://tile.opencyclemap.org/cycle/!' \ -e 's/-STYLE/-cycle/' \ < $(top_srcdir)/OSM_template >$@ OSM_tiled_mapnik.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL http://tile.openstreetmap.org/!' \ -e 's/-STYLE/-mapnik/' \ < $(top_srcdir)/OSM_template >$@ OSM_tiled_fosm.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL http://map.fosm.org/default/!' \ -e 's/-STYLE/-fosm/' \ < $(top_srcdir)/OSM_template >$@ ChangeLog:: Xastir-Release-2.2.2/NEWS000066400000000000000000000017751501463444000150570ustar00rootroot00000000000000 News - Updated 29 April 2001 ------------------------------------------------------------------------ What's new, first read the following documents: INSTALL README ChangeLog All of these documents combined will fill you in on the latest changes to xastir in version 0.4.x. A lot of things have changed in this version so at a minimum read the ChangeLog text file. ChangeLog shows what's been added and fixed along the way. This version includes a "first try" at using the GNU Autotools for configuration. These scripts have not been thoroughly tested on all platforms. Any feedback is actively solicited. This version also includes several additional directories added in preparation for the implementation of GNU internationalization routines. CAUTION: 1. Before you start Xastir for the first time BACKUP your data files if this is an upgrade from a previous version. 2. DON'T USE YOUR OLD CONFIG FILE.. MAKE A NEW ONE......... Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/NWS-TEST.log000066400000000000000000000115131501463444000162760ustar00rootroot00000000000000 # Test log file for weather alerts. Bring this file into Xastir via # the Open Log File option and within 30-60 seconds you should see # the alerts light up. All except the first one listed here which # has a matching cancel: See that alert as cancelled in the # View->Weather Alerts dialog. # # If using this file during the early part of a month you must # change the date stamp ("30" here) to numbers closer to your # current date but into the future a bit. Note that these are UTC # date/times. You must be within XX days (mod 31) to see the # alerts, else Xastir assumes the date was from the previous month # and discards them. The alert must be within 0-10 days into the # future (UTC) in order to be displayed, per # util.c:time_from_aprsstring() # # Note: If commenting out sentences you'll need to use more than # just one a '#' mark. "####" seems to work fine (4 chars). # Test individual alerts, with only one area lit up per message. # Alert level tests, color specifies alert level: # ----------------------------------------------- # First we do an active alert and a cancel. This should not display # on the map, but CANCL messages show in the View WX Alerts dialog. # If the alert did show, it would be lighting up the San Juan # Islands (upper Puget Sound) in Blue. SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,WA_Z001, {OKoAB SEWWSW>APRS::NWS-CANCL:302119z,DENSE_FOG,WA_Z001, {OKoAB # # Blue "ALERT", WA, WA, lower left. SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,WA_Z020, {OKoAB # # Red "ALERT", WA, lower left. SEWWSW>APRS::NWS-WARN :302119z,DENSE_FOG,WA_Z021, {OKoAB # # Green "ALERT", WA, above Portland. "NWS- " works here also, # giving a Green alert just like "NWS-CURT ". SEWWSW>APRS::NWS-CURT :302119z,DENSE_FOG,WA_Z019, {OKoAB # # Red "ALERT", WA, along Columbia river. SEWWSW>APRS::NWS-CIVIL:302119z,DENSE_FOG,WA_Z024, {OKoAB # # K2DLS WA_Z023 no longer exists (08/25/17) # Yellow "ALERT", WA, along Columbia river. #SEWWSW>APRS::NWS-WATCH:302119z,DENSE_FOG,WA_Z023, {OKoAB # # Cyan "ALERT", WA, along Columbia river. SEWWSW>APRS::NWS-ADVIS:302119z,DENSE_FOG,WA_Z022, {OKoAB # Event type tests, embedded text changes with even type: # ------------------------------------------------------- # Blue "FLOOD", WA, lower middle. SEWWSW>APRS::NWS-TEST :302119z,FLOOD,WA_Z026, {OKoAB # # Red "SNOW", WA, bottom middle. SEWWSW>APRS::NWS-WARN :302119z,SNOW,WA_Z027, {OKoAB # # Yellow "TORNDO", WA, lower middle. SEWWSW>APRS::NWS-WATCH:302119z,TORNDO,WA_Z028, {OKoAB # # Cyan "WIND", WA, lower right. SEWWSW>APRS::NWS-ADVIS:302119z,WIND,WA_Z029, {OKoAB # # Green "WNTR STRM", WA, lower right. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,WA_Z030, {OKoAB # # Blue "WINTER WX", WA, lower right. SEWWSW>APRS::NWS-TEST :302119z,WINTER_WEATHER,WA_Z031, {OKoAB # # Red "ALERT", WA, lower right. SEWWSW>APRS::NWS-WARN :302119z,SVRTSM,WA_Z032, {OKoAB # # Green "ALERT", WA, lower right. SEWWSW>APRS::NWS-CURT :302119z,CURT,WA_Z033, {OKoAB # # "RED FLAG", Yellow/Cyan/Red respectively. WA, left edge. SEWWSW>APRS::NWS-WATCH:302119z,RED_FLAG,WA_Z650, {OKoAB SEWWSW>APRS::NWS-ADVIS:302119z,RED_FLAG,WA_Z651, {OKoAB SEWWSW>APRS::NWS-CIVIL:302119z,RED_FLAG,WA_Z652, {OKoAB # File type tests: # ---------------- # c_08au05.shp # z_06oc05.shp # Cyan "WNTR STRM", WA, upper middle. SEWWSW>APRS::NWS-ADVIS:302119z,WINTER_STORM,WA_C007, {OKoAB # # Green "WNTR STRM", WA, lower middle right. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,WA_Z034, {OKoAB # # fz20se05.shp # Red "RED FLAG", WA lower Puget Sound. SEWWSW>APRS::NWS-CIVIL:302119z,RED_FLAG,WA_Z654, {OKoAB # # mz12se05.shp # Yellow "WNTR STRM", WA, Whidbey Island. SEWWSW>APRS::NWS-WATCH:302119z,WINTER_STORM,PZ_Z134, {OKoAB # # K2DLS PZ_Z082 no longer exists (08/25/17) # oz15de04.shp # Green "WNTR STRM", WA, off west coast out in the Pacific. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,PZ_Z082, {OKoAB # # w_28de04.shp # Green "SNOW", ID & OR, around the Boise area. SEWWSW>APRS::NWS-CURT :302119z,SNOW,CW_ABOI, {OKoAB # # hz28au04.shp # Support for this filename is not implemented in Xastir. # Test multiple alerts in one packet, in WSSVR normal and compressed # format (dash/underline). # # Blue "ALERT" in OR, along coast SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,OR_Z001,OR_Z002,OR_Z003,OR_Z004,OR_Z005 {OKoAB # # This one ends up yellow because "WATCH" is found later in the # string: #//////#SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM_WATCH_C,OR_Z011,OR_Z013 {OKoAB # But this one ends up Green. #//////#SEWWSW>APRS::NWS-CURT :302119z,DENSE_FOG,OR_Z011,OR_Z013 {OKoAB # # Blue "ALERT", upper portion of Idaho SEWWSW>APRS::NWS_TEST :302119z,DENSE_FOG,IDZ1-2-3-4-5-IDZ6>9 {OKoAB # NOTES: # ------ # CANCL=C=6=orange3 # TEST=T=4=RoyalBlue # WARN=R=1=red2 # CIVIL=R=1=red2 # WATCH=Y=2=yellow2 # ADVIS=B=3=cyan2 # ?=G=5=ForestGreen # # FLOOD # SNOW # TORNDO # WIND # WINTER_STORM # WINTER_WEATHER # RED_FLAG # SVRTSM (not implemented) # ? Xastir-Release-2.2.2/National.geo000066400000000000000000000002631501463444000166100ustar00rootroot00000000000000WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=National Xastir-Release-2.2.2/OSM_template000066400000000000000000000027171501463444000166310ustar00rootroot00000000000000# # # THIS IS A TEMPLATE FILE # # Map data Copyright OpenStreetMap Contributors, CC-BY-SA # See www.openstreetmap.org and http://creativecommons.org/licenses/by-sa/2.0/ # # The string following OSMSTATICMAP-, is appended to the URL # The string is typically expected to select a layer, and possibly style # options. If not set it defaults to: # layer=osmarander # # The string following OSM_TILED_MAP-, is the name of a sub-directory in # the tile cache. It can be empty (delete the '-' too), though that is a # bad idea if multiple map styles are using the same TILE_DIR. # # Select only one of the two map types: OSMSTATICMAP or OSM_TILED_MAP # # #OSMSTATICMAP-STYLE # or #OSM_TILED_MAP-STYLE # # The url for tiled maps defaults to http://tile.openstreetmap.org/. For # static maps it defaults to http://ojw.dev.openstreetmap.org/StaticMap/ #URL tileURL # Tile extension defaults to png #TILE_EXT png #ZOOM_LEVEL_MIN 0 #ZOOM_LEVEL_MAX 18 # The tile cache can be changed from the default (~/.xastir/OSMtiles) by # setting the following variable. If path does not begin with a '/' then # it will be relative to ~/.xastir/. # #TILE_DIR OSMtiles # When defined: # OSM_OPTIMIZE_KEY will change the map scaling to the nearest OSM zoom level. # OSM_REPORT_SCALE_KEY will report the present, scale_x, scale_y, # and OSM zoom level, but only for debug level 512 (-v 512) # # The values are X KeySym values. # 65473 = F4 # 65474 = F5 OSM_OPTIMIZE_KEY 65473 OSM_REPORT_SCALE_KEY 65474 Xastir-Release-2.2.2/README000066400000000000000000000237211501463444000152330ustar00rootroot00000000000000# README ------------------------------------------------------------------------ Please at least SKIM this document before asking questions. In fact, READ IT if you've never successfully set up Xastir before. PLEASE! READ IT! If you haven't read this file, and ask for help expect to be told to READ the README file first! or RTFM :) Contents: 0. Important notice 1. What is Xastir? 2. How do I get Xastir & Git usage 3. Quick startup 4. Upgrading 5. Identification notes 6. OS-specific notes 7. Gating weather alerts 8. Boring legal stuff 9. Mailing list 10. Documentation 11. Obtaining help ------------------------------------------------------------------------ 0. NOTICE Please read this file carefully before trying to set up Xastir. This software was developed to be used by licensed amateur radio operators. You are responsible for any information transmitted or propagated on any network. 1. WHAT IS XASTIR? Xastir is an open-source project to create a free X11 graphical APRS(tm) client. APRS(tm) use amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. Xastir currently runs under several flavors of Linux and BSD Unix. A few people are running Xastir on Solaris Unix, FreeBSD, Lindows and Mac OS X, but there may be small changes necessary in order to get Xastir to configure/compile on some systems. There are a few notes below which may help in this task. Most of the developers use Linux which makes it the best supported platform at the moment. Xastir is an open-source project: Most sources, documentation, and binaries are available under the GPL license, with a few modules available under other open-source or public domain licenses. More information on Xastir can be found here: * http://xastir.org * http://github.com/Xastir including the latest releases, Git access (lets you download the latest developers' code), and information on how to join Xastir mailing lists. Note that you must be subscribed in order to post to the mailing lists. SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used. Thanks to Tony and Steve for that contribution! -- The Xastir Group. 2. HOW TO GET XASTIR Xastir is currently developed at You can get the latest version of Xastir from there. You might try for help and information, particularly the Xastir mailing list (listed near the bottom of the page). * Git USAGE Obtain the *very latest* version of Xastir under development by using Git. See the file README.GIT for more details. * Release version tarballs You can get the latest packaged release source code without git at https://github.com/Xastir/Xastir/releases. Be warned that packaged source tarballs may be quite old and not representative of the current state of the project. We highly recommend not using this method unless you have a specific reason to stick to official releases. 3. QUICK STARTUP See README.Getting-Started for a relatively quick overview of how to build and use Xastir. Check the Xastir wiki (http://xastir.org) for OS-specific guidance for building Xastir on your system. WINDOWS USERS: Please refer to the "README.CYGWIN" file for specific instructions. See the 'INSTALL' file in the Xastir source tree for detailed information about configure. 4. UPGRADING Upgrading Xastir that has been built from a recent Git clone is as simple as running "git pull" in the source tree and recompiling. 5. IDENTIFICATION NOTES Packet radio modes, by their very nature, typically identify themselves with every transmission. Xastir has a few features targeted to people who used Xastir in demonstrations and other broadcasts where Xastir itself is used over radio. Xastir can auto-ID via voice if Festival is compiled in and/or via a message splashed across the screen. It does this identification every 9.5 minutes if enabled. These identification modes were designed for broadcasting Xastir across fast-scan television (for events perhaps). Set the "ATV_SCREEN_ID" variable to 1 to enable the screen message, and "SPEAK_ID" variable to 1 to enable festival to speak the message. These variables are in the ~/.xastir/config/xastir.cnf file. 6. OS SPECIFIC NOTES [The OS-specific notes that were here were horribly outdated and not maintained. That text has been removed. Please see the Xastir wiki at http://xastir.org in the "Installation Notes" section for OS-specific build guidance.] 7. GATING WEATHER ALERTS, STATIONS, OBJECTS/ITEMS TO RF ## Gating NWS Weather Alerts to RF: If you wish to gate NWS weather alerts from the Internet onto RF, you'll need to create a text file in the users directory as ~/.xastir/data/nws-stations.txt List each NWS station that you would like to transmit via RF. Wildcards are implied for lengths of 3 or greater. Here's what an example file looks like: # # Seattle, WA SEANPW # # Portland, OR (any alert type) PDX # # Pendleton, OR PDTNPW # # Medford, OR MFRNPW # All text should start at the beginning of the line. Once that file is in place, you'll need to hook up to at least one Internet server that is feeding you the weather alerts. You'll also need to have at least one RF interface up and running with transmit enabled on that interface. Make sure that "Interfaces->Disable Transmit: All" is not selected. You should now be gating NWS weather messages to RF. Turn on igate logging and look at that log file to view what you're sending out via RF. Don't forget to turn off logging or set up auto-rollover of the log files, else your hard drive might fill up with logging info. Auto-rollover of log files is typically accomplished via CRON. ## Gating Stations, Objects/Items to RF: The latest code also allows gating packets from specific stations to RF using the above method (except object/item packets). You can also gate objects/items to RF by name. The same wildcarding rules apply as listed above. Callsigns or object/item names listed in this file are case-insensitive, so they'll match any case in received packets. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.aprs.org/aprs-jota.txt 8. BORING LEGAL STUFF Xastir is Copyright by Frank Giannandrea. Xastir is distributed according to the GNU General Public License. There should be a copy of this license in the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As of Xastir 0.4.0 all changes made by the Xastir development team to the Xastir source code and any related files are Copyright (C) 2000-2023 The Xastir Group. The source code will still be distributed according to the GNU General Public License as Frank Giannandrea did in the past. There is no warranty, implied or whatever. You use this software at your own risk, no matter what purpose you put it to. You didn't pay for it, so don't expect magic. 9. MAILING LIST There are currently a couple of mailing lists about Xastir. xastir@xastir.org is the one relevant for most users. The xastir@xastir.org mail-list is dedicated to Bug reports, technical questions, your thoughts or suggestions on new features being added to Xastir, things that should be removed or fixed, amazing problems that even stump the guru's, etc... are what we want to see here. You must be subscribed to the list in order to post messages. To subscribe to the Xastir mailing list, send email to: xastir-request@xastir.org In the body of the message, put "subscribe xastir"; or go to http://xastir.org and click on "XASTIR MAILING LISTS" (in the "Resources" section near the bottom) to subscribe. ### DO NOT SEND FRANK EMAIL ABOUT XASTIR ### Frank is no longer developing the Xastir code (although he does put a word in every now and then) so don't bother e-mailing him. If you have a serious problem, email the Xastir mailing list and it will get to the coders. Please, before posting to this list, see what things are like, and when you do post, read over your post for readability, spelling, and grammar mistakes. Obviously, we're all human (or are we?) and we all make mistakes (heck, look at this document! ;). Open discussion and debate is integral to change and progress. Don't flame others over mere form (grammar and spelling), or even substantive issues either for that matter. Please read and follow the mailing list rules. A second mailing list, xastir-dev@xastir.org is intended for developer's discussion. 10. DOCUMENTATION We're trying to get the documentation up to date. If you feel that anything is missing here, or that anything should be added etc, please email xastir@xastir.org about it, thank you. 11. OBTAINING HELP Please read the file FAQ, and make sure you've followed any relevant instructions in INSTALL. If the problem still exists, feel free to ask on the Xastir mailing-list, as described above. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/README.CYGWIN000066400000000000000000000434501501463444000162330ustar00rootroot00000000000000November 2017 Update This document offers a method of running Xastir on Windows using the Cygwin environment. Cygwin is a large collection of GNU and Open Source tools which provide functionality similar to a Linux distribution on Windows. Microsoft now offers their own Linux solution, using an Ubuntu Linux framework that runs under Windows. However, you must be running a 64 bit version of Windows 10 to use the Microsoft option. More information may be found in the Xastir Wiki at: http://xastir.org/index.php/HowTo:Win10 ------------------------------------ Installing Xastir on Windows/Cygwin: ------------------------------------ These directions were most recently validated on Windows 10, both 32 and 64 bit, with Cygwin version 2.882. SPACES IN FILENAMES/USERNAMES: Cygwin specifically, and Unix boxes in general, don't much like spaces in filenames, directories, or login names. Any of these may cause you headaches while playing with Cygwin. Create a new login that doesn't have spaces and log in as that user before installing Cygwin, and whenever you intend to run Cygwin/Xastir. It's very likely that Xastir won't work for you if you use a login that has spaces embedded in it. For additional info, see this link: https://cygwin.com/faq/faq.html#faq.using.filename-spaces The following steps direct you through installing Cygwin, Xastir, and a few optional map libraries that Xastir can use. Note that in most of the places below where the directions state to type commands, this must be done from within a Cygwin BASH shell, not a DOS window. Where you are asked to edit files, it's best to use Wordpad instead of Notepad, as Notepad doesn't do nice things to Unix-format files. Cygwin now allows you to have Xwindows apps and Windows apps all on the screen and visible at the same time! The instructions here set it up in that manner, so you can have Xastir as just another app on your Windows desktop. Please subscribe to the "xastir" mailing list at "http://xastir.org". There are lots of helpful people there that can aid you in installing/running Xastir. You must be subscribed in order to post messages there. [ ] Step 1) Install Cygwin, a free download. [ ] Step 1a) Go to https://cygwin.com/install.html with your web browser. Choose the 64 bit or 32 bit version as appropriate for your Windows operating system. This will download the Cygwin network installer program onto your computer. Remember where you decide to put this program. I put mine in my user "Downloads" folder. Note: It will be beneficial to re-run the Cygwin network installer from time to time in order to keep Cygwin up to date. Each time you run it you'll update any packages that have been changed since you last ran it. [ ] Step 1b) Find the "setup-x86.exe" program (32 bit) or the "setup-x86_64" (64 bit) program. Make note of which version you are using. Open a Windows Command Prompt as the Administrator and change directory to the directory where you just saved the setup program. If you have setup-x86.exe (32 bit), run this command to download and install the needed Cygwin components: setup-x86.exe --quiet-mode --packages autoconf,automake,binutils,^ db,font-util,gcc-core,git,GraphicsMagick,gv,libcurl-devel,libdb-devel,^ libgeotiff,libgeotiff-devel,libjasper-devel,libjbig-devel,^ liblcms2-devel,libpcre-devel,libshp-devel,libtiff-devel,libwebp-devel,^ libwmf-devel,libxml2-devel,libGraphicsMagick-devel,libX11-devel,^ libXext-devel,libXm-devel,make,nano,sox,unzip,wget,xfontsel,xinit,^ xorg-x11-fonts-Type1,xorg-x11-fonts-dpi100,libbz2-devel,libproj-devel If you have setup-x86_64.exe (64 bit), run this command to download and install the needed Cygwin components: setup-x86_64.exe --quiet-mode --packages autoconf,automake,binutils,^ db,font-util,gcc-core,git,GraphicsMagick,gv,libcurl-devel,libdb-devel,^ libgeotiff,libgeotiff-devel,libjasper-devel,libjbig-devel,^ liblcms2-devel,libpcre-devel,libshp-devel,libtiff-devel,libwebp-devel,^ libwmf-devel,libxml2-devel,libGraphicsMagick-devel,libX11-devel,^ libXext-devel,libXm-devel,make,nano,sox,unzip,wget,xfontsel,xinit,^ xorg-x11-fonts-Type1,xorg-x11-fonts-dpi100,libbz2-devel,libproj-devel [ ] Step 1c) Choose a Download Site and then click Next. [ ] Step 1d) The Select Packages screen will display. You don't have to actually select any, the right packages have been selected for you. But, if you wish, you can review the selection and make changes if you know what you are doing. Click Next and the Resolving Dependencies screen will display. [ ] Step 1e) Click Next and the packages will get downloaded and installed. Repeat the above if you have network difficulties, until the install succeeds completely. In addition to the base packages, the following packages required to compile and run Xastir, along with their dependencies, will be installed. [ ] autoconf [ ] automake [ ] binutils [ ] db [ ] font-util [ ] gcc-core [ ] git [ ] GraphicsMagick [ ] gv [ ] gzip [ ] libbz2-devel [ ] libcurl-devel [ ] libdb-devel [ ] libgeotiff [ ] libgeotiff-devel [ ] libjasper-devel [ ] libjbig-devel [ ] liblcms2-devel [ ] libpcre-devel [ ] libproj-devel [ ] libshp-devel [ ] libtiff-devel [ ] libwebp-devel [ ] libwmf-devel [ ] libxml2-devel [ ] libGraphicsMagick-devel [ ] libX11-devel [ ] libXext-devel [ ] libXm-devel [ ] make [ ] nano (a windows-style text editor, optional) [ ] patch [ ] sox [ ] unzip [ ] wget (Optional: Can use libcurl instead) [ ] xfontsel [ ] xinit [ ] xorg-x11-fonts-Type1 [ ] xorg-x11-fonts-dpi100 [ ] Step 1f) You may receive a Postinstall script errors screen. It is not necessarily an issue, but you are advised to check the contents of /cygwin/var/log/setup.log.full or /cygwin64/var/log/setup.log.full. Click Next to proceed. [ ] Step 1g) At the end of the install it'll ask you if you wish to create desktop icons and menu entries. Definitely select these! It doesn't mean that Cygwin will start automatically each time you reboot your computer or login (it doesn't start automatically). It _does_ mean that you'll have an icon to click on manually to get things going. This will create a Black/Green Cygwin icon on the desktop and a menu entry so that you can start Cygwin through the menu system as well. [ ] Step 1h) Click "Finish". Cygwin is now installed. One more pop-up informs you Cygwin has been installed. Sometimes this last dialog gets hidden behind other windows, and it does seem to need OK clicked to complete the installation. Click the OK button on that last dialog to _really_ complete the installation. The Command Prompt in the window will not return. When it prints "Ending Cygwin install" it is done. You can press enter and the prompt will reappear. The Black/Green Cygwin icon will start up a BASH window, without starting up Xwindows. Think of it as being similar to a DOS window, but with a lot more power. It understands Unix commands though, not DOS commands. [ ] Note: I've had the Cygwin network install fail before during the downloading stage without informing me in any recognizable manner. You might want to re-do step 1 to make sure nothing further gets downloaded/installed. Once you get to that point, Step 1 is complete. [ ] Step 2) Start the X Server: Click on the Windows menu icon or press the Windows button. Look for the Cygwin-X program group and click on the XWin Server. It will create a green "X" icon in the system tray. Right-click on green "X" icon in the system tray. Select Systems Tools, and then Cygwin Terminal. [ ] Step 3) Test Cygwin and create startup shortcuts: You should get a shell window that looks very much like a DOS window. It's a BASH shell window and understands Unix commands instead of DOS commands. Once you've gotten to this stage, you now have Cygwin and Xwindows installed and operational. Next we go after Xastir itself. [ ] Step 4) Download Xastir sources. Use the Cygwin Terminal window that you just started. Type the three lines below into the shell exactly as shown. mkdir git cd git git clone http://github.com/Xastir/Xastir The end result when it succeeds will be a new directory "~\git\Xastir\" which contains all of the Xastir source code. You can type "ls Xastir" (that's lower-case LS) to see the file listing. Side Note: Here's the coolest thing about Git: Once you've done this initial source-code download, you'll never have to do the whole Xastir download again. You'll just go into the "git/xastir" directory and type "git pull", which will snag just the _changes_ to the files since you last updated, and is very fast. Compile and install at that point and you'll be running the latest developer's version in just a few minutes! It's very easy to keep up with the developers this way. [ ] Step 5) Configure/compile/install Xastir. Type these commands into the BASH shell, waiting until each one completes before typing the next command: cd ~/git/Xastir ./bootstrap.sh mkdir -p build cd build ../configure make make install-strip NOTE: You'll probably want to run the configure step from an xterm window with the X11 server running of course. If you do this from a non-X11 window then the configure test for "gv" will fail, as "gv" requires an X11 server even when asking it for it's version number. Without "gv" support you won't be able to print from Xastir. Once you get through the above commands, Xastir is compiled and installed on your system, with minimal map support. Later sections of this document detail adding additional map libraries in order to give you access to the full mapping capability of Xastir. --------------------------------------------------------------------- [ ] Step 6) Actually run the darn thing: Let's start from scratch to make sure it all works. Close any Cygwin/BASH windows you may have. Click on the shortcut you created to start Xwindows. From the resulting BASH window, type "xastir &". Xastir should start up shortly. As built, using this documentation, the following map types are supported. Built-in map types: gnis USGS GNIS Datapoints pop USGS GNIS Datapoints w/population map APRSdos Maps map WinAPRS/MacAPRS/X-APRS Maps Support for these additional map types has been compiled in: geo Image Map (ImageMagick/GraphicsMagick library, many formats allowed) geo URL (Internet maps via libcurl library) geo URL (OpenStreetMaps via libcurl library Copyright OpenStreetMap and contributors, CC-BY-SA) shp ESRI Shapefile Maps (Shapelib library) tif USGS DRG Geotiff Topographic Maps (libgeotiff/libproj) xpm X Pixmap Maps (XPM library) The README.MAPS file has instructions for where to get maps and where to put them under the Xastir hierarchy. If you have any WinAPRS, DosAPRS, or PocketAPRS maps, now is a good time to place them in the /cygwin/usr/local/share/xastir/maps folder (or a subdirectory of it). You can also use "*.geo" files and the associated image files with Xastir. You may place them in this directory (or a subdirectory of it) as well. FILESYSTEM PATHS (WINDOWS VS CYGWIN): From Windows, just prefix all paths with "/cygwin" or "/cygwin64" as appropriate. For instance, maps go into /cgwin/usr/local/share/xastir/maps instead of /usr/local/share/xastir/maps. Xastir will continue to see them as "/usr/local/share/xastir/maps" though from inside Cygwin. It kind of looks like a miniature Unix box from inside Cygwin. LANGUAGE OPTIONS: To set a new language or change the language current choice, use this command line instead from inside an Xterm: xastir -l Current choices are: Dutch English French German Italian Portuguese Spanish ElmerFudd MuppetsChef OldeEnglish PigLatin PirateEnglish This option will be stored in the users config file for the next time Xastir is run. On new installs Xastir will default to English until you use this command line option once. CYGWIN vs LINUX/UNIX: Another difference with Cygwin as opposed to Unix-like operating systems: You can't do the make install portion if Xastir is up and running. You have to kill Xastir first before you do "make install" or "make install-strip". Otherwise the newly compiled Xastir won't replace the old one. Another interesting "feature" of Cygwin/Xwindows is that some of the modifier keys like ScrollLock/CapsLock/NumLock must be pressed while that X-window is the active foreground window. If not, the event can be missed, and Xwindows can get out of sync with the actual state of the key. This doesn't appear to be an Xastir-specific problem, but a Cygwin/Xwindow problem. With just a BASH shell under Cygwin (not involving Xwindows), the problem doesn't appear to happen. Just inside Xwindows on Cygwin. When specifying serial ports to use with Xastir, "COM1" is called "/dev/ttyS0" in Cygwin (and Linux) "COM2" is called "/dev/ttyS1" in Cygwin (and Linux) Note the capital 'S'. OPTIONAL Please see the INSTALL file and the Help menu in Xastir itself for additional information not mentioned in this document. Additional info can be found on the cygwin web-site: http://www.cygwin.com or the Cygwin/XFree86 web-site: http://cygwin.com/xfree/ Keeping up-to-date: Once a week or once a month, run the Cygwin network installer program (setup-x86.exe or setup-x86_64.exe). After it finishes, open a Cygwin terminal window and type these commands to update the Xastir source code: cd ~/git/xastir git pull Every once in a while Windows will refuse to allow you to delete/rename one of the files. The only way I've found to get around this problem is to reboot. I sometimes see this when trying to do a "git pull", and Windows won't allow one or more files to get updated. You can now repeat step 5 to update Xastir. ------------------------------------------- OPTIONAL: ADDING ADDITIONAL MAP LIBRARIES: ------------------------------------------- These additional Xastir libraries have been tested on Cygwin: ImageMagick (no need to use if using GraphicsMagick) Festival Anyone testing additional libraries is encouraged to share their findings on the Xastir mailing lists (you must be subscribed in order to post messages there). The libraries which have _not_ been made to work yet on Cygwin are: AX25 GPSMan/gpsmanshp The AX25 libraries will probably never work, as they are for Linux only. GPSMan/gpsmanshp may work on Cygwin at some point if enough work is done to figure out and document the process. OPTIONAL: Install Festival support: ------------------------------------ Note: The most recent version of Festival is 2.4. According to the README for this version, "Do NOT use Windows with Cygwin". With that warning up front, here are instructions that were previously used to make a legacy version of Festival work with Xastir. They were not revalidated during the November 2017 update to this document. Allows using a synthesized voice from within Xastir for alerts, reading messages to you, and other cool things. Tom Russo did the initial work on this, Henk de Groot optimized it: 1) Start BASH shell in Cygwin 2) Make ~/festival download directory and /usr/local/festival installation directory 3) Download festival components from festvox.org into ~/festival, in the Windows environment the corresponding path is: C:\Cygwin\home\%USERNAME%\festival get the following files: speech_tools-1.2.95-beta.tar.gz festival-1.95-beta.tar.gz festlex-CMU.tar.gz festlex-POSLEX.tar.gz festvox-kallpc16k.tar.gz 4) Build festival and company: cd /usr/local/festival tar xzf ~/festival/speech_tools-1.2.95-beta.tar.gz tar xzf ~/festival/festival-1.95-beta.tar.gz tar xzf ~/festival/festlex_CMU.tar.gz tar xzf ~/festival/festlex_POSLEX.tar.gz tar xzf ~/festival/festvox_kallpc16k.tar.gz cd speech_tools ./configure && make cd ../festival ./configure && make These packages are build and used where they are compiled. 5) Test festival: cd /usr/local/festival/festival/examples sh saytime Festival should say the time if everything went fine 6) Add /festival/festival/bin to PATH in .profile and .bashrc. For me both files look like this: .profile and .bashrc: ------------------- export PATH=$PATH:/lib:/usr/lib:/usr/X11R6/lib:/usr/local/lib:/usr/local/bin:/usr/local/festival/festival/bin:~/bin:. ------------------- 7) Configure and build xastir. Configure should report that festival is found. 8) Start the festival server: festival --server & To do this automatically I added the following lines to my .bash_profile: ------------------- if [ `ps -ef | grep festival | wc -l` -eq 0 ] then festival --server & sleep 1 fi ------------------- 9) Run xastir, do File->Configure->Speech, add things to say, and listen. OPTIONAL: How to make Sound Alerts work under Cygwin: ------------------------------------------------------ There is currently (November 2017) a problem using sound alerts under Cygwin. It is recommended that sound alerts are turned off within Cygwin or you may experience lockups. You'll need to add the .wav files to Xastir. git clone http://github.com/Xastir/Xastir-sounds cd Xastir-sounds cp -r sounds/* /usr/local/share/xastir/sounds/ November 2017 documentation updates by K2DLS. There may be out-of-date items that remain in this document. Please report issues via the Xastir mailing list. APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/README.GIT000066400000000000000000000304301501463444000156500ustar00rootroot00000000000000Git Instructions: ----------------- For those who think git might be a bit too complicated to deal with, here are (I think) the minimal commands. See the "SUDO" section in README.sudo for ideas to make updating Xastir even simpler. USERS: ------ Initial Copy (Git Clone): ------------------------- 0) Make sure git is installed on your system. 1) Run git config --global user.name "Your Name" user.email "Your@email.address" The above is not strictly necessary, but if you ever try to make changes to Xastir and get them integrated with the project it is important. NOTE: If you already have a different git global config, you can create a local config for a particular repo by going into that repo and doing: git config --local user.name "Your Name" user.email "Your@email.address" Check the config by: git config --local -l git config --global -l git config -l # Doesn't differentiate between global and local though! 2) Go to to access the project page. There you will find the URL of the git repository, just to the right of a button that says "HTTPS". Copy this URL to your clipboard. (At the time of this writing, the URL was ) 3) Open a shell, navigate to a directory where you want to store the Xastir source code, and enter this command: git clone https://github.com/Xastir/Xastir.git This will create a clone of the Xastir git repository in an "Xastir" subdirectory of the current directory. All done! You now have the latest development sources on your computer. Not only that, you have a complete copy of the entire project history and access to all prior releases. 4) Please set your default git commit message template for the project to the one included in the Xastir source tree: cd Xastir cp git_commit_message_template ~ git config --global commit.template ~/git_commit_message_template This will assure that when you make commits, your editor will start with a template that helps guide you through the process of writing commit messages that conform to the guidelines below in the section titled "Important: Git Commit Message Format". This template is quite generic and conforms to the guidelines of many other open source projects, so it is reasonable to make it a global git option. Updating Your Copy: ------------------- cd Xastir git pull # Update your local repo (May be dangerous for developers) ./bootstrap.sh # "autoreconf -i" also works mkdir -p build # Build in a separate directory cd build ../configure (make clean;make -j3 2>&1) | tee make.log sudo make install # "make install-strip" can be used after the first # time: It removes debugging info from executable sudo chmod 4555 /usr/local/bin/xastir # Only needed if using kernel AX.25 xastir & # Start it up! Note that you'll need autoconf 2.53 or newer and automake 1.6.3 or newer in order to run the "./bootstrap.sh" script. -or- Bypass all of the commands above and just type: cd Xastir ./update-xastir NOTE: "autoreconf", a part of the autoconf package, does the same thing that bootstrap.sh does, in a more modern approach. The bootstrap.sh approach is very old and was the approach advocated by this document for many years, but invoking "autoreconf -i" does the same thing. PLEASE NOTE: Bootstrap.sh is used by both methods above, even "update-xastir", which is simply a script that performs all the steps listed explicitly earlier. The bootstrap.sh script is what creates the configure script. Running bootstrap.sh requires having autoconf and automake installed, and it will fail if these are not installed. If bootstrap.sh fails, configure won't exist. If bootstrap.sh fails, stop, fix the problem and try again. There is no point continuing if bootstrap.sh gives you error messages about programs not being found (aclocal, autoconf, automake). This is a common problem reported to the Xastir team, and its solution is always the same: install all prerequisite tools before trying to build Xastir. DEVELOPERS: ----------- Initial Checkout: ----------------- HTTPS Method: git clone https://github.com/Xastir/Xastir -or- SSH Method. Add keys to GitHub and then: git clone git@github.com:Xastir/Xastir Note that using the SSH method means that you won't have to answer the popups for user/password each time you do anything with the remote repo, although you will have to enter a passphrase if you added a passphrase to your SSH key. The SSH method is highly recommended for active developers! Normal Development Flow: ------------------------ A pull before committing can be dangerous, if there are substantial conflicts between your work and others (not very likely with Xastir, but definitely likely in bigger projects). It is much better to do a fetch (which pulls down changes from the remote but DOESN'T merge them into your tracking branch), then look at what changed upstream, and then either a merge, rebase, stash/pop, or something else depending on the level of conflict you see. See README.GIT. Doing a pull before starting your own work is reasonable, but if someone pushes while you're working (again, not very likely with Xastir), you can still wind up with really ugly history, with weird merge commits and undesired branching. On the other hand, if you replace "git pull" with "git pull --rebase" in that recipe, with the caveat that sometimes you might have to be more careful and that you need to understand what you're doing, a lot of the danger of the simple git pull can be avoided. We will often be working on a branch for development, then merging that branch with the trunk when that feature or bug-fix is ready for prime-time. Commit your work to your LOCAL repo: - First add all desired changes to the staging area: git add ... - Then commit your staged changes to your local repo git commit Push your local repo changes up to GitHub when you are ready to publish them: git push Important: Git Commit Message Format ------------------------------------ Git commit messages need to be in a certain format to make the best use of the "git log" commands. In particular the first line needs to be 50 chars or less, then a BLANK LINE, then a detailed commit message. See this link for more info: http://chris.beams.io/posts/git-commit/ Checking Out A Branch: ---------------------- All branches associated with the Xastir project are contained in the clone you made earlier. You can switch your current working directory to one of those branches easily: cd Xastir git fetch (this updates your local repo copy from github, but doesn't merge changes into your working tree) git checkout (this switches all the files in your working tree to match those in the branch) git merge (This makes sure that all the changes that may have happened upstream on that branch get into your copy) You do not have to do this in a new directory --- so long as you haven't changed any files in the source tree, git checkout automatically swaps out all files it knows about with versions from the branch. If you really want to keep more than one branch's code around to work on, you can do that if you have git version 2.5 or later with the following commands: cd Xastir git worktree add This will create a new directory tree called with the named branch checked out into it. In early 2018, there is only one active branch, the master branch, and we will be performing releases by creating release branches. There are many more git commands and options. Many of them are more of use to the developers. Some of those are listed below. The above should be enough for most people to keep their copies in sync with the latest git development sources. If Using Multiple GitHub Accounts: ---------------------------------- You may have trouble getting your commits attributed to the correct GitHub login. GitHub uses the username/email in your git config settings for attribution. If it is wrong, you may have to do some of the below in order to set a LOCAL username and email for the one repository. The user.name and user.email are pulled from the global git config, but a local git config inside each repo will override those settings. Go to root of checked-out repo and set local user.name and user.email for this repo: git config user.name git config user.email git config -l # Shows both local and global settings, hard to tell which is which git config --global # Shows global settings git config --local -l # Shows local repo configs, so should show new settings Another method (but more error-prone) of editing local/global git config is: git config edit # Edit local config git config --global edit # Edit global config If new commits still aren't using the right email, make sure you have not set GIT_COMMITTER_EMAIL or GIT_AUTHOR_EMAIL environment variables. More Info: ---------- Make sure you know how git works. Read https://git-scm.com/book/en/v2 If you are very familiar with CVS, get used to working differently, because git is different. Read and understand http://chris.beams.io/posts/git-commit/ Read http://justinhileman.info/article/changing-history/ Read http://think-like-a-git.net/ Read "Visual Git Cheat Sheet" at http://ndpsoftware.com/git-cheatsheet.html Branching and merging in git is very simple, and is documented very well by all those links. We will not repeat it here. If you use SSH, set up your SSH keys on GitHub and do the "git clone" using the SSH path. This will save you having to put in your password each time you use the remote repository, although if you added a passphrase to your SSH key you'll have to enter that each time. Useful Git Commands: -------------------- Set up global user/email git config --global user.name "Your Name" git config --global user.email "user@domain.com" Set up user/email for a local repository cd /path/repository git config user.name "Your Name" git config user.email "user@domain.com" Configure Git's editor: git config --global core.editor /path/to/editor Colorizing Git output (set once and forget): git config --global color.ui auto Clone a repo: git clone http://github.com/Xastir/Xastir git clone https://github.com/Xastir/Xastir git clone git@github.com:Xastir/Xastir Status of local repo: git status Diff for a file: git diff See all branches, local and remote: git branch -a Visual Git viewer: gitk (tcl/tk and generic X11 viewer, comes with git) or gitg (gnome git viewer) Add files to the staging area: git add Commit changes to LOCAL repo: git commit # If have files in staging area already git commit # Ignores staging area Push local changes to remote repository: git push Update local repo from remote repo git fetch Update local repo and merge remote/local changes in local repo (May be dangerous for developers with modified code in their working tree): git pull Rebase local changes against latest master branch git fetch git rebase master ------------------------------------------------------------------------ Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/README.MAPS000066400000000000000000001745461501463444000160060ustar00rootroot00000000000000 Recommended Configurations for: U.S. Users: ----------- Minimum: Shapelib, pcre -------- Allows use of all built-in map types plus 2003 (and later) Tigermap data, shapefile weather alerts, and local ESRI Shapefile format maps, including U.S. satellite/image/topo maps via Internet. Medium: Shapelib, pcre, lcms, ImageMagick, libcurl/wget, ------- Allows use of all the above plus Internet maps and local image maps. Maximum: Shapelib, pcre, lcms, ImageMagick, libcurl/wget, -------- libtif, libproj, libgeotiff Allows use of all the above plus USGS topo maps. Rest of World: -------------- Minimum: lcms, ImageMagick, libcurl/wget -------- Allows use of all built-in map types plus local and Internet image maps, including Canadian topo maps via Internet. Medium: lcms, ImageMagick, libcurl/wget, Shapelib, pcre, ------- Allows use of all the above plus ESRI Shapefile maps. Maximum: libproj/libtiff/libgeotiff -------- Adds more map types. Some of these may not be useful in your part of the world. Map Type: Libraries Required/Notes: --------------- ------------------------- DosAPRS Built-in. WinAPRS Built-in. X-APRS Built-in. MacAPRS Built-in. PocketAPRS Built-in. USGS GNIS Built-in. Can split into county-sized chunks using xastir/scripts/split_gnis.pl to speed things up. Address Lookup Built-in. Weather Alerts Shapelib pre-2003 Tigermaps Shapelib post-2003 Tigermaps Shapelib, pcre ESRI Shapefiles Shapelib Image Maps ImageMagick. Often need lcms library and others as well (whatever it takes to make ImageMagick happy). Can also use the XPM library for some image types without installing ImageMagick. Internet Maps ImageMagick plus wget or libcurl. Often need lcms library and others as well (whatever it takes to make ImageMagick happy). WMS Maps are in this category as well. UI-View Maps Convert from .INF to .GEO format using xastir/scripts/inf2geo.pl OziExplorer Maps Convert some maps to .GEO format using xastir/scripts/ozi2geo.pl USGS DRG Topo libtiff, libtiff-devel, libproj, libgeotiff APRS Overlays Convert to Shapefile maps with scripts/pos2shp.pl The default map, "worldhi.map", is used with permission of its creator, Keith Sproul, WU2Z. How to Use APRS Overlay Maps (*.POS files) within Xastir: --------------------------------------------------------- Use the "xastir/scripts/pos2shp.pl" script to convert the overlay files to ESRI Shapefile maps: # ./pos2shp.pl test.pos testmap # cp testmap* /usr/local/share/xastir/maps/. Xastir: Map->Configure->Index: Add New Maps Map Chooser: Select the "testmap" map Using Online Maps: ------------------ There are a few *.geo files that get installed into Xastir's maps/ directory upon install. These invoke online map sources of various types: OpenStreetMap ------------- Select the appropriate files from the Online/ directory in Map Chooser WMS Map Servers --------------- Xastir has support for WMS map servers built-in. To use this you'll need to create a *.geo file in your map directory (usually "/usr/local/share/xastir/maps/Online/", "/usr/share/xastir/maps/Online/" or any directory below those) for each LAYER you wish to use, perform a re-index of your maps, then select them in the Map Chooser. Procedure: Hunt down a WMS map server that you wish to use, then find its "GetCapabilities" link. Here's an example: http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetCapabilities Look at it directly in your browser or use Xastir's "wms.pl" script to see the structure and keywords of the XML. Note that if using "wms.pl" you must add backslashes prior to each '&' character in the URL. wms.pl "http://geogratis.gc.ca/maps/CBMT?service=wms\&version=1.1.1\&request=GetCapabilities" "wms.pl" will show the format of the XML file plus a section at the end which looks like: --------------- POSSIBLE .GEO FILE CONTENTS: WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=National WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_national WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Regional WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_regional --------------- This means there are four different map layers you can get from that WMS server. To see/use each one you'll need to create four different .geo files for Xastir. The format of a WMS Server .geo file is exactly two lines. Try using each of the two-line outputs from wms.pl as a start towards creating your own .geo files. Getting Maps and other Data Files for Xastir: --------------------------------------------- NOTE: Set map FILES to permissions 644 ("rw-r--r--"), map DIRECTORIES to 755 ("rwxr-xr-x") using the "chmod" command. These permissions will allow anyone on the box to read the map files, and access the map directories. Type these commands exactly as shown in order to set the map directory's permissions properly. Do this as the root user: cd /usr/local/share/xastir/maps find . -type d -exec chmod 755 {} \; find . -type f -exec chmod 644 {} \; You can repeat these commands at anytime, to fix up errant map permissions that are created by downloading/installing new maps. Currently the maps/GPS directory needs to be writable by normal users in order to support downloading GPS data using GPSMan. This will be changed at some future date, moving this directory into the user's home directory instead. cd /usr/local/share/xastir/maps chmod 777 GPS find GPS -type d -exec chmod 777 {} \; find GPS -type f -exec chmod 777 {} \; Download some maps: If you compiled with ImageMagick and have wget or libcurl installed, you can skip this step and use the online OSM/WMS maps exclusively. However, having maps on your computer is often faster than transferring images over a modem, and is not subject to the failures of your Internet connection. See the section below on map caching for an exciting feature that works with most online maps to really speed things up! You can have any number of maps in the /usr/local/share/xastir/maps directory. You can organize the maps however you like. You can also use symbolic links to link to files/directories on other disks. Map files are loaded in the order that they appear in the chooser unless you adjust the layering priorities in the "Properties" dialog (it's recommended that you use these now instead of a directory hierarchy to choose the layering). There are many methods for organizing many maps. Create a map hierarchy using something that makes sense to you. The old method of creating transparent/filled or raster/vector directories has been superseded by the new map layering features in the Map Chooser->Properties dialog. It's now suggested that the map layering be done there, and the directory layout designed to make it easiest for the user to select maps. Perhaps a good start would be: World/ Canada/ Canada/Province/ USA/ USA/State/WA/ USA/State/WA/County/ ... GNIS/ Overlay/ Please note that the map directories are entirely up to the user now. Use the map layering facilities (Map Chooser->Properties) to determine the order in which they will be drawn, and to determine which will draw filled areas. Note that raster maps will always draw filled, not matter what the setting suggests. For vector maps, you have a choice of: Fill = No Polygons will never be filled Fill = Yes Polygons will always be filled Fill = Auto Polygon fill is determined by map (or if it's a Shapefile, by any associated dbfawk file). Map types available by extension: Vector Format: .shp/.shx/.dbf Shapefile vector map (need all three files) .map APRSdos/WinAPRS/MacAPRS vector map .gnis GNIS labels file (actually points instead of vectors) .geo Vector map or Internet vector map. Note that for http/ftp-based maps Xastir requires an IMAGESIZE line. Raster Format: .tif/.fgd geoTIFF raster image map .geo Raster image map or Internet raster image map. Note that for http/ftp-based maps Xastir requires an IMAGESIZE line unless using WMS maps. Note: .geo is listed twice because it can fit in both categories, depending on the base format of the map file that the .geo file points to. .geo files are handled by the XPM library or by ImageMagick, so most anything that can be handled by those installed libraries can by handled by Xastir. A few maps of various types are available from: http://we7u.wetnet.net/xastir/maps/ Here's a page that we'll try to keep up-to-date which will have lots of links to download-able maps on it: http://xastir.org/index.php/Xastir_Maps Dos/Win/MacAPRS style vector/fill maps: http://www.winaprs.com/Maps.htm http://www.cnunix.com/ftp/hamradio/rutgers.mirror/maps/maps2/ ftp://ftp.tapr.org/aprssig/maps/ WORLDHI.MAP is suggested as a basic view of the world map. You can use any of the other maps available from this site. Many of them were created from Tiger/Line maps, but they are several years out of date. It is suggested that you don't use these as your primary street-level maps; the newer shapefile-based maps are usually preferable. In cases where you cannot compile shapefile support, these maps suffice. PocketAPRS vector maps: The WinAPRS 2.51 distribution included the full collection of PocketAPRS vector maps for the USA. The download is about 60MB, from the TAPR ftp site. ftp://ftp.tapr.org/aprssig/winstuff/WinAPRS/waprs251.zip Raster Maps: For Canada there is a country wide set of topographic map images available from the "Department of Natural Resources Geomatics Canada". Running /scripts/toporama250k.pl will pull down 430mb of 1:250k map images from that departments site. If that's not enough data, running /scripts/toporama50k.pl will pull down around 10gigs **** Note that recent changes at the "Department of Natural Resources Geomatics Canada" have made these scripts fail. Changes to the scripts are being coded and tested. Git will be updated once the scripts are proven to work again. **** For Ireland, EI8IC (http://www.mapability.com) has produced a set of overlay maps that show the County Borders, Main Towns and Roads. John, EI7IG, has created a set of ".geo" files to go with them and they are all available in one tarball from [http://ireland.aprs2.net/xastir/IrelandMaps/Ireland.tar.gz ireland.aprs2.net] They are free for non-commercial use. Also available are a map of the [http://ireland.aprs2.net/xastir/IrelandMaps/Ireland1600x2000.bmp country], with an associated [http://ireland.aprs2.net/xastir/IrelandMapsIreland1600x2000.geo geo] file, the [http://ireland.aprs2.net/xastir/IrelandMaps/Ireland1600x2000.bmp South East], its associated [http://ireland.aprs2.net/xastir/IrelandMapsIreland1600x2000.geo geo] and a [http://ireland.aprs2.net/xastir/IrelandMaps/IrishMET.geo Weather Radar] .geo file. Shapefile format maps (Requires shapefile support): Shapefile format maps are slowly becoming the standard vector format of maps used with Xastir. Xastir 1.3.2 and above by default enable dbfawk support for parsing shapefile metadata, see below. A nice world map is available at http://aprsworld.net/gisdata/world/ thanks to James Jefferson, TerraSpace, Russia, and the Digital Chart of the World (for Antarctica). Note that this file is currently available only in uncompressed or in tar/bzip2 format. To decompress the latter file, you'd type "bunzip2 filename" and then "tar xvf filename". Some other shapefile format maps are available at: http://www.nws.noaa.gov/geodata/ Still other shapefiles are available from esri.com, geographynetwork.com and gisdatadepot.com (from their "free data" link). Lot's of useful stuff at these sites, just look around. You can also check with your County GIS office for shapefiles of your county. You can convert them from State Plane to Lat/Long projection using instructions later in this document. Canada street maps in Shapefile format are available at http://www.geobase.ca If you also use GeoTIFF images, get the handy usgs_24kgrid.zip file from http://data.geocomm.com/quadindex/. This file provides a grid of all of the 7.5' maps and their names for the U.S. A nice world map is available at http://aprsworld.net/gisdata/world/ thanks to James Jefferson, TerraSpace, Russia, and the Digital Chart of the World (for Antarctica). Note that this file is currently available only in uncompressed or in tar/bzip2 format. To decompress the latter file, you'd type "bunzip2 filename" and then "tar xvf filename". www.bts.gov has the "National Transportation Atlas" that you can download pieces of (at least for the larger layers) or ask for (free) CD-ROM's to be mailed to you. ----- Re-projecting shapefiles (or: why doesn't my shapefile show up?) A shapefile is pretty much just a collection of points and lines between points. Xastir expects that those points are expressed in degrees of longitude and latitude with positive values indicating N and E and negative values indicating S and W. One often comes across shapefiles with data in some other format, such as UTM or state-plane projections with units in meters or feet. You must re-project these sorts of shapefiles in order to use them in Xastir. You must either know what the current format is of the shapefile you wish to re-project, or have the .prj file that some shapefiles come with. Fortunately, the shapelib-1.2.10 distribution (which you probably compiled and installed to enable shapefile maps in Xastir) includes a tool for performing this re-projection. First make the shpproj utility by: 1. change to directory: /contrib 2. type 'make' to compile the contrib files 3. Optionally install shpproj by copying it to /usr/local/bin shpproj takes 4 arguments: shpproj shp_file new_shp -i="in_params" -o="out_params" shp_file is the name of your existing shapefile triad (without the extension). new_shp is the name of your new shapefile triad (which doesn't exist yet). -i="in_params" are the parameters describing the existing shapefile. -o="out_params" are the parameters describing the new shapefile. We want this to be "geographic". Examples: Convert shapefile triad from US State-plane, South Central Texas region (FIPS code 4204), in feet to geographic: shpproj stateplane_shapefile geographic_shapefile \ -i="init=nad83:4204 units=us-ft" -o=geographic Convert UTM zone 15 to geographic: shpproj utm_shapefile geographic_shapefile \ -i="proj=utm zone=15 units=m" -o=geographic To get a listing of the FIPS codes, you need to have proj installed (see elsewhere in this file for more information). Look in the "/nad/nad.lst" file. For more detailed documentation, see the shpproj.txt file in the "/contrib/doc" directory. There's a resource for looking up the FIPS codes for a particular area: http://www.aprs.net/fips/ An important note about using shpproj to re-project maps The shpproj program cannot be used to convert shapefiles unless they're already using the NAD83 or WGS84 datum. shpproj will do the conversion if you ask it to, but it will do it incorrectly. A simple program to convert shapefiles between various projections that does do datum conversions correctly is "shpcs2cs," available from That program requires libproj to be installed properly, and uses a command line format similar to the "cs2cs" program that comes with libproj. If you already have GDAL installed, you should have the "ogr2ogr" program available to you. ogr2ogr will not only convert projections and geodetic datum correctly, but will also convert format (ArcView binary format to shapefile, TIGER/Line files to shapefile, etc.). Some detailed instructions for using ogr2ogr to do this conversion are available at ----- Using "dbfawk" to interpret shapefile DBF data: Each shapefile map (*.shp, *.shx) comes with a DBase data file (*.dbf) in which each shape in the .shp file has a corresponding set of descriptive data about that shape in the .dbf file. While shapefiles are all a standard format and will most always draw (possibly after having been re-projected with shpproj), the corresponding .dbf data varies widely depending on the data source. For example, US Census Tiger/Line files contain 20 attributes for each shape including such values as the name of the shape (i.e. street name), and a "Census Feature Class Code" (CFCC) which indicates whether a shape is a dirt road or a superhighway, for example. In "pre-dbfawk" Xastir, knowledge of the various sources of shape files was built into the program and it was necessary to add code to support new shapefile sources (such as those produced by local government agencies, non-US, etc.). Xastir with dbfawk moves this logic into metadata files named *.dbfawk. These files are linked to the .shp/.dbf files they belong with in one of two ways: 1. "Signature" recognition. .dbfawk files located in the config/ directory are read to find the "dbfinfo" signature, which is simply the ordered list of attribute names found in the .dbf file. If you browse config/*.dbfawk you will see dbfawk's for the most well know shapefile types. For example, tgrlk.dbfawk matches all the "tgr*lk?.dbf" US Census Tiger/Line files. When a shapefile map is displayed, its .dbf signature is matched up with one of the config/*.dbfawk files. 2. "Tied" to a file. If you installed a .dbfawk file in the same directory as the .shp and .dbf files (e.g. sample.shp, sample.dbf get a corresponding sample.dbfawk) then that file is used instead of signature matching. The first method allows a single .dbfawk file to be automatically used for hundreds of standard shapefile maps. The later allows you to customize how your particular shapefile map displays. What's in a .dbfawk file? The best documentation of these files is found by looking at the commented examples in config/*.dbfawk. dbfawk is modeled after the "awk" pattern scanning and processing language -- but, it is *not* exactly awk: - Regular expression syntax is that used by Perl (the pcre library is used) rather than pure awk. - Action statements are much more limited than full-blown awk. - The concept of records and fields is used since a .dbf record is structured of usually several fields (name, feature type, etc.). That said, what dbfawk does is allow a great degree of control of how and when shapes and their names are displayed. This is done by setting the values of several "builtin" variables [Technically, these are only built-in to shapefile support. Potentially the awk-like code can be extended to other uses.]: dbfinfo: the "signature" to match against. dbffields: which fields to read from the .dbf file. color: what color code to display the shape with. lanes: width of the shape. name: name of the shape. key: search key (used for WX alerts to find the shape) symbol: symbol for landmarks, etc. filled: draw polygons filled. Filled="Yes" or "No" in the Map Properties dialog will override this option. Set to "Auto" in that dialog to have the dbfawk file control this. fill_style: style of fill (0=solid, 1=FillTiled, 2=FillStippled, etc.) fill_color: color of fill fill_stipple: stipple pattern if fill_style=2 ("FillStipple") 0=13 percent, 1=25 percent, 2=50 percent. pattern: solid or dashed lines. display_level: at what zoom level to begin displaying the shape label_level: at what zoom level to begin displaying labels label_color: color to use for labels Execution of a dbfawk file: Just like awk, the file consists of patterns that are matched against input data and actions to take when the pattern matches. There are four special patterns in dbfawk: BEGIN_RECORD: action is executed just before parsing a record. BEGIN: action is executed just before parsing a field. END: action is executed just after parsing the field. END_RECORD: action is executed just after parsing a record. All other patterns are regular expressions that are matched against a data value of =. For example: FENAME=Main Actions in dbfawk files consist of setting variables and two special actions: next: skips to the next field in the record. skip: skips to the next record. If neither next nor skip is given in the action, then processing falls through to the next pattern/action pair in the dbfawk file. The special dbffields variable is used to list which fields of the record to be processed and in what order. The order is significant since it may take several DBF fields to build up a complete name. For example, in Tiger/Line, the street name is actually the concatenation of FEDIRP, FENAME, TYPE, FEDIRS. Here's an excerpt from tgrlk.dbfawk to demonstrate: BEGIN {dbffields="TLID:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC"} ... /^FEDIRP=(.+)$/ {name="$1 ";next} /^FENAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^FENAME=State Highway (.*)$/ {name="$(name)State $1";next} /^FENAME=State Route (.*)$/ {name="$(name)SR $1";next} /^FENAME=(.*)$/ {name="$(name)$1; next} /^FETYPE=(.+)$/ {name="$(name) $1"; next} /^FEDIRS=(.+)$/ {name="$(name) $1"; next} Creating and testing dbfawk files: You can test an existing dbfawk file by setting debug level 16 in Xastir (this will generate a huge amount of map rendering debug output, including dbfawk info): "./xastir -v 16 2>/tmp/log" Or, use "testdbfawk" which reads a .dbf file (or single field assignments on the command line). For example: cd /usr/local/share/xastir testdbfawk -D config -d Counties/mz01ap14.dbf 2>&1 | less 8 Columns, 479 Records in file sig: ID:WFO:GL_WFO:NAME:AJOIN0:AJOIN1:LON:LAT DBF Signatures match! name=Lake Okeechobee, key=AM_Z610, symbol=, color=8, lanes=2, filled=0, pattern=0, display_level=65536, font_size=2, label_level=512 label_color=20 ... testdbfawk takes the following command line syntax: testdbfawk --help Prints command line usage testdbfawk -D directory -d file.dbf Scans directory for dbfawk files with signatures matching file.dbf, runs the dbfawk program that matches if it's found. testdbfawk -f file.dbfawk -d file.dbf runs the dbfawk file "file.dbfawk" over the dbf file "file.dbf" So in the example above, testdbfawk scans the current directory for dbfawk files with signatures that match tgr36119lkA.dbf's signature. testdbfawk dumps its output to standard error, so in the example standard error is redirected to standard out and piped into "less" for paging. To create a .dbfawk file, you need to understand the layout and contents of your .dbf file. Use "dbfinfo" and "dbfdump" which are in the shapelib contrib directory. Dbfinfo will list the field names and dbfdump will dump out all fields of all records. Take the field names from dbfinfo, and concatenate them together in order, separated by ":" to make the dbfinfo= signature variable assignment. Your best bet is to start with an existing .dbfawk file as an example. Dbfawk hints and kinks: You have to think like an awk programmer and realize that the order that rules are listed matters, that it's important to use "next" as soon as it makes sense so other rules aren't looked at unnecessarily and, to use "skip" when you want to fix bad dbf data. For example, my county's Tiger/Line maps have several coding errors where a segment of a main highway is incorrectly labeled as a local street. This rule overrides one of those incorrect records: # This Furnace Dock Rd segment is really Rt 9! /^TLID=139773160$/ {name="Briarcliff-Peekskill Pky"; display_level=8192; label_level=512; color=4; lanes=4; skip;} TLID is the Tiger/Line ID which is the unique identifier for this segment. ----- Rolling your own shapefile maps: It is relatively easy to create your own shapefile maps (for example, if you want to highlight a walk-a-thon course). There are several methods available with Xastir: 1. Use GPSMan to download a GPS track to a shapefile. 2. Save a station tracklog of an actual station or an object that you manually move along the course. When you select Station Info, you are presented with the option to save the track, which gets put in .xastir/tracklogs/__APRS_Trail_.* You can move the .shp, .shx, and .dbf files to your maps directory. Use DBFAWK to make a map-specific .dbfawk file. For example: BEGIN {dbfinfo="Credits:DateTime";dbffields="Credits:"} BEGIN_RECORD {key=""; lanes=4; color=12; name=""; filled=0; pattern=1; display_level=8192; label_level=32; symbol=""} This makes the track width 4 and red (12). 3. You can use xastir's "object" capability to generate shapefile maps. a) Turn off object transmission using Interface->Disable Transmit:Objects b) Put objects where you want. Set the display symbol as you like it. c) run the "object2shp.pl" script in the scripts directory (/usr/local/share/xastir/scripts/object2shp.pl in most installations) to generate a shapefile: /usr/local/share/xastir/scripts/object2shp.pl ~/.xastir/object.log myshape This requires the four shapelib utilities "dbfcreate", "shpcreate", "shpadd" and "dbfadd" as described below. d) EXIT XASTIR e) REMOVE ~/.xastir/config/object.log f) move "myshape.shp," "myshape.shx," and "myshape.dbf" to your maps directory. g) restart xastir. h) select your newmap in the map chooser. Creating maps in this way is basically just a scripted version of the manual map generation technique in (4) below. 4. You can also use the shapelib tools (shpproj was presented earlier) to manually create a shapefile. For example, the following marks out the mile-posts for a marathon, using tgrlpt.dbfawk (US Census Tiger/Line landmark points with an APRS(tm) symbol extension) for the metadata: #!/bin/sh # turn mileposts into a Tiger landmark shapefile rm -f posts.shp posts.dbf shpcreate posts point dbfcreate posts -n ID 8 0 -s CFCC 3 -s NAME 30 shpadd posts -74.0570 40.6025 dbfadd posts 1 'X\m ' Start shpadd posts -74.0443 40.6065 dbfadd posts 2 'X\m ' 1M shpadd posts -74.0353 40.6093 dbfadd posts 3 'X\m ' 2M shpadd posts -74.0268 40.6260 dbfadd posts 4 'X\m ' 3R shpadd posts -74.0200 40.6277 dbfadd posts 5 'X\m ' 3G shpadd posts -74.0270 40.6252 dbfadd posts 6 'X\m ' 3B shpadd posts -74.0197 40.6395 dbfadd posts 7 'X\m ' 4R shpadd posts -74.0203 40.6388 dbfadd posts 8 'X\m ' 4BG shpadd posts -74.0077 40.6508 dbfadd posts 9 'X\m ' 5R shpadd posts -74.0083 40.6503 dbfadd posts 10 'X\m ' 5BG shpadd posts -73.9957 40.6623 dbfadd posts 11 'X\m ' 6R shpadd posts -73.9962 40.6617 dbfadd posts 12 'X\m ' 6BG shpadd posts -73.9850 40.6743 dbfadd posts 13 'X\m ' 7R shpadd posts -73.9858 40.6738 dbfadd posts 14 'X\m ' 7BG shpadd posts -73.9782 40.6865 dbfadd posts 15 'X\m ' 8M shpadd posts -73.9597 40.6890 dbfadd posts 16 'X\m ' 9M shpadd posts -73.9573 40.7007 dbfadd posts 17 'X\m ' 10M shpadd posts -73.9622 40.7122 dbfadd posts 18 'X\m ' 11M shpadd posts -73.9515 40.7230 dbfadd posts 19 'X\m ' 12M shpadd posts -73.9520 40.7345 dbfadd posts 20 'X\m ' 13M shpadd posts -73.9525 40.7465 dbfadd posts 22 'X\m ' 14M shpadd posts -73.9403 40.7503 dbfadd posts 23 'X\m ' 15M shpadd posts -73.9578 40.7587 dbfadd posts 24 'X\m ' 16M shpadd posts -73.9556 40.7675 dbfadd posts 25 'X\m ' 17M shpadd posts -73.9465 40.7808 dbfadd posts 26 'X\m ' 18M shpadd posts -73.9372 40.7935 dbfadd posts 27 'X\m ' 19M shpadd posts -73.9272 40.8047 dbfadd posts 28 'X\m ' 20M shpadd posts -73.9343 40.8142 dbfadd posts 29 'X\m ' 21M shpadd posts -73.9453 40.8050 dbfadd posts 30 'X\m ' 22M shpadd posts -73.9525 40.7923 dbfadd posts 31 'X\m ' 23M shpadd posts -73.9630 40.7810 dbfadd posts 32 'X\m ' 24M shpadd posts -73.9720 40.7696 dbfadd posts 33 'X\m ' 25M shpadd posts -73.9811 40.7683 dbfadd posts 34 'X\m ' 26M shpadd posts -73.9763 40.7720 dbfadd posts 35 'X\m ' Finish --------- Splitting large Shapefile maps into regularly-sized tiles: Look for "shp2tile" at http://imaptools.com/tools/, it does exactly that. This can speed up Xastir tremendously if you're zoomed in quite a bit on a large Shapefile map (or maps). If it is broken into tiles Xastir only has to load the tiles of interest instead of slogging through the entire large file each time. GeoTIFF Map files (requires GeoTIFF): If you compiled in geoTIFF support, you can use USGS DRG topographic maps. These are primarily useful to U.S. users. DRG topo maps can be found for free for most states, and can be purchased for others. http://www.bianifc.org/gis_gps/gps/drgfree.html http://www.gisdatadepot.com or try a google search with "free drg maps" as the search query. If you have no luck finding free DRG maps, go to http://www.geocomm.com/ and check out the "DRG Data Bundles" they have available. You can purchase a DVD containing all the DRGs for an entire state in three scales, all of them usable in xastir, for a relatively low price. Be warned, however, that parts of the US have DRGs that are produced by an agency other than the United States Geological Survey, and these DRGs are not necessarily in correct GeoTIFF format. The areas covered by the Tennessee Valley Authority appear to be among those, as one xastir user discovered when purchasing a DVD of DRGs for North Carolina. It is still possible to use these DRG files, but they need preprocessing. See the section below entitled "Defective GeoTIFF files need even more special processing." Many useful US maps can be downloaded from the National Map Viewer: http://nmviewogc.cr.usgs.gov/viewer.htm Free FAA sectional charts can be downloaded from http://aviationtoolbox.org/raw_data/FAA_sectionals/current/ This site was set up by someone who had a subscription to the FAA DVD collection and made them available on the web (this is legal per FAA's terms of use). They are no longer being updated as of mid 2005. These charts are in Lambert Conformal Conic projection, though, and need to be converted with gdalwarp to be usable in xastir (see below). Current, valid-for-navigation FAA sectional charts may be purchased from the FAA at https://naco.faa.gov/ecomp/Catalog.aspx?a=AERO+NOS+DIGITAL for about $1.50US each. These files are also in GeoTIFF and are the same type as those that are available on aviationtoolbox, but these are updated every 6 months and are kept current. You will have to process them before viewing in xastir. The 7.5' topo maps work the best so far. Be sure to install the .tif AND the .fgd files side-by-side into the map directories. Without the .fgd file Xastir won't be able to crop the white border from the map. Xastir currently knows how to handle NAD27, NAD83, and WGS84 geoTIFF files. GeoTIFF files created in other datums will be displayed at an incorrect location with Xastir. The .tfw files included with most geoTIFF images are not used by Xastir. If you must make FGD files by hand, the included script mapfgd.pl can create them for you from the USGS geoTIFF files. The format Xastir is looking for is the following: 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 -or- 1.5.1.1 West_Bounding_Coordinate: -122.000000 1.5.1.2 East_Bounding_Coordinate: -120.000000 1.5.1.3 North_Bounding_Coordinate: 48.000000 1.5.1.4 South_Bounding_Coordinate: 47.000000 Notes about DRG-Enhanced (DRG-E) files: * The DRG-E files will draw over the correct spots if you remove the .fgd file, but will overflow their boundaries and * The DRG-E files will draw over the correct spots with decent boundary trimming (as far as I can tell, which isn't very far: correct me!) if you use a .fgd file taken from 'real' DRG files from USGS. Basically: get rid of the .fgd file from the DRG-E!! Highly Compressed MrSID image files: Be wary of DRG-E or DOQQ files that are compressed with MrSID compression. That is a proprietary compression format for which we do not have access to the decoding algorithm. We cannot use those from within Xastir. There's possible good news lurking on the horizon though: LizardTech has mentioned on the gdal-dev mailing list that they might be supporting open-source with a driver for gdal sometime soon. It is also possible to decompress these files with a free tool from LizardTech called "mrsiddecode", available at http://www.lizardtech.com/download/dl_options.php?page=tools mrsiddecode can produce GeoTIFF output with the right command line options. There is a Linux version of mrsiddecode, but one user has observed that the Windows version running under Wine is a little more robust. Your mileage may vary. Be warned that MrSID is a very effective compression algorithm, and compressed MrSID files of size 5MB could easily decompress into 50MB GeoTIFFs. Note also that many GIS departments take perfectly usable GeoTIFF files with all projection and datum tags and use ESRI products to compress them down into MrSID files, thereby losing all the GeoTIFF tags. See below. GeoTIFF files in certain projections need special processing: Not all geotiff files available on the net are usable directly in xastir. Some of them are in projections that xastir can't use properly, and others are missing all of the metadata information that is needed to work out how to convert them to Lat/Lon unprojected rasters. If you encounter a geotiff file that has the correct tags, but is in some projection other than UTM, you can convert that file to a lat/lon raster if you have gdal installed. Simply run the following command: gdalwarp -t_srs EPSG:4326 original_raster.tif usable_raster.tif This will warp the geotiff file "original raster.tif" from whatever projection it was in into an unprojected lat/lon raster "usable_raster.tif" that can be directly read into xastir. Depending on the source projection, you might get a map that doesn't tile well with other maps due to the inclusion of opaque border material, but it can sometimes be the only way to import a map you need to use. Defective GeoTIFF files need even more special processing: It is unfortunately the case that the ESRI software in use by many GIS departments produces GeoTIFF files that have NO information about the coordinate system that applies to them --- they'll have just enough information to know what the numerical coordinates of each pixel are, but no information to tell you whether those coordinates are UTM, Lat/Lon, State Plane, or anything else. For such maps you will need to determine the coordinate system by finding external files called "metadata" that are associated with the images. US Federal datasources have a standardized file format (".fgd") that provides this information, but many state or university GIS departments just make some other format up for themselves. Most sources of map data should have such metadata available, but sometimes it is a bit of a chore to find it. You can determine whether a .tif file has coordinate system information in it using the "gdalinfo" command from the GDAL suite or "listgeo" from the libgeotiff distribution. If gdalinfo shows something like this: Driver: GTiff/GeoTIFF Size is 5364, 7620 Coordinate System is `' Origin = (588067.750000,5331248.500000) you're the lucky owner of a file that has no coordinate system info (because the only thing after "Coordinate System is" is a pair of quotation marks). Another dead givaway would be: Metadata: TIFFTAG_SOFTWARE=Arc/Info which tells you that the image was processed with a piece of software that fails to put in all the right tags. If you get maps whose metadata say are in UTM projection but for which gdal indicates missing geoTIFF tags like it does in the example above, xastir won't be able to display them unless you fix them up. Fortunately, the GDAL library tool "gdal_translate" can do the job. For example, if you have a source map with metadata that says it's in UTM Zone 10, NAD83 datum, to make it suitable for Xastir to read you can do something like this: gdal_translate -a_srs EPSG:26910 original.tif georeferenced.tif The inclusion of the "-a_srs" option to gdal_translate forces the new tiff file to have the correct geotiff tags to indicate that coordinate system. The EPSG number to use for images in UTM projection with NAD83 datum is 26900 plus the UTM zone number. The EPSG number for UTM in NAD27 is 26700 plus the zone number. The above command will allow Xastir to read in the image and reference it properly. If you do the gdalwarp option above instead, you can end up with solid color areas between the edges of the original image and the lat/long rectangle that the image will be warped to; these extra pixels represent "no data" areas due to the difference in shape between the original rectangular image and the warped image. The color of this area depends on the colors present in the original image; GDAL attempts to use a color that is different from any in the source image. If those areas don't matter to you, then either method will work for you. If you're planning to tile multiple UTM images together, then the gdal_translate option is best. If your maps are NOT in UTM, you must also gdalwarp, because xastir cannot properly display geotiffs that are in projections other than UTM or "unprojected" lat/lon. EPSG numbers for odd-ball coordinate systems can be found at http://www.remotesensing.org/geotiff/proj_list/Wkt_adam.zip Maps that require gdalwarp include the FAA sectionals mentioned above, and some topo maps in obscure state plane coordinates from various state GIS departments. XASTIR can only use GeoTIFF files that are 8-bit per pixel with one band Some geotiff files contain multiple bands or multiple bytes per pixel. Xastir currently uses only BYTE format, so you may need to convert the geotiff file with gdal_translate. The number of bands, bytes per pixel and other information about geotiff files can be obtained using gdalinfo. One-band, 16- or 32-bit-per-pixel: The command "gdal_translate -ot BYTE original.tif new.tif" can convert 16 and 32 bit per pixel geotiffs to ones that can be used by xastir Multiple band, 8-bit-per-pixel: The command "gdal_translate -ot BYTE -b 1 old.tif new.tif" can extract a single band as a grey scale layer from a multi-band geotiff file, but this is probably not what you really want. The command rgb2pct.py old.tif new.tif can create a single band palette based geotiff from a three band rgb tif by dithering the colors down to a small palette. This last tool requires gdal built with Python support. See the gdal documentation for these tools for further information. More manipulations of GeoTIFF files: gdal also provides several additional tools that can be used to tile maps or chop them up into smaller pieces, but explaining the details of that process is probably beyond the scope of this document. See the man pages for "gdal_translate" and "gdal_merge.py" for an explanation of how those tools could be used to accomplish this. .geo files/online maps & graphics: If you have ImageMagick and wget or libcurl installed, .geo files for NWS radars are available from one of these sites: ftp://gcpoolz.com/geos/Srb_geos.zip http://we7u.wetnet.net/xastir/maps/radar-geos.tgz You'll probably want to add an IMAGESIZE line to each one to speed up loading when some radars are offscreen: (bash syntax, modify for your shell...) for a in srb_*; do echo "IMAGESIZE 620 620" >> $a; done NOTE: For .geo files with an ftp or http address for fetching the image, IMAGESIZE is currently a REQUIRED parameter in the .geo file. For .geo files where the image is resident on your hard drive, the IMAGESIZE tag is optional. Please also note that the coordinates in the .GEO files are expressed in decimal degrees, and are listed with longitude first then latitude on the TIEPOINT lines. Other tags you can put in a .geo file: DATUM: (not used, yet...) PROJECTION: Currently only supports "TM" for transverse Mercator. REFRESH: number of seconds to reload the maps. Multiple maps with different values pick the smallest value. TRANSPARENT: Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffff. Value can be decimal or hex if preceeded by "0x". Multiple TRANSPARENT lines can be used in a file to make multiple colors transparent. CROP: removes borders. Values are [left top right bottom] with (0,0) at the upper left. A good value for the NWS radar images above is "CROP 35 20 616 600" GAMMA, CONTRAST, NEGATE, EQUALIZE, NORMALIZE, LEVEL, MODULATE: These are all ImageMagick options, and are documented there, and briefly in the xastir help file. "Find Address" feature (US only): The "Find Address" feature is based on the open source geo-coder by Dan Egnor and as such uses the same format for the data. You can download preprocessed data based on Census Tiger 2003 data at: http://www.dementia.org/geocoder/tgr2003/ Reprocessed geocoding files from the 2006 Second Edition TIGER/Line data were produced by Jason Winningham in June of 2007 and made available on the TAMU FTP server by Gerry Creager. They are much better than the 2003 data, and it is recommended that they be used instead. Download them from ftp://aprs.tamu.edu/pub/geocode/ Geographic Names Information System Labels: These aren't maps, but are collections of name labels for locations. These display at various zoom levels like Dos/WinAPRS map labels, but are also searchable from the Maps menu. http://geonames.usgs.gov/ Click the link "Download GNIS Data: State and Topical Gazetteers" on the left. These files should be renamed in the form ".gnis" after download, where is the abbreviation for the state that they cover, and should be placed in the /usr/local/share/xastir/GNIS/ directory. To make sure that maps are layered correctly with GNIS labels on the top of the map stack, plus searchable, it is suggested that you link /usr/local/share/xastir/maps/z to this GNIS directory. Type this as root to create the link and directories: cd /usr/local/share/xastir/maps ln -s ../GNIS z The map files must end in ".gnis" to be used by Xastir, and must be in pipe delimited format. These are readily available from the above link with such filenames as "AZ_DECI.TXT". The files must be renamed to .gnis, and the trailing whitespace should be removed for speed. This can be accomplished in one step with the following command. (bash style...) for a in *deci; do sed -e 's/[ ]*$//g' < $a > `basename $a _deci`.gnis; done Individual files can have whitespace removed as follows: sed -e 's/[ ]*$//g' < inputfile > outputfile Populated places GNIS file can be had at: http://geonames.usgs.gov/stategaz/POP_PLACES_DECI.zip A note from Jason Winningham, kg4wsv: "The file has over 181k records in it. You can use the following command to weed out all places with populations less than 1000, and get it down to just under 14k records, which is really fast to load: awk -F\| '{if ($17 > 1000) print $0}' \ /usr/local/share/xastir/GNIS/0pop_places.gnis \ >/usr/local/share/xastir/GNIS/0pop_places_over_1k.gnis I stuck a zero at the beginning of the filename so this would show up in the GNIS directory before any of the state files." County weather Warning maps (requires shapefile support): The latest shapefile format weather maps may be found here: http://www.nws.noaa.gov/geodata/ or more easily found here (but not guaranteed to be the most current: http://we7u.wetnet.net/xastir/Counties/ We now have a script in the xastir/scripts directory called "get-NWSdata" which fetches the files you need and plops them into the correct directory and unzips them. Run that script as root. It requires "wget" to work. You may then try the NWS-TEST.log test shown below to verify proper operation. -------------------------- The files of interest are: -------------------------- NWSI Libraries: --------------- County Warning Area Boundaries (c_*.zip) Public Zone Boundaries (z_*.zip) Coastal and Offshore Marine Zones (mz*.zip, oz*.zip, hz*.zip) Fire Weather Zone Boundaries (fz*.zip) County Libraries: ----------------- AWIPS Counties (w_*.zip) Unzip those files in the /usr/local/share/xastir/Counties/ directory and Xastir should find them and use them for weather alerts. Be sure to include the .shp, .shx, .and dbf. Note that you can also use the county file as the background polygon filled map for drawing county lands and borders. Either make a link to these files from your maps directory, or copy the files there so that they show up in the Map Chooser. To test whether the weather alerts are working (whether weather?), copy the NWS-TEST.log file to your ~/.xastir/logs/ directory and then bring it in to Xastir using the File->Open Log File option. Zoom in to the WA/OR/ID area (Pacific Northwest) and you should see a picture that looks like this: Note that you may have to change the dates embedded in the file if Xastir thinks they are expired. See the notes at the top of that file. If the alerts are still active they should appear in the View->Weather Alerts dialog. Australian rules Weather Alerts http://wxsvr.aprs.net.au/implementation.html Download audio files: To play the wav files you will need a program such as vplay to play the audio file through your sound card. Grab xastir-sounds.tgz at the ftp site you downloaded Xastir, or at ftp://ftp.tapr.org/software_lib/Linux/xastir/xastir-sounds.tgz Un-tar the file. Put the sounds files into the /usr/local/share/xastir/sounds directory where Xastir can find them. (FIXME: thunder.wav is missing?). Download FCC and/or RAC Database files: If the FCC database is installed, a Search FCC Database button will appear in the station info box. If the RAC (Radio Amateurs of Canada) database is installed, a Search RAC Database button will appear for callsigns beginning with "VE" or "VA". The download and installation of these is automated in the get-fcc-rac.pl script included with Xastir, but you may install them by hand individually if you wish as described here: To use the FCC lookup: ---------------------- Download: http://wireless.fcc.gov/uls/data/complete/l_amat.zip (The only file needed from this 87 Meg zip is the EN.dat file) **** NOTE To use the data base file it must be sorted first!!! **** unzip l_amat.zip To sort the file, make sure you have plenty of disk space for this as the file is BIG! cat EN.dat | /usr/bin/perl -pe 's/\r\r\n//g' | sort +4 -t \| > EN.dat.sorted Install it in the xastir/fcc directory: su mv EN.dat.sorted /usr/local/share/xastir/fcc/EN.dat To use the RAC lookup: ---------------------- Download: http://205.236.99.41/%7Eindicatif/download/amateur.zip unzip amateur.zip mv AMATEUR.RPT /usr/local/share/xastir/fcc/AMACALL.LST Hiking trails from National Geographic's Topo or mapXchange: ------------------------------------------------------------ For those of you who may be familiar with National Geographic's Topo! program, there's a way to use the user-saved data (but not topo maps themselves) from within Xastir. Many users create TPG and/or TPO files in TOPO from GPS data and/or hand-drawn routes. They can then upload them to the mapXchange site, and in fact there are many hiking trails that one can download for free from that site. Okay, how to use them? Go to . Go to the Project page and then the CVS page and follow the instructions for grabbing the CVS gpsbabel sources. Only CVS has the Topo version 3.x support, which was just recently added (May 2006). Follow their instructions for building/ installing/using the program. It's a command-line program where you specify the input and output formats and filenames. Using this program you can snag the interesting data out of the files and convert it to GPX format. Once you have that, you can use the "gpx2shape" script to convert them to Shapefiles. Xastir can then use them as map files. WHERE TO FIND MORE INFO ON MAP DATUMS, ETC: Geodesy: http://oceanservice.noaa.gov/education/geodesy/welcome.html "Geodesy for the Layman" http://www.ngs.noaa.gov/PUBS_LIB/Geodesy4Layman/toc.htm MAP CACHING (WORKS WITH MOST ONLINE MAPS): Map caching works in conjunction with the map download routines, which fetch maps from http or ftp addresses. The map caching features use functions found in Berkeley DB 4.0 library, AKA libdb (version 4.0 or better), to create and manage a cache directory and a persistent database of information about the files in the cache directory. This directory defaults to ~/.xastir/map_cache. The files under this directory can be cleaned up or removed by hand at any time - the caching routines will simply download the maps and put new entries into the .db file. Map files are saved with filenames that include the number of seconds since the Unix epoch. This allows the caching routines to easily determine the age of maps so that older cached maps can be deleted. This is currently (Dec 2004) controlled with a compile time maximum age setting. See map_cache.h for specifics and for brief documentation about all of the map_cache functions. DRAWING YOUR OWN MAPS USING XASTIR ITSELF: The final result here will be ESRI Shapefile vector maps that you can then use within Xastir. You'll need Shapelib compiled into Xastir to make use of this feature (the private copy of Shapelib is fine for this). Turn off Object Transmit first (Interface menu). Place an object or item at the start location of your route. Click on the "Move" button to active move mode, then move that object around the map. Once you're done you'll have a bunch of straight lines that depict the course. Now bring up Station Info on that object and click on the Store Track button. If you've got Shapelib compiled in, you'll get a shapefile created with the track you just drew. After you're done you can delete the object and then turn on the Object Transmit toggle again. You'll end up transmitting the deleted final position of the object for a few hours unless you kill/restart Xastir, but that's ok. Nobody will see it on their maps 'cuz it's a deleted object. Look in ~/.xastir/tracklogs/ for the Shapefile. Copy it to your maps directory, changing the name on the three files as you like, then create a dbfawk file for it if you want to change how it is drawn in Xastir. Another way would be to drive the course with a GPS and then download the track via Xastir/GPSman to create a Shapefile map. Yet another way would be to drive it with an APRS rig and then Store Track as described above. You could also drive with GPS/Xastir (without APRS) to get a very detailed track and then save your own track. DRAWING SAR SEARCH SEGMENTS IN XASTIR: Turn on "Draw" mode (togglebutton at the top of the main window). The cursor should change to the Measure/Draw symbol. Using the middle mouse button, click on each vertice until you are almost done describing a polygon (don't close it yet). If you don't have a middle mouse button, clicking on BOTH mouse buttons at once will do it if you have "emulate third mouse button" enabled in your X Window System configuration. Go to Map->Draw CAD Objects->Close Polygon. The polygon will get completed, the area enclosed will be computed, and a dialog will pop up asking you for more information. You do not have to enter any information in this dialog, but a name of some type is helpful in order to be able to identify each segment when modifying/deleting/viewing these segments. Note that these CAD Objects get saved in a file and reloaded each time you start Xastir, but they cannot currently be written out as a map file and used as a general map. Note also that these CAD Objects don't get transmitted. They are currently for local display only. The display of various kinds of data related to these segments can be modified in the Map->Draw CAD Objects menu. Modifying parameters for any segment is done in the Map->Draw CAD Objects->CAD Polygons dialog. Click on the dashed line in the menus in order to separate that menu from the rest and allow you to keep the menu on the screen. This is very useful when drawing CAD Objects or changing display/filtering options. Turn off "Draw" mode when you're done. The cursor should return to normal. SUMMARY OF DISTANCE/AREA/ANGLE CALCULATIONS: DISTANCE: --------- *) Haversine formula (2-parameter atan version) for computing distance between two points, for our general distance routines: calc_distance() calc_distance_course() distance_from_my_station() *) Haversine formula (2-parameter atan version) in "Measure" for both the X/Y offsets and the total distance. Haversine formula is more accurate for shorter distances than spherical trigonometry calculations. Both methods are equivalent for longer distances. Both are Great-Circle calculations (as opposed to Rhumb-line or planar geometry). See the GIS FAQ for info on these methods. Dr. Math website mentions both of these and refers people to the same GIS FAQ. Also note that the Haversine formula is ill-conditioned if the two points are antipodal (on opposite sides of the Earth). From the GIS FAQ: "but the error, perhaps as large as 2km (1 mi), is in the context of a distance near 20,000km (12,000 mi)." For our purposes that's just fine. AREA: ----- *) Area of a spherical rectangle from Dr. Math's website for the "Measure" function. There are errors in their last two derived formulas. They have been notified of it. Our implemented code is correct. *) The area calculation for CAD Object Polygons is probably not spherical, but closer to planar. It might take some doing to calculate the area of irregular polygons on a spherical surface. We use Greene's Theorem to compute the area based on the vectors. The lengths of each vector are computed via the Haversine formula, so it's not strictly a planar area calculation either. Somewhere in-between planar and spherical? This should be plenty good enough for areas that are less than 12 miles on a side (that's about where planar geometry starts to diverge from spherical trigonometry), perhaps also for somewhat larger areas than this due to the advantage of computing the vector lengths with the Haversine formula. ANGLE: ------ *) Great Circle departure angle for the "Measure" function. *) Great Circle departure angle for the calc_distance_course() function. *) Dead-reckoning angle is essentially a Rhumb-line calculation (constant heading), with a few caveats: We compute the next point along a constant angle based on the last position transmitted, the time elapsed, and the course desired. This then gets corrupted a bit either by the standard APRS grid that it has to snap to (and the position snapped to for the previous position) and/or by the relatively course angle available for Base-91 compressed positions. Standard APRS positions give 1-degree angular resolution but 60-foot or so grid points. Base-91 Compressed positions give something like 1 to 3-foot grid points but less angular resolution (+/- 2 degrees. We can't win! The end result is that we start off like a drunk sailer due to our short transmit times and the above limitations, then the angle smooths out as the time increases between the transmits. You can see this easily at zoom level 1 when you place an object, when you make a change to an object, or move an object (transmit rate goes up for any of these conditions). Dead-reckoning effectively does a Rhumb-Line calculation as it is trying to do a constant heading. That means it is not the shortest distance between the points. I'm still trying to get my head around that last concept as it is counter-intuitive to someone versed in compass/maps on land and with shorter distances. A Great-Circle route is the shortest distance between two points on a sphere, whereas a Rhumb-line is what you get if you move along a constant compass heading and is a bit longer. We probably do not need to go to ellipsoid calculations for Xastir. Spherical calculations should be easily accurate enough for what we do. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/README.OSM_maps000066400000000000000000000207631501463444000167130ustar00rootroot00000000000000 Copyright (C) 2000-2023 The Xastir Group Using OpenStreetMap in Xastir ------------------------------------------------------------------------ CONTENTS Introduction Map Types Map Sources and Renderings (Styles) Map Cache Sharing Tiles Map Definition Files Copyrights and Licenses Introduction ------------ What, you may ask is 'OpenStreetMap' (OSM)? From the web site, www.openstreetmap.org, we read that "OpenStreetMap is a free editable map of the whole world. It is made by people like you". The tag line for the map is "The Free Wiki World Map". Xastir will display bitmap versions of the OSM. There are multiple renderings of the OSM to choose from and, by default, nine (9) are available in Xastir. Map Types --------- Xastir can use two different map types based on OSM: static and tiled. Static maps are bitmaps that are least as large as the Xastir window. Tiled maps are built up from 256x256 pixel images. Static maps are also assembled from tiles, but the assembly occurs at the server and the full size image is downloaded to Xastir. There is a major disadvantage to static maps: even slight changes in map position requires a new map download. Most online maps, including OSM, use map tiles that follow the "Web Mercator" projection and tiling scheme. The Web Mercator projection was first popularized by Google Maps. It is a modified Mercator projection, using a hybrid spheroid/ellipsoid model that is faster to compute. Wikipedia has a nice description: https://en.wikipedia.org/wiki/Web_Mercator. Map tiles are referred to by their zoom level, and row and column number. Major providers (such as OSM, Google, Apple, Mapbox, and Bing) and open source projects (such as Open Layers and openmaptiles.org) use the same general tile numbering scheme, although they vary in the specific sequence of zoom/row/column numbers, and the supporting parts of the URL. The URL for a particular tile looks something like this: https://a.tile.openstreetmap.org/11/329/715.png (tile server a, zoom level 11, column 329, row 715). You can see more in this Wikiepedia article: https://en.wikipedia.org/wiki/Tiled_web_map. Bitmap images, whether static or tiled, are available for only a limited number of zoom levels. There are 18 possible zoom levels. It takes 2^zoom tiles to represent 360 degrees. Since the tiles are 256 pixel squares, there are 2^(zoom + 8) pixels in 360 degrees. When the Xastir scale is different from a bitmap image's zoom level, the bitmap image is scaled. However, scaled bitmaps tend to look ugly. The scaled bitmap can have jagged lines, unequal pixel sizes, and/or missing information. At best a scaled bitmap looks blurred, but more typically some pixels will be enlarged into visible blocks or compressed invisibility. You can use the F4 key to adjust the Xastir scale to approximate the OSM zoom level and refresh the display. (The key can be changed by modifying a variable in the OSM definition (GEO) files. Map Sources and Renderings (Styles) ----------------------------------- The OSM data is rendered into tiles using different styles. The easiest place to view and compare the styles is at http://ojw.dev.openstreetmap.org/StaticMap/?mode=Style& Tiles can be retrieved from a number of servers. The supplied map definitions will download tiles from http://tile.openstreetmap.org/ Map Cache --------- Static maps are cached with other bitmap map images in the ~/.xastir/map_cache/ directory. Tiles are cached separately to make it possible to share them with other applications. By default tiles are cached in ~/.xastir/map_cache/OSMtiles/, but that location can be changed on a by-style basis. The tiles are organized directories by style, zoom level, and longitude: ~/.xastir/map_cache/OSMtiles/ + / | + / | / | + [0 ... (2^zoom - 1)].png + / ... Note that 'longitude' is a tile number between 0 and (2^zoom -1). Xastir downloads tiles as needed. If Xastir is compiled with libcurl support, then it will check for updates to tiles that have been cached for 7 days or more. See http://wiki.openstreetmap.org/wiki/Tile_usage_policy If a tile can not be downloaded for any reason or if the downloaded file is not usable image, then the downloaded file (if any) will be deleted and a red area will be shown in it's place on the display. NOTE: Run Xastir at debug level 512 (-v 512) for more information on download issues. At debug level 512, corrupt tile files will not be deleted. Examining the contents of the corrupt files can be informative. If Xastir is compiled with libcurl support, then debug level 8192 will enable verbose output from libcurl. WARNING: Corrupt tile files will not be deleted when running at debug level 512. If you do not delete them manually before restarting Xastir, then the first time Xastir displays the tile it will be shown in red and then deleted from the cache. Sharing Tiles ------------- The directory structure used to cache tiles is common to other programs, though the style names are typically different. An example of a program that can share tiles with Xastir is TangoGPS (http://www.tangogps.org). Here are some examples of how you can share tiles with TangoGPS (the setup for other programs would be similar): 1) Setup a symlink at the style level of the caches $ cd ~/.xastir/OSMmaps/ $ ln ~/Maps// 2) Change the Xastir map definition file to specify the TangoGPS cache by changing the following variables (see the next section for more information): OSM_TILED_MAP- TILE_DIR /home//Maps 3) Share all styles and tiles by creating a symlink at the top level of the cache. This also requires changing the Xastir map definition files to specify the style names used by TangoGPS: $ cd ~/.xastir $ rm -rf OSMmaps/ $ ln -s ../Maps OSMmaps Map Definition Files -------------------- OSM map type, style, server, cache directory, and function keys are specified in Xastir GEO files. By default the files are located in the /usr/local/share/xastir/maps/Online/ directory. The supplied definition files have filenames of this form: OSM_.geo - static maps OSM_tiled_.geo - tiled maps Where is replaced with the style name. Note that could be any unique string and is not required to be the style. Read the comments in the supplied definition files for more information. Copyrights and Licenses ----------------------- Maps and tiles from the OpenStreetMap project are Copyright OpenStreetMap and contributors, CC-BY-SA http://www.openstreetmap.org/ http://creativecommons.org/licenses/by-sa/2.0/ in addition, tiles from CloudMade are Copyright CloudMade, CC-BY-SA http://www.cloudmade.com/ http://cloudmade.com/about/api-terms-and-conditions http://cloudmade.com/terms_conditions TopOSM tiles are a composite of CC-BY-SA and public domain data, including MassGIS data. See http://wiki.openstreetmap.org/wiki/TopOSM for more information. Changing the Displayed Attribution ---------------------------------- The licenses from OpenStreetMap and CloudMade require attribution that is met, in part, by a label shown at the top left corner of the map. Two label images have been provided, one shows icons and the other shows black text on a white background. You can change between the two label styles by changing a symlink: $ cd /usr/local/share/xastir/maps/ # your installing may differ! $ rm CC_OpenStreetMap.png $ ln -s CC_OpenStreetMap_txt.png CC_OpenStreetMap.png or $ ln -S CC_OpenStreetMap_logo.png CC_OpenStreetMap.png ------------------------------------------------------------------------ Xastir-Release-2.2.2/README.developers.md000066400000000000000000000213711501463444000200000ustar00rootroot00000000000000# Developer notes on creating releases Since the move to git, the old process we followed to push development snapshots and stable releases to SourceForge is no longer possible, nor especially helpful. With git and github, we are doing away with the concept of development snapshots, because one can always just download a tarball of the current repo state from github. We are also simplifying the stable release process, doing away with the difference between building a tarball release and building from a git clone. ## Development snapshots Xastir migrated to git and github instead of cvs and sourceforge, and therefore creating "development snapshots" isn't necessary, because every commit is essentially a development snapshot that can be checked out by referencing its SHA-1 hash. Furthermore, github allows users to download code as a tarball directly without needing to clone, so we need not make a duplicate process for it. ## Stable Releases Stable releases are the enduring, numbered releases that tend to make it into official package repositories (eventually). It is necessary to do more for these releases than just tag a repository state, because most package management systems require that a stable version of the code be downloadable, and don't support pulling versions-of-the-day out of source code management systems. Beginning with release 2.1.8 we stopped providing "configure" scripts and all the droppings from "bootstrap.sh" in release tarballs, and all users must now use "bootstrap.sh" as a first step in building Xastir. ### Stable release process in a nutshell - Get master ready for a release. - Update version number. - Test everything. - Tag the repo. - Push the repo and the tag to Github. - Define a release on github and associate it with the tag. - Email interested parties that there has been a release. - Go back and update the version number on master and move on. ### Stable release in gory detail - Make sure the current state of the master branch is what you want to release. This should include all documentation updates and help file updates. Only when the master branch is really ready to release do you perform the following steps. Let's assume we're creating release X.Y.Z, and that our Xastir clone and working directory is in ~/XASTIR/Xastir. - By our long-standing convention, stable releases are always even numbers in the last field of the release number, and odd numbers mean "this is a development version." So whatever version number appears in configure.ac on the master branch is going to be odd at the moment, and you're going to pick X.Y.Z so that the new Z is even. - Change the version number in configure.ac to X.Y.Z. Grep around the code and remember to fix any other places where the old version string appears (there should, at this point, not be any). Commit this change: git add configure.ac git commit Mention why you're doing this in the commit message (e.g., "Update release version number"). Follow our commit log message guidance in CONTRIBUTING.md - Run bootstrap.sh or "autoreconf -i" - Make sure the program builds, and do so in a fresh build directory, just as a first-time user would have to do: mkdir build-release-check cd build-release-check ../configure [options] make cd .. If the code builds you should be in good shape, and you should also try querying the binary it produced to have it print its version: build-release-check/src/xastir -V Confirm that it is reporting the version you expect it to. It will have additional decorations indicating stuff about git, ignore those. For safety's sake, you should remove the build directory now, too. rm -rf build-release-check - You now have a working directory that should look like what we want to distribute to users. Check that there are no uncommitted changes: git status should tell you you're on master, and that you're one commit ahead of "origin/master", with nothing to commit and a clean working tree. If it says anything else, figure out why and get the current working tree to the right state, with all important changes committed properly. - Create an annotated tag marking the current state of the repo as your new release: git tag -a -m "Xastir Release X.Y.Z" Release-X.Y.Z - At this point, you are almost done, but all of your changes are only in your local repository clone. Double check that it really works by creating a tar file of your code from the tagged state, then try to build it somewhere other than in your git checkout directory: git archive --format=tar.gz --prefix=Xastir-Release-X.Y.Z/ Release-X.Y.Z > ~/src/Xastir-Release-X.Y.Z.tar.gz This process will exactly reproduce what Github will be doing when we're finished and actually create the release. Now make sure it builds: cd ~/src tar xzf Xastir-Release-X.Y.Z.tar.gz cd Xastir-Release-X.Y.Z ./bootstrap.sh # You could also use "autoreconf -i" mkdir build cd build ../configure [options] make - If the sanity check above worked, you can throw away the testing tarball and unpacked code: cd ~/src rm -rf Xastir-Release-X.Y.Z Xastir-Release-X.Y.Z.tar.gz - If the sanity check did NOT work, then you need to go back to your original working directory and fix any problems you found. Commit your changes, and then MOVE THE TAG so it points to your NEW proposed release: git tag -d Release-X.Y.Z git tag -a -m "Xastir Release X.Y.Z" Release-X.Y.Z Now go back and redo the sanity check. Repeat until the tarball you created actually produces a working Xastir. - Now go back to your working directory and finish up by pushing the code and tag to Github: cd ~/XASTIR/Xastir git push origin master git push origin Release-X.Y.Z - Log in to github and go to the Xastir project releases page at http://github.com/Xastir/Xastir/releases. Click the "Draft a new release" button. Put your tag name (Release-X.Y.Z) into the dialog box that says "Tag version" and Github will display a note that it found a matching, existing tag. Fill in the rest of the form: - Give the release a name ("Xastir Release X.Y.Z") that will appear prominently above it in the releases list. - Enter some release notes in the large text box below the title where it says "Describe this release." Ideally, you should list release highlights (new features, bug fixes, etc.). Use Markdown to pretty up the text, using the Preview tab to render the markdown until it looks the way you want it to. - Click "Publish Release." - You have finished releasing the code as far as Github is concerned. This new release will now appear on the "Releases" page, along with links to tar and zip files for the source code and the release notes you just created. The fixed URL https://github.com/Xastir/Xastir/releases/latest will always point to the most recent release. The source code download link will be https://github.com/Xastir/Xastir/archive/Release-X.Y.Z/Xastir-Release-X.Y.Z.tar.gz with the obvious change for the zip version. - The last step here is to announce the new release in all the usual places. These days it is probably enough to announce it on the xastir mailing list, and possibly the aprssig and linux-hams groups. No need to spam every ham radio mailing list. On the other hand, the Xastir wiki does recommend sending notification of all releases (both development and stable) to: - xastir at xastir.org - nwaprssig at nwaprs.info - aprssig at tapr.org - aprsnews at tapr.org - macaprs at yahoogroups.com - aprs at yahoogroups.com and stable releases to: - SAR_APRS at yahoogroups.com - CSAR at yahoogroups.com - aprs at mailman.qth.net - linux-hams at vger.kernel.org - linux at tapr.org - linux-hams-using-ax25 at yahoogroups.com This list is probably excessive nowadays, and probably contains a lot of groups that are long gone. #### Getting master ready to move on All of this work got the X.Y.Z release done, which has now been finished and pushed to github. Now we need to change the version number on the master branch so that development versions show a different version than releases. - Make sure you're still in your master branch in your main clone: cd ~/src/Xastir git checkout master - Edit configure.ac and change the version number to be one higher than the release you just did. So if you just pushed release 2.1.8, set the version to 2.1.9. - Commit this change and push it to github. git add configure.ac git commit git push The release is done, and now the repo is ready for further development. Xastir-Release-2.2.2/README.md000066400000000000000000000236041501463444000156320ustar00rootroot00000000000000# README ------------------------------------------------------------------------ Please at least SKIM this document before asking questions. In fact, READ IT if you've never successfully set up Xastir before. PLEASE! READ IT! If you haven't read this file, and ask for help expect to be told to READ the README file first! or RTFM :) Contents: 0. Important notice 1. What is Xastir? 2. How do I get Xastir & Git usage 3. Quick startup 4. Upgrading 5. Identification notes 6. OS-specific notes 7. Gating weather alerts 8. Boring legal stuff 9. Mailing list 10. Documentation 11. Obtaining help ------------------------------------------------------------------------ 0. NOTICE Please read this file carefully before trying to set up Xastir. This software was developed to be used by licensed amateur radio operators. You are responsible for any information transmitted or propagated on any network. 1. WHAT IS XASTIR? Xastir is an open-source project to create a free X11 graphical APRS(tm) client. APRS(tm) use amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. Xastir currently runs under several flavors of Linux and BSD Unix. A few people are running Xastir on Solaris Unix, FreeBSD, Lindows and Mac OS X, but there may be small changes necessary in order to get Xastir to configure/compile on some systems. There are a few notes below which may help in this task. Most of the developers use Linux which makes it the best supported platform at the moment. Xastir is an open-source project: Most sources, documentation, and binaries are available under the GPL license, with a few modules available under other open-source or public domain licenses. More information on Xastir can be found here: * http://xastir.org * http://github.com/Xastir including the latest releases, Git access (lets you download the latest developers' code), and information on how to join Xastir mailing lists. Note that you must be subscribed in order to post to the mailing lists. SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used. Thanks to Tony and Steve for that contribution! -- The Xastir Group. 2. HOW TO GET XASTIR Xastir is currently developed at You can get the latest version of Xastir from there. You might try for help and information, particularly the Xastir mailing list (listed near the bottom of the page). * Git USAGE Obtain the *very latest* version of Xastir under development by using Git. See the file [README.GIT](README.GIT) for more details. * Release version tarballs You can get the latest packaged release source code without git at https://github.com/Xastir/Xastir/releases. Be warned that packaged source tarballs may be quite old and not representative of the current state of the project. We highly recommend not using this method unless you have a specific reason to stick to official releases. 3. QUICK STARTUP See [INSTALL.md](INSTALL.md) for a relatively quick overview of how to build and use Xastir. Check the Xastir wiki (http://xastir.org) for OS-specific guidance for building Xastir on your system. WINDOWS USERS: Please refer to the [README.CYGWIN](README.CYGWIN) file for specific instructions. 4. UPGRADING Upgrading Xastir that has been built from a recent Git clone is as simple as running "git pull" in the source tree and recompiling. 5. IDENTIFICATION NOTES Packet radio modes, by their very nature, typically identify themselves with every transmission. Xastir has a few features targeted to people who used Xastir in demonstrations and other broadcasts where Xastir itself is used over radio. Xastir can auto-ID via voice if Festival is compiled in and/or via a message splashed across the screen. It does this identification every 9.5 minutes if enabled. These identification modes were designed for broadcasting Xastir across fast-scan television (for events perhaps). Set the "ATV_SCREEN_ID" variable to 1 to enable the screen message, and "SPEAK_ID" variable to 1 to enable festival to speak the message. These variables are in the ~/.xastir/config/xastir.cnf file. 6. OS SPECIFIC NOTES [The OS-specific notes that were here were horribly outdated and not maintained. That text has been removed. Please see the Xastir wiki at http://xastir.org in the "Installation Notes" section for OS-specific build guidance.] 7. GATING WEATHER ALERTS, STATIONS, OBJECTS/ITEMS TO RF ## Gating NWS Weather Alerts to RF: If you wish to gate NWS weather alerts from the Internet onto RF, you'll need to create a text file in the users directory as ~/.xastir/data/nws-stations.txt List each NWS station that you would like to transmit via RF. Wildcards are implied for lengths of 3 or greater. Here's what an example file looks like: # # Seattle, WA SEANPW # # Portland, OR (any alert type) PDX # # Pendleton, OR PDTNPW # # Medford, OR MFRNPW # All text should start at the beginning of the line. Once that file is in place, you'll need to hook up to at least one Internet server that is feeding you the weather alerts. You'll also need to have at least one RF interface up and running with transmit enabled on that interface. Make sure that "Interfaces->Disable Transmit: All" is not selected. You should now be gating NWS weather messages to RF. Turn on igate logging and look at that log file to view what you're sending out via RF. Don't forget to turn off logging or set up auto-rollover of the log files, else your hard drive might fill up with logging info. Auto-rollover of log files is typically accomplished via CRON. ## Gating Stations, Objects/Items to RF: The latest code also allows gating packets from specific stations to RF using the above method (except object/item packets). You can also gate objects/items to RF by name. The same wildcarding rules apply as listed above. Callsigns or object/item names listed in this file are case-insensitive, so they'll match any case in received packets. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.aprs.org/aprs-jota.txt 8. BORING LEGAL STUFF Xastir is Copyright by Frank Giannandrea. Xastir is distributed according to the GNU General Public License. There should be a copy of this license in the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As of Xastir 0.4.0 all changes made by the Xastir development team to the Xastir source code and any related files are Copyright (C) 2000-2023 The Xastir Group. The source code will still be distributed according to the GNU General Public License as Frank Giannandrea did in the past. There is no warranty, implied or whatever. You use this software at your own risk, no matter what purpose you put it to. You didn't pay for it, so don't expect magic. 9. MAILING LIST There are currently a couple of mailing lists about Xastir. xastir@xastir.org is the one relevant for most users. The xastir@xastir.org mail-list is dedicated to Bug reports, technical questions, your thoughts or suggestions on new features being added to Xastir, things that should be removed or fixed, amazing problems that even stump the guru's, etc... are what we want to see here. You must be subscribed to the list in order to post messages. To subscribe to the Xastir mailing list, send email to: xastir-request@xastir.org In the body of the message, put "subscribe xastir"; or go to http://xastir.org and click on "XASTIR MAILING LISTS" (in the "Resources" section near the bottom) to subscribe. ### DO NOT SEND FRANK EMAIL ABOUT XASTIR ### Frank is no longer developing the Xastir code (although he does put a word in every now and then) so don't bother e-mailing him. If you have a serious problem, email the Xastir mailing list and it will get to the coders. Please, before posting to this list, see what things are like, and when you do post, read over your post for readability, spelling, and grammar mistakes. Obviously, we're all human (or are we?) and we all make mistakes (heck, look at this document! ;). Open discussion and debate is integral to change and progress. Don't flame others over mere form (grammar and spelling), or even substantive issues either for that matter. Please read and follow the mailing list rules. A second mailing list, xastir-dev@xastir.org is intended for developer's discussion. 10. DOCUMENTATION We're trying to get the documentation up to date. If you feel that anything is missing here, or that anything should be added etc, please email xastir@xastir.org about it, thank you. 11. OBTAINING HELP Please read the file FAQ, and make sure you've followed any relevant instructions in INSTALL. If the problem still exists, feel free to ask on the Xastir mailing-list, as described above. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/README.qt000066400000000000000000000135641501463444000156620ustar00rootroot00000000000000LATEST STATUS: -------------- The File->Exit and Interface->Interface Control portions work. No other menu options have been implemented. It will connect to a server and display raw packets as they come in, but there are no maps, symbols, etc. There's not any packet decoding either. The networking is both IPv4 and IPv6 compatible. It compiles/runs fine and should be very cross-platform at this stage (must be compiled on each one though). INITIAL PREPARATION: -------------------- Qt4 development tools are required for compiling -or- GUI design. For SuSE Linux they are in the "libqt4-devel" RPM package. This includes "qmake", "uic", and "designer" (Qt4 Designer). You'll also need the gcc-c++ compiler installed. For SuSE Linux that's in the "gcc-c++" package. You can do manual builds or builds from within Qt Creator. In general I describe manual builds here. MANUAL BUILD: ------------- cd Xastir/src/qt ./build.sh RUN THE EXECUTABLE: ------------------- cd build ./xastir_qt & GENERAL QT4 NOTES: ------------------ *) Do an out-of-source build to keep the source code directory pristine. Perform all configure/compile commands from inside a "build" directory: mkdir -p build cd build *) Use QT 4 Designer to create the graphical elements. Each dialog/window gets written out to a separate *.ui file. designer & Open->mainwindow.ui *) Manual compile of ".ui" files: Use the "uic" compiler to compile .ui files to .h files: Note: The "qmake" command below does this automatically! uic -o *.h *.ui *) moc -o mydialog.moc mydialog.h *) Use "qmake -project" to create the initial .pro file for the os-independent build system. *) Include the .h files in the .cpp files for your C++ program. *) Use "qmake" to build the project. *) "make" Examples: (Generic, not for the Xastir project: uic -o ui_mydialog.h mydialog.ui moc -o mydialog.moc mydialog.h qmake -project qmake make Once the project branch has been checked-out, these steps issued from the command-line should compile it: cd Xastir/src/qt mkdir -p build cd build qmake ../xastir-qt.pro make Remember also that the *best* way to do multiple builds of an autoconfiscated code (and a qmake-ified code) is do do out-of-source builds, not in-source builds. Doing so keeps the source tree unpolluted with build droppings. Thus, mkdir ~/builds/xastir-qt -p cd ~/builds/xastir-qt qmake ~/src/xastir/qt/xastir-qt.pro make will build the qt stuff, and mkdir ~/builds/xastir-motif -p cd ~/builds/xastir-motif ~/src/xastir/configure make will build the normal build, and neither will interfere with the other. libqt4-devel rpm provides these binaries (as well as include files and others). Those with '*' are the ones we currently use: * /usr/bin/designer /usr/bin/lconvert /usr/bin/linguist /usr/bin/lrelease /usr/bin/lupdate * /usr/bin/moc /usr/bin/pixeltool /usr/bin/qdbuscpp2xml /usr/bin/qdbusxml2cpp /usr/bin/qdoc3 /usr/bin/qhelpconverter /usr/bin/qhelpgenerator * /usr/bin/qmake /usr/bin/qt3to4 /usr/bin/qttracereplay /usr/bin/qvfb /usr/bin/rcc * /usr/bin/uic /usr/bin/uic3 SPECIFIC NOTES: --------------- Here's what Qt Creator does when you do a Build->Clean All: ----------------------------------------------------------- Starting: /usr/bin/make clean -w make: Entering directory `/home/src/we7u/xastir/xastir-qt' rm -f moc_xastir.cpp rm -f ui_mainwindow.h rm -f main.o mainwindow.o moc_xastir.o rm -f *~ core *.core make: Leaving directory `/home/src/we7u/xastir/xastir-qt' Exited with code 0. Here's a Qt Creator Build->Build All command: --------------------------------------------- Configuration unchanged, skipping QMake step. Starting: /usr/bin/make -w make: Entering directory `/home/src/we7u/xastir/xastir-qt' /usr/bin/uic mainwindow.ui -o ui_mainwindow.h g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtNetwork -I/usr/include/QtGui -I/usr/include -I. -I. -o main.o main.cpp g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtNetwork -I/usr/include/QtGui -I/usr/include -I. -I. -o mainwindow.o mainwindow.cpp /usr/bin/moc -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtNetwork -I/usr/include/QtGui -I/usr/include -I. -I. xastir.h -o moc_xastir.cpp g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/QtCore -I/usr/include/QtNetwork -I/usr/include/QtGui -I/usr/include -I. -I. -o moc_xastir.o moc_xastir.cpp g++ -m64 -o xastir-qt main.o mainwindow.o moc_xastir.o -L/usr/lib64 -lQtGui -L/usr/lib64 -L/usr/X11R6/lib64 -lQtNetwork -lQtCore -lpthread make: Leaving directory `/home/src/we7u/xastir/xastir-qt' Exited with code 0. Here's a Qt Creator Build->Run qmake (I must have something misconfigured in my project): ----------------------------------------------------------------------------------------- Starting: /usr/bin/qmake /home/src/we7u/xastir/xastir-qt/xastir-qt.pro -spec linux-g++-64 -r CONFIG+=debug QMLJSDEBUGGER_PATH=/usr/share/qtcreator/qml/qmljsdebugger Exited with code 0. LINUX: ------ For Linux: Had to run "qmake;make" on a 32-bit system because all the files had been created on a 64-bit system. On a 64-bit system just run "make". Xastir-Release-2.2.2/README.sudo000066400000000000000000000065601501463444000162060ustar00rootroot00000000000000SUDO Instructions: ------------------ "sudo" is a command that can make your life much simpler. After you set it up that is! By adding a couple of lines to your /etc/sudoers file (using the "visudo" command to edit this file), you'll be able to run a few commands as root without having to type the root password each time. Another thing you can do at that point is automate the entire "git pull; mkdir -p build; cd build; ../configure; su; make install" process via a script. Here's how to set all of this up: Type "su" to become the root user, then type "visudo". This will bring up the "vi" editor on the /etc/sudoers file. If you'd like to learn more about what I'm going to describe, type "man sudoers" in another window and read about this file. Another man-page that is useful here is the "man sudo" page. Back to the editing: There's a section in there for user alias. Mine is labeled "# User alias specification". Add a line there that reads like this: User_Alias XASTIR = username1, username2, username3 where username1, etc, are valid usernames that you wish to be able to do Xastir installs. For instance you might have: User_Alias XASTIR = mikey Next, add a line near the bottom that reads like this: XASTIR ALL = NOPASSWD: /bin/chmod, /usr/bin/make Now write out and close the file. At this point the "mikey" user will have root permissions when he/she runs the commands "/bin/chmod" or "/usr/bin/make". Make sure the paths to those programs are correct for your system. Exit from "su" so that you're a regular (non-root) user again. Now, in the "xastir" source directory (mine is in "~/src/xastir"), create a script that reads like this. I named my script "update-xastir" but nearly any name for the script will do: -----------------cut here-------------------- #! /bin/sh git pull ./bootstrap.sh mkdir -p build cd build ../configure sudo make clean sudo make install sudo chmod 4755 /usr/local/bin/xastir -----------------cut here-------------------- Now type "chmod u+rwx update-xastir" to make that script executable. Actually, we've just created a script for Xastir that implements the above and called it "update-xastir". Do a "git pull" to get it. Try out the script. Type: ./update-xastir It should run through the entire update/configure/make/install process for Xastir. Remember to either change to the proper xastir directory before running it, or add a "cd" command at the beginning of the script so that it will run in the proper directory in all cases. If you add the proper "cd" command you can copy the script to /usr/local/bin and then run it as "update-xastir" from anywhere. Windows users: You may need to remove the "sudo" keyword on each line to have it work properly for you. A note from Gerry Creager as to another way to set up the sudoers file: "I now consider it a good idea to add the "gifted" users to the 'wheel' group and then solely enable wheel in /etc/sudoers; I've seen a recent article also supporting this." ------------------------------------------------------------------------ Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/REGRESSION_TESTS000077500000000000000000000716131501463444000167460ustar00rootroot00000000000000#!/bin/sh # Simple regression tests. Run through various combinations of the # configure flags, create a lot file, then grep for "warning" or # "error" through that log file when done. This is intended to be # run as a normal user on a system that has all of the optional # libraries installed and usable. # # Copyright (C) 2000-2023 The Xastir Group. # # Licensed under the GPL license. See the file "COPYING" for more # information. # NOTE: It might be wise to move, rename, or change permissions on # select header and/or library files when doing these tests, in # order to verify that the code does the right thing when these # libraries or headers are unavailable. Perhaps add a series of # tests just before the very last current test which do this. This # series of tests would probably by necessity be Linux-specific, and # perhaps even distribution-specific, so perhaps we should have a # command-line flag to enable those tests too. # # One test that definitely needs to be done (as root or sudo) is: # # chmod 000 /usr/include/magick # ./configure # make # chmod 755 /usr/include/magick # # The above will test the XPM code in map_geo.c to test whether we # can compile with XPM but without ImageMagick support. # Use this command to tail the status file through multiple # compiles: # # tail -F --max-unchanged-stats=1 -s 0.05 regression.log # date # Start an Xterm to show the regression log as the script runs: xterm -geometry 91x67-0+65 -e tail -F --max-unchanged-stats=1 -s 0.05 regression.log & nice ./bootstrap.sh # Test with ZERO options enabled #echo echo -n " 55 TEST: NONE: " rm -rf autom4te.cache (rm regression.log 2>&1) >/dev/null (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + ax25 #echo echo -n " 54 TEST: Sparse + ax25: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + festival #echo echo -n " 53 TEST: Sparse + festival: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + gpsman #echo echo -n " 52 TEST: Sparse + gpsman: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + imagemagick #echo echo -n " 51 TEST: Sparse + imagemagick: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + libproj #echo echo -n " 50 TEST: Sparse + libproj: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + geotiff #echo echo -n " 49 TEST: Sparse + geotiff: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + libproj + geotiff #echo echo -n " 48 TEST: Sparse + libproj/geotiff: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + shapelib #echo echo -n " 46 TEST: Sparse + shapelib: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-pcre \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + pcre #echo echo -n " 45 TEST: Sparse + pcre: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-dbfawk \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + dbfawk #echo echo -n " 44 TEST: Sparse + dbfawk: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + pcre/dbfawk #echo echo -n " 43 TEST: Sparse + shapelib/pcre/dbfawk: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + map-cache #echo echo -n " 42 TEST: Sparse + map-cache: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + errorpopups #echo echo -n " 41 TEST: Sparse + errorpopups: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-errorpopups 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + libgc #echo echo -n " 40 TEST: Sparse + libgc: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-libgc 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + profiling #echo echo -n " 39 TEST: Sparse + profiling: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-profiling 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + rtree #echo echo -n " 38 TEST: Sparse + rtree: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-rtree 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + shapelib/rtree #echo echo -n " 37 TEST: Sparse + shapelib/rtree: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-rtree 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test sparse + lsb #echo echo -n " 36 TEST: Sparse + lsb: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --without-ax25 \ --without-festival \ --without-gpsman \ --without-imagemagick \ --without-libproj \ --without-geotiff \ --without-shapelib \ --without-pcre \ --without-dbfawk \ --without-map-cache \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with ALL options enabled #echo echo -n " 35 TEST: ALL: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 34 TEST: --without-ax25: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-ax25 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 33 TEST: --without-festival: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-festival 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 32 TEST: --without-gpsman: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-gpsman 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 31 TEST: --without-imagemagick: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-imagemagick 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 30 TEST: --without-libproj: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-libproj 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 29 TEST: --without-geotiff: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-geotiff 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 27 TEST: --without-shapelib: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-shapelib 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 26 TEST: --without-pcre: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-pcre 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 25 TEST: --without-dbfawk: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-dbfawk 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 24 TEST: --without-map-cache: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-map-cache 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 23 TEST: --with-errorpopups: " rm -rf autom4te.cache rm regression.log (nice ./configure --with-errorpopups 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 22 TEST: --with-libgc: " rm -rf autom4te.cache rm regression.log (nice ./configure --with-libgc 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 21 TEST: --with-profiling: " rm -rf autom4te.cache rm regression.log (nice ./configure --with-profiling 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 20 TEST: --with-rtree: " rm -rf autom4te.cache rm regression.log (nice ./configure --with-rtree 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with each flag in turn, one flag at a time #echo echo -n " 19 TEST: --with-lsb: " rm -rf autom4te.cache rm regression.log (nice ./configure --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 18 TEST: ALL --without-ax25: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-ax25 \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 17 TEST: ALL --without-festival: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-festival \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 16 TEST: ALL --without-gpsman: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-gpsman \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 15 TEST: ALL --without-imagemagick: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-imagemagick \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 14 TEST: ALL --without-libproj: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-libproj \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 13 TEST: ALL --without-geotiff: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-geotiff \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 11 TEST: ALL --without-shapelib: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-shapelib \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 10 TEST: ALL --without-pcre: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-pcre \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 09 TEST: ALL --without-dbfawk: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-dbfawk \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 08 TEST: ALL --without-map-cache: " rm -rf autom4te.cache rm regression.log (nice ./configure --without-map-cache \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 07 TEST: ALL except errorpopups: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 06 TEST: ALL except libgc: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-errorpopups \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 05 TEST: ALL except profiling: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-errorpopups \ --with-libgc \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 04 TEST: ALL except rtree: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Test with all but one option enabled #echo echo -n " 03 TEST: ALL except lsb: " rm -rf autom4te.cache rm regression.log (nice ./configure \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" ################################################## # Test with ALL options enabled but various header files disabled #echo echo -n " 35 TEST: ALL: ImageMagick disabled " rm -rf autom4te.cache rm regression.log sudo chmod 000 /usr/include/magick # Disable ImageMagick headers (nice ./configure \ --with-errorpopups \ --with-libgc \ --with-profiling \ --with-rtree \ --with-lsb 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log sudo chmod 755 /usr/include/magick # Enable ImageMagick headers grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" ################################################## # Test default compile, no configure flags at all. This test will # also put the system back into a mode where a "make install" should # be proper for this exact system. #echo echo -n " 01 TEST: Default configure: " rm -rf autom4te.cache rm regression.log (nice ./configure 2>&1) >> regression.log #echo -n " " head -1 summary.log (nice make clean 2>&1) >/dev/null (nice make 2>&1) >> regression.log grep -i warning regression.log grep -i error regression.log | grep -vi errorpopups | grep -v "checking for strerror" # Cleanup rm -rf autom4te.cache rm regression.log date Xastir-Release-2.2.2/Regional.geo000066400000000000000000000002631501463444000166030ustar00rootroot00000000000000WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Regional Xastir-Release-2.2.2/Sub_national.geo000066400000000000000000000002671501463444000174650ustar00rootroot00000000000000WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_national Xastir-Release-2.2.2/Sub_regional.geo000066400000000000000000000002671501463444000174600ustar00rootroot00000000000000WMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_regional Xastir-Release-2.2.2/UPGRADE000066400000000000000000000073221501463444000153640ustar00rootroot00000000000000 Previous Install Notes: ----------------------- Backup all previous installed data! Xastir 0.1.0 users (if there are any of you still around!): For Xastir version 0.1.0 and below there are new file locations: All map data, TNC config data, and support files now go under the /usr/local/xastir directory. All personal config data, logs, etc are user the (user home dir)/.xastir directory (which will be created after xastir starts). You can copy (after your first xastir startup) your xastir.cnf file to your (user home dir)/.xastir/config directory. MAKE SURE YOU DELETE all lines referencing Files! Xastir may not run properly if you don't! If you have Xastir version 0.1.1 then your files are in the right place, just follow the typical build instructions. Xastir 0.2.0 users: Xastir 0.2.0 and newer have new device controls so you will need to setup your devices again with 0.2.0. Look at File->Configure->Interfaces and File->Configure->Defaults Xastir 0.3.x, 0.9.x, 1.0.x, 1.1.0: Versions above 1.1 drop privileges if they are run as root. If any of the Xastir files are owned by root, on only readable by root, they will cause problems. Fix these files by "chmod 644 filename" where filename is the problem file. Xastir 1.2.1 or later Git: On or about July 3rd, 2003, the locations of the Xastir system directories were changed. Existing users must go through this procedure in order to convert to the new directory structure. Note that if you've installed Xastir from RPM's or other packages, the migration scripts (xastir-migrate.sh and xastir-fixcfg.sh) may not work properly for you. These scripts are designed to move Xastir's system directories only from /usr/local/xastir to the new locations. If your Xastir files are installed elsewhere (/usr/share/xastir, /usr/lib/xastir, /usr/bin), you may need to perform the alternate procedure listed below under ALTERNATE. cd src/Xastir git pull ./bootstrap.sh mkdir -p build cd build ../configure make Shut down any running Xastir instances cd scripts su ./xastir-migrate.sh (this will move the Xastir system directories) make install (or make install-strip) chmod 4555 /usr/local/bin/xastir (only if required) exit (from root) ./xastir-fixcfg.sh (run this for each user that has ever run Xastir) ALTERNATE PROCEDURE (see note above): Remove the installed Xastir using the system tools for doing so (apt, rpm, etc). You'll probably wish to keep your maps directories and your ~/.xastir/config/xastir.cnf files. Make sure to delete any "callpass" or "xastir" binaries as well. Remove your ~/.xastir directory, subdirectories, and all contents (remember to save your xastir.cnf file if some of the settings are important to you). Move your maps directory to "/usr/local/share/xastir/maps" Configure/compile/install the new Xastir. When you start up the new Xastir, it will create a new xastir.cnf file with the proper directory paths defined in order to find the maps. After you start the new Xastir, you'll need to re-index all maps. The Xastir binary should be in /usr/local/bin/xastir if you installed from sources. Xastir files are now installed in: /usr/local/bin/ /usr/local/lib/xastir/ /usr/local/man/ /usr/local/share/xastir/* ------------------------------------------------------------------------ Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/USTigermap.geo000066400000000000000000000012241501463444000170610ustar00rootroot00000000000000WMSSERVER # URL https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_PhysicalFeatures/MapServer/WMSServer?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Primary%20Roads,Primary%20Roads%20Labels,Secondary%20Roads,Secondary%20Roads%20Labels,Local%20Roads,Local%20Roads%20Labels,Railroads,Railroads%20Labels,Linear%20Hydrography,Linear%20Hydrography%20Labels,Areal%20Hydrography,Areal%20Hydrography%20Labels,Glaciers,Glaciers%20Labels,National%20Park%20Service%20Areas,National%20Park%20Service%20Areas%20Labels,Military%20Installations,MilitaryInstallations%20Labels&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE #TRANSPARENT 0x999999 Xastir-Release-2.2.2/USTigermapBorders.geo000066400000000000000000000005251501463444000204050ustar00rootroot00000000000000WMSSERVER # URL https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_Current/MapServer/WMSServer?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Incorporated%20Places,Incorporated%20Places%20Labels,States,States%20Labels,Counties,Counties%20Labels&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE TRANSPARENT 0x999999 Xastir-Release-2.2.2/WMS_USGS_Hydrography.geo000066400000000000000000000003441501463444000207320ustar00rootroot00000000000000WMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSHydroCached/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.2/WMS_USGS_ImageryOnly.geo000066400000000000000000000003431501463444000206700ustar00rootroot00000000000000WMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSImageryOnly/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.2/WMS_USGS_ImageryTopo.geo000066400000000000000000000003431501463444000206700ustar00rootroot00000000000000WMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSImageryTopo/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.2/WMS_USGS_ShadedReliefOnly.geo000066400000000000000000000003501501463444000216100ustar00rootroot00000000000000WMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSShadedReliefOnly/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.2/WMS_USGS_Topo.geo000066400000000000000000000003361501463444000173540ustar00rootroot00000000000000WMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSTopo/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 # Xastir-Release-2.2.2/acinclude.m4000066400000000000000000000770361501463444000165540ustar00rootroot00000000000000# acinclude.m4 for Xastir # # Copyright (C) 2000-2023 The Xastir Group # # test for devices. Avoid the tests on Cygwin as they hang on some # WinXP boxes. # AC_DEFUN([XASTIR_DETECT_DEVICES], [ AC_MSG_CHECKING([for devices]) if test -d /proc/registry ; then ac_tnc_port=/dev/ttyS0 ac_gps_port=/dev/ttyS1 elif test -c /dev/cuaa0 ; then ac_tnc_port=/dev/cuaa0 ac_gps_port=/dev/cuaa1 elif test -c /dev/ttyS0 ; then ac_tnc_port=/dev/ttyS0 ac_gps_port=/dev/ttyS1 elif test -c /dev/cua/a ; then ac_tnc_port=/dev/cua/a ac_gps_port=/dev/cua/b else ac_tnc_port=none ac_gps_port=none fi AC_DEFINE_UNQUOTED([TNC_PORT], "$ac_tnc_port", [Default TNC port.]) AC_DEFINE_UNQUOTED([GPS_PORT], "$ac_gps_port", [Default GPS port.]) AC_MSG_RESULT(found $ac_tnc_port and $ac_gps_port) ]) # add search paths AC_DEFUN([XASTIR_ADD_SEARCH_PATHS], [ AC_MSG_CHECKING([for search paths]) test -d /usr/local/include && CPPFLAGS="-I/usr/local/include $CPPFLAGS" test -d /usr/local/lib && LDFLAGS="-L/usr/local/lib $LDFLAGS" for d in /sw /opt /opt/local /usr/dt/share /usr/sfw /opt/sfw; do test -d $d/include && CPPFLAGS="$CPPFLAGS -I$d/include" test -d $d/lib && LDFLAGS="$LDFLAGS -L$d/lib" done AC_MSG_RESULT([done]) ]) # add compiler flags AC_DEFUN([XASTIR_COMPILER_FLAGS], [ # brutal! # check for sed maybe? if test "$ac_cv_prog_ac_ct_CC" = "gcc"; then gcc --help | sed -e "/^[^ ]/d" -e "/^ [^ ]/d" -e "/^ [^-]/d" -e "s/ //" -e "s/ .*//" > gccflags # I need a test for -Wno-return-type and -DFUNCPROTO=15 # before adding them for f in -no-cpp-precomp -pipe; do grep -- $f gccflags > /dev/null && CFLAGS="$CFLAGS $f" done # delete temporary file rm -f gccflags # add any other flags that aren't added earlier # Can't add "-Wno-unused-parameter" as older compilers don't like # it. # for f in -W -Wall -Wpointer-arith -Wstrict-prototypes; do echo $CFLAGS | grep -- $f > /dev/null || CFLAGS="$CFLAGS $f" done # Now check whether to use -Wno-unused-parameter (gcc 3) or -Wno-unused AC_MSG_CHECKING([whether compiler accepts -Wno-unused-parameter]) save_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -Wno-unused-parameter" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[]], [[int i;]])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no, using -Wno-unused]); CFLAGS="$save_CFLAGS -Wno-unused"]) # end gcc-specific checks fi # add any pthread flags now CFLAGS="$CFLAGS $PTHREAD_CFLAGS" AC_MSG_CHECKING([for compiler flags]) AC_MSG_RESULT(using $CFLAGS) ]) AC_DEFUN([XASTIR_DETECT_BINARIES], [ BINPATH=$PATH for d in / /usr /usr/local /usr/X11 /usr/X11R6 /usr/sfw /opt/sfw /opt/local /sw; do test -d $d/bin && echo $BINPATH | grep -- $d/bin > /dev/null || BINPATH="$BINPATH:$d/bin" done # it would be much nicer to do this in a for loop if test "$use_lsb" = "yes"; then AC_DEFINE_UNQUOTED(HAVE_CONVERT, 1, [Define if you have gm or convert]) AC_DEFINE_UNQUOTED(CONVERT_PATH, "/opt/Xastir/bin/gm convert", [Path to gm or convert]) else AC_PATH_PROG(gm, [gm version], no, $BINPATH) AC_CHECK_FILE(/usr/bin/gm.exe, gm="/usr/bin/gm") if test "$gm" != "no"; then AC_DEFINE_UNQUOTED(HAVE_CONVERT, 1, [Define if you have gm or convert]) AC_DEFINE_UNQUOTED(CONVERT_PATH, "${gm} convert", [Path to gm or convert]) else AC_PATH_PROG(convert, [convert --version], no, $BINPATH) AC_CHECK_FILE(/usr/bin/convert.exe, convert="/usr/bin/convert") if test "$convert" != "no"; then AC_DEFINE_UNQUOTED(HAVE_CONVERT, 1, [Define if you have convert]) AC_DEFINE_UNQUOTED(CONVERT_PATH, "${convert}", [Path to convert]) fi fi fi AC_PATH_PROG(lpr, [lpr /dev/null], no, $BINPATH) if test "$lpr" != "no"; then AC_DEFINE_UNQUOTED(HAVE_LPR, 1, [Define if you have lpr]) AC_DEFINE_UNQUOTED(LPR_PATH, "${lpr}", [Path to lpr]) fi #Find gv executable AC_PATH_PROG(gv, [gv], no, $BINPATH) if test "$gv" != "no"; then # Test gv version AC_MSG_CHECKING([gv version]) gv_new="no"; gv_version=`gv --version` gv_test=`echo $gv_version | cut -d ' ' -f 1` if test "$gv_test" != "gv"; then gv_version=`gv -v` fi gv_test=`echo $gv_version | cut -d ' ' -f 1` if test "$gv_test" != "gv"; then # No gv found. Put an AC_PATH_PROG here so the "then" clause has # something to do and so that we get proper output to the user. AC_MSG_RESULT([gv version test likely exited with error, this is what it said: $gv_version]) else gv_short_version=`echo $gv_version | cut -d ' ' -f 2` gv_major=`echo $gv_short_version | cut -d '.' -f 1` gv_minor=`echo $gv_short_version | cut -d '.' -f 2` gv_tiny=`echo $gv_short_version | cut -d '.' -f 3` if test "$gv_major" -gt 3; then gv_new="yes"; elif test "$gv_major" -ge 3 -a "$gv_minor" -gt 6; then gv_new="yes"; elif test "$gv_major" -ge 3 -a "$gv_minor" -ge 6 -a "$gv_tiny" -ge 1; then gv_new="yes"; fi if test "$gv_new" != "no"; then AC_MSG_RESULT([new, >= 3.6.1]) AC_DEFINE_UNQUOTED(HAVE_GV, 1, [Define if you have gv]) AC_DEFINE_UNQUOTED(HAVE_NEW_GV, 1, [Define if you have old gv]) AC_DEFINE_UNQUOTED(GV_PATH, "${gv}", [Path to gv]) else AC_MSG_RESULT([old, pre 3.6.1]) AC_DEFINE_UNQUOTED(HAVE_GV, 1, [Define if you have gv]) AC_DEFINE_UNQUOTED(HAVE_OLD_GV, 1, [Define if you have old gv]) AC_DEFINE_UNQUOTED(GV_PATH, "${gv}", [Path to gv]) fi fi fi if test "$use_festival" != "no"; then AC_PATH_PROG(festival, [festival], no, $BINPATH) if test "$festival" != "no"; then AC_DEFINE_UNQUOTED(HAVE_FESTIVAL, 1, [Define if you have festival]) fi fi if test "$use_gpsman" != "no"; then AC_PATH_PROG(gpsman, [gpsman haslib gpsmanshp], no, $BINPATH) if test "$gpsman" != "no"; then AC_DEFINE_UNQUOTED(HAVE_GPSMAN, 1, [Define if you have gpsman]) AC_DEFINE_UNQUOTED(GPSMAN_PATH, "${gpsman}", [Path to gpsman]) fi fi if test "$use_err_popups" != "no"; then AC_DEFINE_UNQUOTED(HAVE_ERROR_POPUPS, 1, [Define if you have error popups enabled]) fi if test "$use_lsb" != "no"; then AC_DEFINE_UNQUOTED(__LSB__, 1, [Define if you're compiling for Linux Standard Base]) fi ]) AC_DEFUN([XASTIR_CHECK_POSTGIS], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # test for postgresql if test "${with_postgis+set}" = set; then PG_CONFIG="pg_config" if test "$with_postgis" != "yes"; then # get path if provided pg_path="$with_postgis" PG_CONFIG_PATH="${pg_path}/bin" BINPATH="${BINPATH}:${PG_CONFIG_PATH}" POSTGIS_LIB_DIR="-L${pg_path}/lib" AC_PATH_PROG(PG_CONFIG, [pg_config], no, $PG_CONFIG_PATH) else AC_PATH_PROG(PG_CONFIG, [pg_config], no) fi if test "$PG_CONFIG" != "no"; then # Check for postgis spatial extensions. # Look for lwpostgis.sql script in default location. # If found, is likely a postgis installation. # Need more definitive test for postgis, as this may fail to detect postgres # installations where this script was removed, and will incorrectly # detect postgres without postgis where this script has been installed but not run. AC_PATH_PROG(LWPOSTGIS, [lwpostgis.sql], no, "${pg_path}/share") if test "LWPOSTGIS" != "no"; then #postgres with postgis enabled use_postgis=yes use_spatial_db=yes save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" CPPFLAGS="$CPPFLAGS -I`${PG_CONFIG} --includedir` `${PG_CONFIG} --cppflags`" CXXFLAGS="$CXXFLAGS `${PG_CONFIG} --cflags`" LDFLAGS="$LDFLAGS `${PG_CONFIG} --ldflags`" LIBS="${POSTGIS_LIB_DIR} `${PG_CONFIG} --libs` -lpq $LIBS" AC_DEFINE(HAVE_POSTGIS, 1, Postgresql with postgis is present. ) else AC_MSG_WARN(*** Cannot find lwpostgis.sql: Building w/o Postgresql/Postgis support. ***) AC_MSG_WARN(*** Postgresql was found, but does not appear to have Postgis added. ***) AC_MSG_WARN(*** Install and enable postgis and leave the lwpostgis.sql script in ***) AC_MSG_WARN(*** ${pg_path}/share ***) fi else use_postgis=no AC_MSG_WARN(*** Cannot find pg_config: Building w/o Postgresql/Postgis support. ***) AC_MSG_WARN(*** Specify the path to the posgresql installation directory ***) AC_MSG_WARN(*** For example: --with-postgis=/usr/local/pgsql ***) fi fi ]) AC_DEFUN([XASTIR_CHECK_MYSQL], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # test for MySQL if test "${with_mysql+set}" = set; then MYSQL_CONFIG="mysql_config" if test "$with_mysql" != "yes"; then # get path to mysql_config if provided mysql_path="$with_mysql" BINPATH="${BINPATH}:${mysql_path}" AC_PATH_PROG(MYSQL_CONFIG, [mysql_config], no, $mysql_path) else AC_PATH_PROG(MYSQL_CONFIG, [mysql_config], no) fi use_mysql_spatial=no use_mysql_any=no if test "$MYSQL_CONFIG" != "no"; then # check for mysql version with spatial support # look for mysql 4.1.2 or greater for spatial support # and standardized prepared statements # 4.1.0 and 4.1.1 have spatial support, but only early versions # of prepared statement functions that changed in 4.1.2 AC_MSG_CHECKING([mysql version >= 4.1.2]) mysqlversion=`$MYSQL_CONFIG --version` mysqlversionmajor=`echo ${mysqlversion} | cut -d '.' -f 1` mysqlversionminor=`echo ${mysqlversion} | cut -d '.' -f 2` mysqlversiontiny=`echo ${mysqlversion} | cut -d '.' -f 3` if test "$mysqlversionmajor" -gt 4 ; then mysql_has_spatial="yes" elif test "$mysqlversionmajor" -ge 4 -a "$mysqlversionminor" -gt 1 ; then mysql_has_spatial="yes" elif test "$mysqlversionmajor" -ge 4 -a "$mysqlversionminor" -ge 1 -a "$mysqlversiontiny" -ge 2 ; then mysql_has_spatial="yes" else mysql_has_spatial="no" fi AC_MSG_RESULT($mysql_has_spatial) # if mysql version < 4.1, mysql present but no spatial support if test "$mysql_has_spatial" = "yes"; then # mysql with spatial support use_mysql_spatial=yes use_spatial_db=yes AC_DEFINE(HAVE_MYSQL_SPATIAL, 1, MySQL with spatial support is present.) else AC_MSG_WARN(*** MySQL version $mysqlversion detected is < 4.1.2 ***) AC_MSG_WARN(*** Spatial support enabled only for MySQL 4.1.2 and higher ***) AC_MSG_WARN(*** MySQL support for Lat/Long fields is available but ***) AC_MSG_WARN(*** not for Points Polygons or other spatial objects. ***) fi save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" CPPFLAGS="$CPPFLAGS `${MYSQL_CONFIG} --cflags`" CXXFLAGS="$CXXFLAGS `${MYSQL_CONFIG} --cflags`" LIBS=" `${MYSQL_CONFIG} --libs` $LIBS" use_mysql_any=yes AC_DEFINE(HAVE_MYSQL, 1, MySQL is present.) else AC_MSG_WARN(*** Cannot find mysql_config: Building w/o MySQL support. ***) AC_MSG_WARN(*** Specify the path to mysql_config ***) AC_MSG_WARN(*** For example: --with-mysql=/var/lib/mysql ***) fi fi #AC_MSG_RESULT($use_mysql_spatial) ]) AC_DEFUN([XASTIR_CHECK_IMAGEMAGICK], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # Check for ImageMagick # # First look for the needed Magick-config script, which tells us all # of the build options we need. # # Important: DO NOT use "use_imagemagick" as the variable here, # because AC_CHECK_PROG will do nothing if the variable is already set! # use_imagemagick=no AC_PATH_PROG(MAGIC_BIN, [MagickCore-config], no, $BINPATH) if test "$MAGIC_BIN" != "no"; then use_imagemagick=yes else AC_PATH_PROG(MAGIC_BIN, [Magick-config], no, $BINPATH) if test "$MAGIC_BIN" != "no"; then use_imagemagick=yes fi # AC_MSG_WARN(*** Cannot find Magick-config: Building w/o ImageMagick support. ***) fi if test "${use_imagemagick}" = "yes"; then # # # # Compute the ImageMagick revision number # # # magickversion=`${MAGIC_BIN} --version` # magickmajor=`echo $magickversion | cut -d '.' -f 1` # magickminor=`echo $magickversion | cut -d '.' -f 2` # magicktiny=`echo $magickversion | cut -d '.' -f 3` # if test "$magickmajor" -lt 5; then # magickold="yes"; # elif test "$magickmajor" -eq 5 -a "$magickminor" -lt 4; then # magickold="yes"; # elif test "$magickmajor" -eq 5 -a "$magickminor" -eq 4 -a "$magicktiny" -lt 9; then # magickold="yes"; # fi # save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" # # Figure out the build options using the Magick-config script # CPPFLAGS="$CPPFLAGS `${MAGIC_BIN} --cppflags`" CXXFLAGS="$CXXFLAGS `${MAGIC_BIN} --cflags`" LDFLAGS="$LDFLAGS `${MAGIC_BIN} --ldflags`" LIBS="${MAGIC_LIB_DIR} `${MAGIC_BIN} --libs` $LIBS" # AC_CHECK_HEADERS([MagickCore/MagickCore.h],[use_imagemagick="yes"], [AC_CHECK_HEADERS([magick/api.h],[use_imagemagick="yes"], [use_imagemagick="no"])]) if test "${use_imagemagick}" = "no" then AC_MSG_WARN([*** Cannot find ImageMagick include files: Building w/o ImageMagick support. ***]) else AC_MSG_CHECKING([if your ImageMagick is old enough for us to use]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #include #endif #if (MagickLibVersion > 0x0700) #error Your Magick is way too new #endif ])],[AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_WARN([***Your ImageMagick is too new and Xastir cannot use it***]) use_imagemagick="no" ]) if test "${use_imagemagick}" = "yes" then AC_SEARCH_LIBS([WriteImage],[Magick MagickCore], [AC_DEFINE(HAVE_IMAGEMAGICK, 1, [Imagemagick image library])], [use_imagemagick="no"]) if test "${use_imagemagick}" = "no" then AC_MSG_WARN(*** Cannot find ImageMagick library files: Building w/o ImageMagick support. ***) fi fi fi # if test "${use_imagemagick}" = "no"; then # # No ImageMagick found. Restore variables. # CPPFLAGS=$save_cppflags CXXFLAGS=$save_cxxflags LIBS=$save_libs LDFLAGS=$save_ldflags fi fi # End of ImageMagick checks ]) AC_DEFUN([XASTIR_CHECK_GRAPHICSMAGICK], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # Check for GraphicsMagick # # First look for the needed GraphicsMagick-config script, which tells us all # of the build options we need. # # Important: DO NOT use "use_graphicsmagick" as the variable here, # because AC_CHECK_PROG will do nothing if the variable is already set! # use_graphicsmagick=no AC_PATH_PROG(GMAGIC_BIN, [GraphicsMagick-config], no, $BINPATH) if test "$GMAGIC_BIN" != "no"; then use_graphicsmagick=yes #else # AC_MSG_WARN(*** Cannot find GraphicsMagick-config: Building w/o GraphicsMagick support. ***) fi # if test "${use_graphicsmagick}" = "yes"; then save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_cflags="$CFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" # # Figure out the build options using the GraphicsMagick-config script # CPPFLAGS="`${GMAGIC_BIN} --cppflags` $CPPFLAGS" CXXFLAGS="`${GMAGIC_BIN} --cflags` $CXXFLAGS" CFLAGS="`${GMAGIC_BIN} --cflags` $CFLAGS" LDFLAGS="`${GMAGIC_BIN} --ldflags` $LDFLAGS" LIBS="${MAGIC_LIB_DIR} `${GMAGIC_BIN} --libs` $LIBS" # AC_CHECK_HEADERS([magick/api.h], [use_graphicsmagick="yes"],[use_graphicsmagick="no"]) if test "${use_graphicsmagick}" = "no"; then AC_MSG_WARN(*** Cannot find GraphicsMagick include files: Building w/o GraphicsMagick support. ***) else AC_CHECK_LIB([GraphicsMagick], [WriteImage], AC_DEFINE(HAVE_GRAPHICSMAGICK, 1, [GraphicsMagick image library]), use_graphicsmagick="no") if test "${use_graphicsmagick}" = "no"; then AC_MSG_WARN(*** Cannot find GraphicsMagick library files: Building w/o GraphicsMagick support. ***) fi fi # if test "${use_graphicsmagick}" = "no"; then # # No GraphicsMagick found. Restore variables. # CPPFLAGS=$save_cppflags CXXFLAGS=$save_cxxflags CFLAGS=$save_cflags LIBS=$save_libs LDFLAGS=$save_ldflags fi fi # # End of GraphicsMagick checks ]) # things grabbed elsewhere # this is from Squeak-3.2-4's acinclude.m4 AC_DEFUN([AC_CHECK_GMTOFF], [AC_CACHE_CHECK([for gmtoff in struct tm], ac_cv_tm_gmtoff, [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [struct tm tm; tm.tm_gmtoff;])], ac_cv_tm_gmtoff="yes", ac_cv_tm_gmtoff="no")]) test "$ac_cv_tm_gmtoff" != "no" && AC_DEFINE(HAVE_TM_GMTOFF,,X)]) dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html dnl AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # pthread: Linux, etcetera # --thread-safe: KAI C++ case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthread or # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0);]])], [acx_pthread_ok=yes], [acx_pthread_ok=no]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: threads are created detached by default # and the JOINABLE attribute has a nonstandard name (UNDETACHED). AC_MSG_CHECKING([for joinable pthread attribute]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[int attr=PTHREAD_CREATE_JOINABLE;]])], [ok=PTHREAD_CREATE_JOINABLE], [ok=unknown]) if test x"$ok" = xunknown; then AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[int attr=PTHREAD_CREATE_UNDETACHED;]])], [ok=PTHREAD_CREATE_UNDETACHED], [ok=unknown]) fi if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, [Define to the necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_RESULT(${ok}) if test x"$ok" = xunknown; then AC_MSG_WARN([we do not know how to create joinable pthreads]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with cc_r AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_POP([C]) ])dnl ACX_PTHREAD # AC_DEFUN([XASTIR_PATH_MOTIF], [ # New stuff to check for Motif/Lesstif. Shamelessly borrowed from # the opendx project. Opendx in turn snarfed their test from AC_PATH_X. # Allow "--with-motif-includes" and "--with-motif-libs" so user can # force a specific set of includes. AC_ARG_WITH(motif-includes, [ --with-motif-includes Set path for motif includes (default none)],[with_motif_includes=$withval], [with_motif_includes=]) if test "$with_motif_includes" != "yes" && test -z "$with_motif_includes" then with_motif_includes= fi AC_ARG_WITH(motif-libs, [ --with-motif-libs Set path for motif libraries (default none)],[with_motif_libs=$withval], [with_motif_libs=]) if test "$with_motif_libs" != "yes" && test -z "$with_motif_libs" then with_motif_libs= fi # Guess where to find include files, by looking for this one Xm .h file. test -z "$xm_direct_test_include" && xm_direct_test_include=Xm/Xm.h # First, try using that file with no special directory specified. AC_MSG_CHECKING([for Motif headers]) AC_PREPROC_IFELSE( [AC_LANG_SOURCE([[#include <$xm_direct_test_include>]])], [ # We can compile using X headers with no special include directory. xm_includes= AC_MSG_RESULT([in default path]) ],[ # that test didn't work, we need to hunt a little # Look for the header file in a standard set of common directories. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in \ /usr/X11/include \ /usr/X11R6/include \ /usr/X11R5/include \ /usr/X11R4/include \ \ /usr/include/X11 \ /usr/include/X11R6 \ /usr/include/X11R5 \ /usr/include/X11R4 \ \ /usr/local/X11/include \ /usr/local/X11R6/include \ /usr/local/X11R5/include \ /usr/local/X11R4/include \ \ /usr/local/include/X11 \ /usr/local/include/X11R6 \ /usr/local/include/X11R5 \ /usr/local/include/X11R4 \ \ /usr/X386/include \ /usr/x386/include \ /usr/XFree86/include/X11 \ \ /usr/include \ /usr/local/include \ /usr/unsupported/include \ /usr/athena/include \ /usr/local/x11r5/include \ /usr/lpp/Xamples/include \ \ /usr/openwin/include \ /usr/openwin/share/include \ "$with_motif_includes" \ ; \ do if test -r "$ac_dir/$xm_direct_test_include"; then xm_includes=$ac_dir AC_MSG_RESULT([in $xm_includes]) break fi done if test "x$xm_includes" = "x"; then AC_MSG_ERROR([**** NO MOTIF HEADERS FOUND **** install Motif development headers or use --with-motif-includes to specify location of Xm/Xm.h ]) fi ]) # Check for the libraries. AC_MSG_CHECKING([for Motif libraries]) test -z "$xm_direct_test_library" && xm_direct_test_library=Xm test -z "$xm_direct_test_function" && xm_direct_test_function=XmGetDestination # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS="$LIBS" LIBS="-l$xm_direct_test_library $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([ [#include <$xm_direct_test_include> #include ]], [[Display *foobar; ${xm_direct_test_function}(foobar)]])], [ LIBS="$ac_save_LIBS" # We can link Motif programs with no special library path. xm_libraries= AC_MSG_RESULT([in default path]) ],[ LIBS="$ac_save_LIBS" # First see if replacing the include by lib works. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in `echo "$xm_includes" | sed s/include/lib/` \ /usr/X11/lib \ /usr/X11R6/lib \ /usr/X11R5/lib \ /usr/X11R4/lib \ \ /usr/lib/X11 \ /usr/lib/X11R6 \ /usr/lib/X11R5 \ /usr/lib/X11R4 \ \ /usr/local/X11/lib \ /usr/local/X11R6/lib \ /usr/local/X11R5/lib \ /usr/local/X11R4/lib \ \ /usr/local/lib/X11 \ /usr/local/lib/X11R6 \ /usr/local/lib/X11R5 \ /usr/local/lib/X11R4 \ \ /usr/X386/lib \ /usr/x386/lib \ /usr/XFree86/lib/X11 \ \ /usr/lib \ /usr/local/lib \ /usr/unsupported/lib \ /usr/athena/lib \ /usr/local/x11r5/lib \ /usr/lpp/Xamples/lib \ /lib/usr/lib/X11 \ \ /usr/openwin/lib \ /usr/openwin/share/lib \ "$with_motif_libs" \ ; \ do dnl Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl; do if test -r $ac_dir/lib${xm_direct_test_library}.$ac_extension; then xm_libraries=$ac_dir AC_MSG_RESULT([in $xm_libraries]) break 2 fi done done if test "x$xm_libraries" = "x"; then AC_MSG_ERROR([**** MOTIF LIBRARIES NOT FOUND **** Install Motif development headers/libraries or use --with-motif-libraries to specify path to libXm.a ]) fi ]) ]) # Look for a library that contains the Berkeley DB function "db_create" # and put it into LIBS if it's not already found by the current setting of # LIBS # # If "--with-bdb-incdir" was specified, it will already have been added # to CPPFLAGS by the caller # # If "--with-bdb-libdir" was specified, we tentatively add it to LDFLAGS # here and add it to BDB_LIBADD. Only if we actually find the library # will this get added to LDFLAGS permanently # # if we find it, dblib will have "berkeley" in it, otherwise it will have # "no" # # Note that this is not perfectly safe. We only call this macro if we # have found a usable "db.h" header in the default CPP search path or # the path augmented by "--with-bdb-incdir", but we have no way of telling # (without actually running a program that calls db_version) whether # this header is actually for the most recent libdb installed on the # system. This can bite users who have multiple versions, but tell Xastir # that they want to use the older header in some nonstandard directory. # # In that case, the ONLY solution for forcing use of the old library is to # specify it in LIBS (e.g. "LIBS='-ldb-5.3'"). AC_DEFUN([XASTIR_BERKELEY_DB_CHK_LIB], [ BDB_SAVE_LDFLAGS=$LDFLAGS if test -d $with_bdb_lib; then LDFLAGS="-L$with_bdb_lib $LDFLAGS" BDB_LIBADD="-L$with_bdb_lib $BDB_LIBADD" else BDB_LIBADD="" fi AC_SEARCH_LIBS([db_create],[db-18.1 db-18 db-5.3 db5.3 db53 db-5.2 db-5.2 db52 db-5.1 db5.1 db51 db-5.0 db5.0 db50],[dblib="berkeley"],[dblib="no"]) LDFLAGS=$BDB_SAVE_LDFLAGS ]) AC_DEFUN([XASTIR_BERKELEY_DB_OPTS], [ AC_ARG_WITH(bdb-libdir, [ --with-bdb-libdir=DIR Berkeley DB lib files are in DIR], with_bdb_lib=$withval, [ test "${with_bdb_lib+set}" = set || with_bdb_lib=none]) AC_ARG_WITH(bdb-incdir, [ --with-bdb-incdir=DIR Berkeley DB include files are in DIR], with_bdb_inc=$withval, [ test "${with_bdb_inc+set}" = set || with_bdb_inc=none ]) ]) AC_DEFUN([XASTIR_BERKELEY_DB_CHK], [ AC_REQUIRE([XASTIR_BERKELEY_DB_OPTS]) xastir_save_CPPFLAGS=$CPPFLAGS if test -d $with_bdb_inc; then CPPFLAGS="$CPPFLAGS -I$with_bdb_inc" BDB_INCADD="-I$with_bdb_inc" else BDB_INCADD="" fi # check to see if the db.h we find first in the search # path will actually pass the test we do in map_cache.c. Don't even bother # looking for a library if not. AC_MSG_CHECKING([if db.h is exists and is usable]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [ #if (DB_VERSION_MAJOR < 4 ) #error DB_VERSION_MAJOR < 4 #endif ])], [ AC_MSG_RESULT([yes]) XASTIR_BERKELEY_DB_CHK_LIB() ], [ AC_MSG_RESULT([no]); dblib="no" ]) CPPFLAGS=$xastir_save_CPPFLAGS use_map_cache="no" if test "${dblib}" = "berkeley"; then CPPFLAGS="$CPPFLAGS $BDB_INCADD" LDFLAGS="$BDB_LIBADD $LDFLAGS" AC_DEFINE(USE_MAP_CACHE, 1, [Berkeley DB Map Caching]) use_map_cache="yes" fi ]) Xastir-Release-2.2.2/archived_docs/000077500000000000000000000000001501463444000171435ustar00rootroot00000000000000Xastir-Release-2.2.2/archived_docs/INSTALL000066400000000000000000001774321501463444000202120ustar00rootroot00000000000000NOTE: This file gives a general overview of how to build Xastir. It is by necessity both extremely vague where it is general, and extremely dense when it tries to get specific. System-specific guidance for building Xastir can be found at http://xastir.org/index.php/Installation_Notes, and some of these build recipes may be more helpful than the general guidance in this file. General steps to configure/compile/install Xastir: (detailed steps and library installation instructions follow these general steps) ---------------------------------------------------------------------- 1) Get one of the source releases from Github at https://github.com/Xastir/Xastir/releases and explode it. (Replace X.Y.Z with the release number below) mkdir Xastir cp Xastir-Release-X.Y.Z.tar.gz Xastir cd Xastir tar xzvf Xastir-Release-X.Y.Z.tar.gz An alternative to the above steps is to use git to download the Xastir sources. See README.GIT for those instructions. Git allows you to easily keep up to date with the developers. 1a) Make sure your system has, at a minimum, these packages: Motif or OpenMotif or LessTiff Required The GUI widget set pthreads Required Threading capability There's no point going past this step if you can't get those installed. They should be in your system's package management system, and you will need both libraries and development headers for Xastir to build. A build of Xastir with only these two will be fairly limited, and you will almost certainly want to add libraries for additional features later. 2) Go into the xastir directory to build the executable: cd Xastir The first time you do this you need to create the "configure" script. To do this run: ./bootstrap.sh or autoreconf -i Note that bootstrap (or autoreconf) requires that you have GNU Autoconf and Automake installed on your system. Any error messages from bootstrap mean that something is missing and you will be unable to proceed, so fix those problems first. Then create a build directory, configure and build the code: mkdir -p build cd build ../configure make su (become the root user) make install chmod 4555 /usr/local/bin/xastir (only if you use kernel ax.25, see below) exit (from root) Note that if there are ANY errors reported by configure and it aborts early, this is generally a sign that something critical has been missed, such as a missing Motif library or missing Motif headers. If this happens, configure will not create a "Makefile" and the "make" step will report that no makefile has been found. Go back and look at the configure output and figure out what it was complaining about, fix that problem, and then try it all again. If your run of configure does not end with the text: xastir X.Y.Z has been configured to use the following options and external libraries: followed by a list of options and their status, and ending with: xastir will be installed in /usr/local/bin. Type 'make' to build Xastir (Use 'gmake' instead on some systems). then configure did NOT complete normally, and you need to figure out why. 3) Xastir should be installed in /usr/local/bin (the default on most systems). You can run it by typing this from a shell: xastir & Installing only the required libs gives you these capabilities: PocketAPRS maps aprsDOS maps WinAPRS maps MacAPRS maps GNIS labels Address searching serial port and Internet gateway connectivity. Short summary of additional libraries Xastir can use: ------------------------------------------------------------------------- Shapelib Recommended ESRI Shapefile maps and WX alerts pcre2 or pcre Required for Shapefile support Xpm Optional XPM images + Snapshots + Printing GraphicsMagick Optional MANY graphics images (you can also use ImageMagick 6, but GraphicsMagick is preferred) libtiff/libgeotiff/libproj Optional geoTIFF maps (USGS topos) AX.25 Optional Kernel AX.25 networking support festival Optional Speaking alerts libcurl or wget Optional Internet images as maps GPSMan/gpsmanshp Optional Converts GPS data to Shapefiles libdb (4.0 or newer) Optional Internet map caching (fast!) libpq Experimental Persistent data with Postgis libmysqlclient Experimental Persistent data with MySQL It is our experience in 2023 that ALL of the libraries that Xastir needs or which can be added optionally are available in every operating system's package management system, so it should be very unusual to have to build any from source. A lot of the information in the later parts of this file is very old, when that was NOT the case. Adding XPM or ImageMagick libs, ImageMagick's "convert" utility, and the "gv" utility gives you printing capability. Postscript or emulated postscript printing capability is required for this as well. Adding XPM or ImageMagick libs plus "convert" also give the capability to create automatic PNG images on disk from the map screen (useful for web pages!). Adding Shapelib support also gives you the capability to use Tiger 2000 maps which were converted to Shapefile format by ESRI. This allows you to use free detailed street maps for any point in the U.S. Shapelib support *requires* that you also install PCRE2 or PCRE libraries and development headers. Adding other libraries gives you the additional capabilities listed above. After you have a working version of Xastir you can always add additional features by installing the libraries required and then rerunning "configure" and rebuilding Xastir. ------------------------------------------------------------------------------ In the text below, we go into far more detail than most users need. It may also be very, very obsolete. ============================================================================== Library/Option Hierarchy: ------------------------- ImageMagick (Usually requires additional libraries) error_popups (Annoying popups, turned off by default) libgc (developer stuff: memory leak testing) "festival --server &" (Xastir connects to this server) | `-----------> Festival gprof | `-+---------> profiling (developer stuff) / | gprof-helper.so libax25 | `-----------> AX25 libProj | `-+-------+-> GeoTiff / / / / libtiff / / libgeotiff gpsmanshp | `-+------+--> GPSMan / / | / tcl/tk / / ShapeLib | +-----------> rtree | `-+---------> Dbfawk / | PCRE libcurl or wget | `-+--------> map_caching / | Berkeley DB MySQL --------> MySQL database interfaces (Experimental) | `-+---------> db2APRS (Xastir connects to this server) / | Meteo Postgresql | `-+--------> Postgis database interfaces (Experimental) | + / QGIS [station data in another GIS application] | Postgis --------------------------------- For those who would like to see the full list of libraries Xastir might use (to decide what packages to install), here's the ldd command run against a pretty much fully-loaded Xastir. Note that quite a few of these libraries are pulled in by the ImageMagick library, and your library list may look little like it due to differences in how ImageMagick was compiled: > ldd /usr/local/bin/xastir libXm.so.3 => /usr/X11R6/lib/libXm.so.3 (0x40030000) libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40287000) libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x402db000) libMagick.so.0 => /usr/lib/libMagick.so.0 (0x403d7000) liblcms.so.1 => /usr/lib/liblcms.so.1 (0x4052f000) libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x40553000) libexif.so.9 => /usr/lib/libexif.so.9 (0x405a9000) libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x405be000) libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x405cc000) libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x405d5000) libbz2.so.1 => /usr/lib/libbz2.so.1 (0x405ed000) libz.so.1 => /usr/lib/libz.so.1 (0x405fd000) libpthread.so.0 => /lib/i686/libpthread.so.0 (0x4060c000) libm.so.6 => /lib/i686/libm.so.6 (0x4065d000) libdb-4.1.so => /usr/lib/libdb-4.1.so (0x40680000) libXpm.so.4 => /usr/X11R6/lib/libXpm.so.4 (0x40744000) librt.so.1 => /lib/librt.so.1 (0x40755000) libcurl.so.2 => /usr/lib/libcurl.so.2 (0x40768000) libXp.so.6 => /usr/X11R6/lib/libXp.so.6 (0x4078f000) libshp.so.1 => /usr/local/lib/libshp.so.1 (0x40797000) libpcre.so.0 => /usr/lib/libpcre.so.0 (0x4079f000) libproj.so.0 => /usr/local/lib/libproj.so.0 (0x407ab000) libtiff.so.3 => /usr/lib/libtiff.so.3 (0x407e2000) libgeotiff.so => /usr/local/lib/libgeotiff.so (0x4082b000) libax25.so.0 => /usr/lib/libax25.so.0 (0x4084d000) libc.so.6 => /lib/i686/libc.so.6 (0x40b64000) libdl.so.2 => /lib/libdl.so.2 (0x40c97000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) libssl.so.0.9.7 => /usr/lib/libssl.so.0.9.7 (0x40c9b000) libcrypto.so.0.9.7 => /usr/lib/libcrypto.so.0.9.7 (0x40ccb000) libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x40dbd000) libjasper-1.700.so.2 => /usr/lib/libjasper-1.700.so.2 (0x40ddd000) libpng.so.3 => /usr/lib/libpng.so.3 (0x40e2c000) libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40e5b000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x40f1b000) Things you need for this version: --------------------------------- * Get Lesstif/OpenMotif from your favorite Linux/Unix distribution. -or- * Lesstif: www.lesstif.org (look below for RED-HAT instructions) -or- * OpenMotif: www.openmotif.org * AX25 packages: (if you want support for kernel AX25 interfaces) Lib AX25 AX25 apps AX25 tools The apps package is not required, but strongly suggested. These packages are in most Linux distributions but may be out of date. See the linux-hams mailing list for details. * You should have glibc on your system that supports threads! For geoTIFF support (such as USGS DRG topo maps) you also need: libtiff (should be in the package set of most distributions): ------------------------------------------------ http://www.simplesystems.org/libtiff/ libproj (proj-4.4.9 or later): --------------------- http://proj4.org/ Datum translations (proj-nad27 or proj-datumgrid): -------------------------------------------------- http://proj4.org/ libgeotiff (any version later than libgeotiff-1.1.5): -------------------------------------------------- http://geotiff.osgeo.org/ Please note that the order of installation for the above libraries is critical. Follow the instructions below carefully. Also, the particular libgeotiff you use depends on the version of libtiff you have installed. For Linux kernel AX.25 interfaces, you require these packages: Lib AX25 AX25 apps AX25 tools These packages are in most Linux distros. Source code and other information about them can be found at: http://www.linux-ax25.org/wiki/Main_Page The apps package is not required, but strongly suggested. See the AX.25 HOWTO and the linux-hams mailing list for details. For speech support via the festival speech synthesis software you need: festival. Many package management systems have it already but source and documentation are at: http://www.cstr.ed.ac.uk/projects/festival/ For ESRI Shapefile format maps/weather alert maps: Shapelib: http://shapelib.maptools.org/ pcre: http://www.pcre.org For ImageMagick support for maps in any of 68 major graphics formats, including the capability to use online maps and weather radar images: ImageMagick: http://www.imagemagick.org/ To use online maps or findu.com historical data, you'll need wget or libcurl/libcurl-devel installed. Many systems have these pre-installed, so check first. You may need to upgrade your installed version for this feature to work correctly from within Xastir: Wget: ftp://ftp.gnu.org/gnu/wget/ libcurl: http://curl.sourceforge.net/ To download GPS tracks/waypoints/routes from a Garmin GPS into Xastir, converting to Shapefile format maps as it runs, you'll need gpsmanshp and GPSMan. GPSMan 6.0 and later has command-line support built-in so that Xastir can control it directly, but only GPSMan 6.1 and later are currently usable with Xastir: gpsmanshp: http://www.ncc.up.pt/gpsmanshp/ GPSMan: http://www.ncc.up.pt/gpsman/ http://sunsite.unc.edu/pub/Linux/science/cartography See below for instructions on installing all of these libraries. Once the libraries are installed, ./configure should find the libraries and allow compiling in support for the new features. If you wish to enable/disable configure's testing of certain features, you can add any of the following flags to configure: --without-ax25 --without-festival --without-gpsman --without-imagemagick --without-libproj --without-geotiff --without-shapelib --without-map-cache --with-errorpopups --with-libgc --with-profiling --with-lsb --with-postgis --with-mysql For example, "./configure --without-ax25" will disable the AX.25 networking code in Xastir. If you have installed Xastir before, read the "UPGRADE" file for information on changes in file location and permissions. First Time Install: ------------------- 1. OPTIONAL: If you wish to use AX.25 interfaces, install the AX.25 packages. Verify that they are configured and working. Use "listen" to watch the packets fly by after getting AX.25 configured and hooked to a TNC. Use the AX.25 HOWTO document to guide you in this process. 2. Install LessTif or OpenMotif If you already have Motif or OpenMotif on your system, including the development headers, then you won't need to install LessTif. Most distributions include one of these; step 2a describes building from source, while 2b describes installing from pre-built packages on your distribution. Now that OpenMotif is available, you may be happier running it than LessTif, but either one should work with Xastir. Some users have had problems with OpenMotif, and others have had troubles with LessTif. Symptoms are often menu problems (menus don't draw correctly, menus won't respond to clicks). If you encounter these problems, then uninstall the current Motif and install the other. Several Mac users have reported problems with OpenMotif, so LessTif may be a better place to start. 2a. Download LessTif version 0.91.1 or higher or download OpenMotif. Follow the instructions provided, compile it and install it. Usually, ./configure make su (root) make install /sbin/ldconfig exit (from root) Or you can try any other OSF/Motif(R) version 1.2 2b. Install LessTif or OpenMotif (from a package) Download the lestif-devel (if it exists) and lestif, and install it as your distribution instructs you to install packages. 3. OPTIONAL: Install geoTIFF support. Allows using USGS DRG topo maps or other types of geoTIFF maps/images and has the ability to tile smaller maps into a larger contiguous map of an area: 3a. Check/Edit your startup files: ----------------------------- Check that /usr/local/lib, /usr/lib, and /usr/X11R6/lib are all listed in /etc/ld.so.conf, and run /sbin/ldconfig to re-create the system's cache file. If you don't have permission to edit this file: Edit ~/.bashrc, ~/.bash_profile, .cshrc, or .login and add: export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/usr/X11R6/lib This will let the loader find the shared libraries when it tries to load Xastir into memory. If you instead have a /etc/ld.so.conf.d directory, then this will add the /usr/local/lib directory to the search: Create a file in the /etc/ld.so.conf.d called "local.conf". The file should contain exactly one line: /usr/local/lib Use your favorite text editor or use these commands: echo "/usr/local/lib" > /etc/ld.so.conf.d/local.conf ldconfig -v Check that you aren't already defining LD_LIBRARY_PATH somewhere else. If so, just add the paths above to it. Make sure this environment variable is defined in the current shell you're using to compile Xastir. Note that if you're running Xastir SUID root, the LD_LIBRARY_PATH variable is ignored. 3b. Install libproj: -------------------- NOTE: You must install libproj BEFORE compiling libgeotiff, because libgeotiff uses libproj to do the datum translations. If you install libgeotiff first, datum translations won't work. proj-nad27-1.1.tar.gz or proj-datumgrid-1.3.zip must be decompressed in the nad subdirectory of the proj distribution directory before you run configure. tar xzvf proj-4.4.9.tar.gz (or newer) cd proj-4.4.9/nad unzip ../../proj-datumgrid-1.3.zip (or tar xzvf ../../proj-nad27-1.1.tar.gz) cd .. ./configure make su (root) make install /sbin/ldconfig exit (from root) libproj should now be installed in: /usr/local/include/ /usr/local/lib/ /usr/local/bin/ /usr/local/share/proj/ You may need to do this (as root) if the "make install" portion fails because it can't find "ginstall": cd /usr/bin ln -s install ginstall Then retry the "make install" portion above. 3c. Upgrade libtiff if needed: ----------------------------- The best way to install libtiff is to get it from the ftp site for your Linux distribution. You must have libtiff 3.5.5 or newer for libgeotiff 1.1.x to compile and run correctly, or libtiff 3.6.0 BETA or newer for libgeotiff 1.2.x to work correctly. If you're using libtiff 3.6.0 BETA or newer, things are simplified. Just use libgeotiff 1.2.x or newer and they should play nicely together. --------- Notes for older libtiff (less than 3.6.0 BETA): If you are compiling libtiff from source, you must use "make install_private" because the libtiff private include files are required for libgeotiff to compile and work correctly. You may also snag just the include files listed below from the source distribution or the source RPM, and copy them manually to their destinations. The errors you'll get if you don't match up the older libtiff and libgeotiff by way of the include files: Xastir will seg-fault when it tries to read a geotiff file. --------- If you upgrade libtiff, check that programs like XV, ImageMagick, and the Gimp still run (if you have these programs installed). Graphics programs that read/write TIFF format depend on libtiff. 3d. Install libgeotiff: ----------------------- NOTE: Depending on your version of libtiff, either libgeotiff-1.1.5 or libgeotiff-1.2.4 may compile properly. libgeotiff is intimately tied to your version of libtiff. libgeotiff 1.2.x or greater requires libtiff-3.6.0 BETA or later. If your version of libtiff is older, get libgeotiff 1.1.4 or 1.1.5. For the latter case you may also have to download the sources for your version of libtiff in order to copy one libtiff header file into the libgeotiff source directory. ----------------------- Pre 3.6.0 libtiff NOTE: You may need to snag some files from your exact libtiff source distribution and place them into your /usr/include directory before libgeotiff will compile. Note: I said use files from the EXACT same distribution of libtiff that you already have installed! libtiff/tiffconf.h libtiff/tiffiop.h libtiff/tif_dir.h contrib/dosdjgpp/port.h Drop all four files into the /usr/include/ directory, creating no subdirectories at all. This allows the libgeotiff code to "see" into the libtiff library so that it can use some functions that aren't normally (publicly) available. Try to make sure that you're not overwriting any files in /usr/include/ by the same name. Some of these files may already be present in /usr/local/. If so, they should be exact duplicates. "diff filename1 filename2" will tell you if there are any differences between two files. If you'd rather not mess with the /usr/include directory, you can drop the four files into the libgeotiff-1.1.5/libtiff_private/ directory instead. Libgeotiff will pick up the files there, issue a warning to you that you're using private include files, yet still compile in support for your particular version of libtiff. With libgeotiff-1.2.4/libtiff-3.6.0-beta or newer you shouldn't need to copy these files across. The newer libtiff and libgeotiff can work together using public interfaces. ------------------------ tar xzvf libgeotiff-1.2.4.tar.gz (or newer) cd libgeotiff-1.2.4 ./configure make su (root) make install /sbin/ldconfig (tells the loader about the new libraries) exit (from root) libgeotiff should now be installed in: /usr/local/include/ /usr/local/lib/ /usr/local/share/epsg_csv/ /usr/local/bin/ If you must re-run "configure" for any of these libraries, remember to delete "config.status" and "config.cache" files first. 4. RECOMMENDED: Install ESRI Shapefile support. Allows using many sources of online polygon, polyline, and point maps, including ones from NOAA. This is also the format for weather alert maps. This support is provided by the shapelib package. NOTE: There are TWO ways to install Shapelib, using the version of Shapelib that comes with Xastir (statically linked with Xastir), or using a separate Shapelib shared library (dynamically linked with Xastir). If you ONLY require Shapelib for Xastir and won't need it for any other program, then you may use the private copy distributed with Xastir, skipping the Shapelib install instructions in this section. If you have other programs which need Shapelib, then it is recommended that you install Shapelib first as a shared library, per the instructions below. If you skip the instructions in this sections, "./configure" will set the compile up so that the private Shapelib code will be statically linked to the executable. It isn't clear from the install instructions in shapelib, but just installing the library is sufficient, and just typing "make" and "make install" doesn't make or install the libraries. Take these steps: make lib su (root) make lib_install /sbin/ldconfig exit (from root) and you should have what you need. You may also need to tweak "/etc/ld.so.conf" to contain the proper path to the libraries and then run /sbin/ldconfig to update "/etc/ld.so.cache". Once this is done the loader should be able to find the Shapelib library. Must run /sbin/ldconfig as root for the system to be able to re-create its cache file. See the instructions earlier in this file if you have an /etc/ld.so.conf.d directory instead (section 3A). For MacOSX: Bill Owen, N2RKL, suggested the following for ShapeLib: "The shapelib Makefile wouldn't work out of the box, so I figured out what the important bits were and built them by hand:" ----------------------------------------------- cc -c shpopen.c cc -c shptree.c cc -c dbfopen.c ar cru libshp.a shpopen.o shptree.o dbfopen.o sudo cp libshp.a /sw/lib sudo ranlib /sw/lib/libshp.a sudo mkdir /sw/include/libshp sudo cp shapefil.h /sw/include/libshp/ ----------------------------------------------- Note that you'll have to set up /etc/sudoers file to allow those commands to be run by a normal user before sudo will work for you. See the README.Git file for sudo instructions. COMPILING OPTIONAL UTILITIES FOR SHAPELIB: These utilities are sometimes useful when writing dbfawk rules but aren't necessary for running Xastir. cd xastir/src/shapelib make -f Makefile_shapelib_orig cd contrib make -f Makefile_orig You'll be left with useful executables in the xastir/src/shapelib and xastir/src/shapelib/contrib directories. It's your choice whether to copy them to a directory in your path (perhaps /usr/local/bin?) to make them easier to use. 5. OPTIONAL: Install -either- GraphicsMagick or ImageMagick support as shown below. Xastir will use one or the other but not both. It'll prefer GraphicsMagick over ImageMagick if both are installed. Do step 5a -or- 5b below to get this type of image support compiled into Xastir. Allows using more than 68 different graphics format files as maps, by creating an associated .geo file for each with tie-points. This support will allow use of online Tiger and Terraserver maps with Xastir, and NOAA weather radar images. Other people are working on integrating even more online mapping sources. This will also allow you to use any GIF/JPG/XPM/ BMP/... image as an Xastir map. Installation instructions are included in the package. If you choose to install from a binary install, be sure that you have all the graphic format libraries that it was originally built with. The easiest way to install one of these is via a package from your linux distribution's CD or ftp site. If you install from such a package, make sure the header files are installed. These are often in a separate package called GraphicsMagick-devel or ImageMagick-devel or similar. 5a. OPTIONAL: Install GraphicsMagick support. Download the GraphicsMagick sources from: http://www.graphicsmagick.org Uncompress/un-tar them... tar -xzvf Gr* Change directory to the newly created GraphicsMagick directory and compile: cd Gr* ./configure --with-quantum-depth=16 --enable-shared make su -c 'make install' su -c '/sbin/ldconfig' Skip the next step (5b) as you only need ImageMagick support installed if you _don't_ install GraphicsMagick. 5b. OPTIONAL: Install ImageMagick graphics support. Note that Xastir's "./configure" stage may fail trying to compile in ImageMagick support. If this happens, make sure you have the ImageMagick development package installed if using RPM packages, or have installed the ImageMagick header files. If it still fails, check the "config.log" file _very_ carefully. Often ImageMagick tests fail due to some other library that ImageMagick depends upon being absent, such as liblcms, libbz2, or others. This can also cause AX.25 support to be dropped in our current "configure" script. We're working on that. Until the RPM packagers for ImageMagick include all of the dependent libraries in their RPM dependency list, the best way to assure that ImageMagick is installed properly is to install it from sources. ------------------------------------------------------------------------- Note: Red Hat 9.0's install of ImageMagick does not work with XASTIR. It will need to be removed and installed from sources. If w3m text based web browser is installed, you will need to remove it before removing ImageMagick: rpm -e w3m rpm -e ImageMagick Download the Imagemagick sources from: ftp://ftp.imagemagick.org/pub/ImageMagick/ At the time of writing, this was ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-5.5.7-34.tar.gz But you may need to get a newer version by the time you read this. Uncompress/un-tar them... tar -xzvf im* Change directory to the newly created ImageMagick directory and compile: cd im* ./configure make su -c 'make install' su -c '/sbin/ldconfig' These instructions are courtesy of Wes Johnston. ------------------------------------------------------------------------- 6. OPTIONAL: If your system doesn't have wget or libcurl/libcurl-devel installed, and you want to use online maps, install either or both of those packages now. Installation instructions are included in the package. Some older versions of wget don't work properly with Xastir, so even if you already have wget you may need to upgrade it. Please refer to the wget man pages or the web pages at http://www.gnu.org/software/wget/wget.html for info concerning wget. Note that if the remote server is down, Xastir can appear to hang for a bit before wget times out. Xastir calls wget with no retries and a 30-second timeout, but one user reported that wget takes one minute fifteen seconds to time out. Also note that the users ~/.wgetrc and the system-wide wgetrc file can change the timeouts and retries as well. See the man pages for details. Pay particular attention to which file/command-line-options take priority over others. It looks like the command-line option "--execute command" will allow overriding the .wgetrc files, which means the user can override the hard-coded timeouts/retries in Xastir by specifying new defaults in their ~/.wgetrc file. Libcurl should be a drop-in replacement for the wget functionality that we use, and it's a faster and more secure method. 7. OPTIONAL: Installing gpsmanshp/GPSMan allows Xastir to fetch GPS waypoints/routes/tracks from a GPS. Xastir can fetch the data automatically, create a Shapefile map, then index/select/display the new map. Make sure you have Shapelib installed first (see above instructions). Note that you may have to change the gpsmanshp Makefile to call out "TCLVERSION = 8.4" instead of 8.3, depending upon which version of tcl is installed on your system. Use your package manager to determine this ("rpm -q -a | grep tcl"), or you may be able to find out in /usr/lib by typing "ls -ld tcl*". Install gpsmanshp: tar xzvf gpsmanshp_1.2.2.tgz cd gpsmanshp make su -c 'make install' Install GPSMan: tar xzvf gpsman-6.0.tgz cd gpsman-6.0 vi gpsman.tcl Change SRCDIR line to: "set SRCDIR /usr/lib/gpsman" su (root) mkdir /usr/lib/gpsman cp gpsman.tcl /usr/lib/gpsman ln -s /usr/lib/gpsman/gpsman.tcl /usr/X11R6/bin/gpsman cd gmsrc cp * /usr/lib/gpsman cp -R gmicons /usr/lib/gpsman chmod -R 755 /usr/lib/gpsman chmod 644 /usr/lib/gpsman/gmicons chmod 777 /usr/local/share/xastir/maps/GPS (IMPORTANT!) exit (from root) Verify that GPSMan will start up and will download information from a Garmin GPS in Garmin-Garmin mode. This also creates the configuration files needed to use GPSMan with Garmin GPS's from within Xastir (sets GPS type, serial port, etc within GPSMan's configs). 8. OPTIONAL: Install Festival for speech support To use speech you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival --server &". More info about the speech features is in the Xastir help file. An easy way to get festival installed on some systems is to go to rpmfind.com and search for both festival and festival-dev, then install the RPM's found. Red Hat RPM's installed onto SuSE 7.3 with no problems. Note that the default voice doesn't speak numbers very well. Edit /usr/share/festival/voices.scm and put "ked_diphone" at the first of the "defvar default-voice-priority-list". This will change the default voice to "ked_diphone". Note that you can start up the festival server and test it out manually by typing these commands: telnet localhost 1314 (SayText "Hello") To exit, press control-] and then type "quit". 9. OPTIONAL: Install Berkely DB Library to enable map caching of internet maps. Please note that segfaults (crashes) in Berkeley DB calls can be caused by having multiple versions of the library installed. The programming interface has changed between the versions. If you compile Xastir with one version's header files but Xastir links to another version's library, you can easily end up with segfaults when Xastir runs. SuSE Linux for instance has these available which you _should_ install: db db-devel Plus SuSE has these additional packages available which you should _not_ install. Remove them if they're on your system (using YaST or rpm): db-40 db42 Xastir will normally try to use /usr/include/db.h as the header file, and /usr/lib/libdb.so as the library it will link to (which is usually a symlink to something else, like /usr/lib/libdb-4.1.so). If the header file and the library file don't match, a segfault often occurs. The easiest way to avoid problems is to keep one and only one version of the Berkeley DB library on your system. Here's how to test what version of include file and library file you're using: Find the db.h file. It's usually in /usr/include/db.h. grep DB_VERSION db.h Mine shows this: #define DB_VERSION_MAJOR 4 #define DB_VERSION_MINOR 1 #define DB_VERSION_PATCH 25 #define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 4.1.25: (October 2, 2003)" Now do this: ldd /usr/local/bin/xastir | grep libdb Mine shows this: libdb-4.1.so => /usr/lib/libdb-4.1.so (0x40680000) In this case, version 4.1 of the include file matches 4.1 of the library file, so it works fine. A mismatch in the first two numbers can cause segfaults when Xastir tries to do map caching. If you install the Berkeley DB library in an unusual place (something other than /usr/lib and /usr/include), you should still be able to tell configure where to find it. This comes courtesy of Tom Russo: > > Someone installed Berkeley DB Library here: > > > > /user/local/BerkeleyDB.4.3/include/db.h > > > > Perhaps I can assume that the library would be located here: > > > > /usr/local/BerkeleyDB.4.3/lib/libdb.so > > > > How does one go about specifying the location of the db.h file and > > the libdb.so file so that configure/compile/loading of Xastir work > > properly? > --with-bdb-libdir=/usr/local/BerkeleyDB.4.3/lib > and > --with-bdb-incdir=/usr/local/BerkeleyDB4.3/include 10. OPTIONAL: Compile db2APRS and install MySQL and Meteo to allow Davis weather station support. Install MySQL and Meteo. cd Davis ./bootstrap.sh # OR "autoreconf -i" ./configure make This should build db2APRS in the "src" directory. Start up db2APRS. Xastir should be able to connect to the db2APRS server in order to get the Davis weather station data. See further instructions in the Davis directory. 11. OPTIONAL: Experimental. Add GIS database support. Note: Database support is experimental and any aspect may change at any time, including database structures. Scripts to create database tables for MySQL and Postgres/Postgis are in the scripts directory as db_gis_postgis.sql and db_gis_mysql.sql. Warning: If you are connected to internet feeds for APRS data, it is possible to accumulate several million station records per day which could amount to around 300 MB of database records per day. Postgres + Postgis: Install Postgres. Include development packages (libpq). Add Postgis spatial object support to Postgres. Compile xastir with --with-postgis After building xastir: Create a database named xastir and a user with create rights on that database. Edit db_gis_postgis.sql to set username and password for an xastir user with select access to the xastir database. Default values are database=xastir, user=xastir_user You may also need to set permissions in pg_hba.conf. Run the queries in db_gis_postgis.sql. Run xastir and add a SQL Database interface, start with the postgis defaults, add the username and password of the xastir user. Other GIS applications (e.g. QGIS, Mapserver, GRASS) can access and display station data directly from the postgresql/postgis database. You can configure the database interface to read station from the database on startup and to save stations as they are heard to the database. This provides persistence of station data between xastir sessions. MySQL: Install MySQL. Include development packages (libmysqlclient). Compile xastir with --with-mysql After building xastir: Create a database named xastir and a user with create rights on that database. Edit db_gis_mysql.sql to set username and password for an xastir user with select access to the xastir database. Default values are database=xastir, user=xastir_user Run the queries in db_gis_mysql.sql mysql xastir -p < db_gis_mysql.sql Run xastir and add a SQL Database interface, start with the MySQL defaults, add the username and password of the xastir user. You can configure the database interface to read station from the database on startup and to save stations as they are heard to the database. This provides persistence of station data between xastir sessions. If you have one or more spatial database interfaces set to activate on startup, and this produces a situation that won't let you start xastir normally [e.g. Station data with unusual characters could concevable cause xastir to segfault when retrieved from the database, and interactions between multiple databases that are both writing are reading station data at the same time from each other could potentially be unstable], you should be able to start xastir by editing the device configuration in ~/.xastir/config/xastir.cnf Look for DEVICEn_TYPE:14 lines (where n is the interface number, between 0 and 14, TYPE:14 devices are sql database interfaces), and edit the device to set both query on startup and on startup values to 0. DEVICEn_QUERY_ON_STARTUP:0 DEVICEn_ONSTARTUP:0 If the cause is problematic data in your database, you may need to run a delete query to eliminate the problematic row(s). 12. Building XASTIR: Note that you'll need autoconf 2.53 or newer and automake 1.6.3 or newer in order to run the "./bootstrap.sh" script. "./bootstrap.sh" (This step needed only for those using Git) "mkdir -p build" "cd build" "../configure" "make" ("gmake" for Solaris or *BSD) This builds XASTIR, You should not get any error or warning messages. If you get the message from Xastir's configure script saying: "**** NO MOTIF HEADERS FOUND **** install Motif development headers or use --with-motif-includes to specify location of Xm/Xm.h" even though you've got the Motif libraries and headers installed in the proper places, you might need to add this to the configure line: "--x-includes=/usr/X11R6/include" If that option does not help, then Motif is installed somewhere other than with the standard X includes. You must locate the file "Xm.h," which should be in a subdirectory called "Xm" somewhere. Once located (let's say in /usr/include/Motif/Xm/Xm.h), use the configure option: "--with-motif-includes=/usr/include/Motif" If you get the message: "**** MOTIF LIBRARIES NOT FOUND **** Install Motif development headers/libraries or use --with-motif-libraries to specify path to libXm.a" then your Motif libraries are not installed in the same directory as your other X libraries, and you must find the file libXm.a, libXm.so, or libXm.sl. Once found (say in /usr/lib/Motif, for example), tell configure where to find it with: "--with-motif-libraries=/usr/lib/Motif" If you wish to install Xastir in a location other than the default ("/usr/local/bin" and "/usr/local/share/xastir" directories), you may add the "--prefix=" flag to configure before compiling. i.e. "./configure --prefix=/home/apps/xastir" Which will cause executables to be installed in "/home/apps/xastir/bin/" and the rest of Xastir to be installed under the "/home/apps/xastir/xastir/" directory. This is useful if you don't have root access on a machine, but still wish to install and use Xastir from your home directory. There are probably many other uses as well. If you want to disable optional "dbfawk" support (see README.MAPS) then add "--without-dbfawk" to your "./configure", i.e. "./configure --without-dbfawk" Most people will want the capability though. You'll need the "pcre" package installed in order to compile in dbfawk support. To enable spatial indexing of shapefiles you can also add "--with-rtree" to your configure command line. Using spatial indices can speed up access of shapefiles that cover large areas if you're only viewing a smaller area, but at the cost of some additional RAM to store the spatial index. This feature is still in the experimental phase, but some users have observed a noticeable speed-up in map redraws, especially with very large shapefiles. The spatial indexing library used is based on public domain code obtained from Melinda Green, http://www.superliminal.com, but this code is included in xastir so you don't need to download anything to use it. If you see some errors, they might be because you are missing GNU msgfmt or GNU gettext/xgettext? These packages are required to compile the latest Xastir sources. Beware of packages with the same names installed into /usr/openwin/bin, these are probably NOT the GNU flavor of the executables and will not work for compiling Xastir. For SuSE Linux: Install "development/gettext" using YaST. If you do see some errors/warnings read the FAQ. If this doesn't help, or you think you have a different problem, dump the errors/warnings to a file, and send the file and the following information to the developers: System type (cpu), speed, memory, Linux Distribution, Linux Version, X Window manager (KDE, GNOME, FVWM, etc..) To install, type (as root) "make install" (or make install-strip to remove debugging information) If you later install additional libraries and just can't get ./configure to see them, remove the config.cache file via this command: "rm config.cache", and then re-run configure. Also see the notes above about /sbin/ldconfig. 13. Kernel AX.25 Interfaces NOTE: Xastir is designed by amateur radio operators, for amateur radio operators. It is intended to be used only by them. If there's a way for unlicensed users to operate the amateur radio equipment (this usually includes sending messages through it which key up the transmitter), it is a violation of the rules and your license (and more) may be at risk. The same goes for igating: Be aware of the rules for your country with respect to gating traffic from the 'net onto RF. If there's any question, don't do it. Please read this entire section before typing anything, as there are serious security implications for some of this! Option 1) If you compiled support for AX.25 in and wish to use Kernel-mode AX-25 interfaces, you _may_ need to type this as root: chmod 4555 /usr/local/bin/xastir This command makes Xastir run as user "root", no matter who actually started it. This allows Xastir to talk to the kernel AX.25 networking. Note however that the above chmod command will prevent you from creating a core file in case Xastir of a major program fault. This core file aids in debugging to trace what went wrong. GENERAL SECURITY WARNING: Beware that Xastir has not been audited for security, and makes limited effort to drop extra privileges. Use this in a multi-user environment at your own risk! The developers have worked hard to fix remote buffer overflows in the code to make Xastir safer to use, but there are _MANY_ potential security risks remaining in the code. User beware! We will attempt to plug known security holes in future releases. Also be aware that turning on the Interface->Server ports (TCP and UDP) will allow other users who authenticate properly to send packets. In the case of TCP they can only get routed to other TCP ports and to the internet. UDP packets may also get routed to your RF ports (as third-party packets). LINUX-SPECIFIC SECURITY WARNING: If you're using Linux AX.25 kernel networking, you'll need to either make Xastir SUID-root, or use a shim (which itself is set to SUID-root) between Xastir and the AX.25 ports. See Option #2 below for the (possibly safer) shim method. If you're the paranoid type (and you should be if you're running a system with multiple users), you may wish to skip SUID-root mode/kernel AX.25 interfaces and use standard serial port TNC interfaces instead. Any program is safer if run as a normal user (not safe, but safer). It is currently impossible to use kernel-mode AX.25 interfaces without the program running with root privileges. Option 2) A more security-conscious option is to use a shim program written by Henk de Groot, PE1DNN. This program runs in SUID-root mode but is much smaller and so is easier to audit for security, and provides a new port that Xastir can connect to. The new port can be read/written without having to be the root user. The program is called aprs_tty and can be obtained here: http://we7u.wetnet.net/xastir/aprs_tty.0.0.2.tgz It actually responds to some TNC commands. The code is straight forward and works well. Run the program, telling it what port to use, and then in XASTIR set up the TNC to point to the new TTY at 19200. It transmits/receives UI frames, and sets the correct unproto path. In this case DO NOT perform the chmod 4555 command on the Xastir executable. Note again that the same SUID-root warnings that were giving in option #1 above also apply to aprs_tty. Buyer beware! As far as we know, aprs_tty has not been audited for security, and makes no effort to drop extra privileges. Use this in a multi-user environment at your own risk! 14. Serially-Connected TNC's NOTE: Xastir is designed by amateur radio operators, for amateur radio operators. It is intended to be used only by them. If there's a way for unlicensed users to operate the amateur radio equipment (this usually includes sending messages through it which key up the transmitter), it is a violation of the rules and your license (and more) may be at risk. The same goes for igating: Be aware of the rules for your country with respect to gating traffic from the 'net onto RF. If there's any question, don't do it. Please read this entire section before typing anything, as there are serious security implications for some of this! If you're using a serial TNC, configure your TNC startup files in the /usr/local/share/xastir/config directory: tnc-startup.sys is used to set up your TNC for Xastir and tnc-stop.sys is to change the TNC back to your normal settings. There are several example TNC startup files in the directory. Choose the one that best suits your TNC and edit to taste. See the note below about where to edit the files. You might be unpleasantly surprised if after you type "make install" next, all your custom changes to the startup files are lost. As always, keep a backup. Some people have had trouble getting Xastir to decode packets. While packets were scrolling quite nicely in the View->Incoming Packet Data dialog, stations weren't showing up on the Xastir screen at all. The cause was incorrect settings in the tnc-startup files for that specific TNC. If you change these files in the xastir source directories make sure to do a "make install" to install them into the /usr/local/share/xastir/config/ directory. Another option would be to edit the files in /usr/local/share/xastir/config/ directly. Keep a copy of them in a safe place in any case. You don't want to lose your custom mods you worked so hard to create. Some systems don't allow normal users to access the serial ports. It's a permissions thing, but is actually the _correct_ way to configure the serial ports. You can fix this in several ways: 1) Add the Xastir user to the group owning the serial ports. 2) Make Xastir run SGID-uucp (or whatever group owns the port). 3) Change the permissions of the device so that any user can access it. 4) Make Xastir run SUID-root. Solutions 3 and 4 are highly discouraged. It can be a security nightmare to start opening up files or devices to read/write access by all users, and the same for SUID-root programs. Don't do either of these. Exception: If you're going to be running AX.25 kernel networking, you may need to be running Xastir SUID-root anyway, or else you need to install a shim program between the port and Xastir. In the latter case the shim is running SUID-root, not Xastir. See the section above regarding AX.25 kernel networking. Here are what the default permissions usually look like for the two serial ports on a Linux box: crw-rw---- 1 root uucp 4, 64 Oct 19 08:15 ttyS0 crw-rw---- 1 root uucp 4, 65 Apr 14 2001 ttyS1 (NOTE: For a Windows/Cygwin installation, a few details are different, but the ttyS0 and ttyS1 keywords are the same. Verify that the permissions of these ports are set appropriately for a normal user to read and write to these devices.) Solution #1: The root user would run the commands necessary to add the Xastir user to the "uucp" group, which would then give the user the necessary permissions to use the port. Usually this involves editing the /etc/group file, but SysAdmin tools usually exist for doing this more easily. Solution #2: As root user, type these commands: chgrp uucp /usr/local/bin/xastir chmod 2555 /usr/local/bin/xastir If you want to restrict Xastir so that only one user can run it, (in this case "user1") type: chown user1 /usr/local/bin/xastir chmod 2500 /usr/local/bin/xastir chgrp uucp /usr/local/bin/xastir Solution #3: You can change the permissions of the serial port to allow use by all users, but this is highly discouraged. Here's what Jack Twilley had to say with regards to "chmod uog+rw" (same as chmod 555) for serial ports: > This is not necessary, and opens up the possibility of abuse. Not all > Xastir installations are Linux boxes used by a single person with a > single purpose -- I know of several instances that are multi-user > machines with access to the Internet by multiple parties, some of whom > are not licensed amateurs, and another couple of instances where the > serial port is not always used by a TNC but also by other devices such > as Palm HotSync cradles and GPS receivers. > > Here are two more secure solutions: > > * use non-root users > One way to use the setuid facilities in Unix would be to set > the xastir binary's user ID to match the user that owns the serial > port. Under Solaris, the default ownership of /dev/cua/a is > uucp:tty, with a default permission of 0600. The command 'chown > uucp /usr/local/bin/xastir' followed by the command 'chmod 4555 > /usr/local/bin/xastir' will allow xastir to run properly without > changing the serial port's permissions or ownership, thus > minimizing any impact on other applications that use the serial > port. Note from Curt: This chmod command will prevent creation of "core" file that are useful for debugging in case Xastir crashes. > > * use groups > A better way to use the setuid facilities in Unix is to set the > xastir binary's *group* ID to match a group that already has the > privilege to mess with the serial port. Under FreeBSD, the default > ownership of /dev/cuaa0 is uucp:dialer, with a default permission > of 0660. The command 'chgrp dialer /usr/local/bin/xastir' followed > by the command 'chmod 2555 /usr/local/bin/xastir' will change > Xastir's group to the serial port's group, and then add the setgid > privilege to the binary. Now when xastir starts up, it will have > the minimum privilege necessary to do what it needs to do, without > being yet another root exploit-in-waiting. 15. Serially-Connected Garmin RINO Radio/GPS If you have a Garmin RINO attached to a serial port, have GPSMan installed, and have support for GPSMan compiled into Xastir, then Xastir has the capability to periodically download waypoints from the RINO unit and create APRS(tm) Objects out of them. Any RINO waypoints that begin with "APRS" will be automatically created, placed on the map, and transmitted as your own Xastir APRS(tm) objects. If you wish to see them but not transmit them, turn off Object/Item transmit or global transmit in the interface menu. Another option is to turn off the transmit enable per interface. Please note that Xastir cannot cause the attached RINO to poll the other RINO units on the air. Xastir can only download the waypoints that the attached RINO has collected from the other RINO units that it is passively monitoring. Here's a blurb from Wes Johnston about the RINO's: "Lets say I have three RINO radios... two in the hands of the SAR teams on the ground, and a third radio in a plane circling above. It is preferred that the radio in the hands of the SAR teams be the nicer rino120 since it does mapping. The radio in the plane can be the lowly rino110 since it does not do mapping but you will have a copy of xastir with maps on the laptop with you anyway. If I set two of my rino radios to APRSSAR1 and APRSSAR2, and connect a third rino radio to xastir with serial in the plane, xastir will query rino radio #3 at any one minute interval between 0 and 30 minutes, get the APRS* waypoints, lop off the first four characters and publish the shorter named waypoints as SAR1 and SAR2 as APRS(tm) objects on to your TNC. The hitch to this is that the rino radio cannot automatically poll the RINO users' locations on the ground. You have to manually (on the radio) select a menu item called POLL and poll the users that way. The reason the first four characters of the rino callsign have to be "APRS" is that when you send a query, rino only asks about the first 4 chars... so any station with the first four that match will answer... ie all of them in your group. The other method is to simply fly the plane overhead and listen (eavesdrop) on the channel and passively pickup the locations of the groups as they converse with one another. The rino will send it's location just as you un-key the PTT if it has been >30 sec since the last time you sent your position. It would be practical to simply ask each team for an update... they just need to squeeze their PTT for a moment (ie kerchunk) to send a position." 16. Start up XASTIR and read the help files to configure it. If you have problems, please consult the FAQ file. You can now start XASTIR. On most systems that the path is set up in FHS format just type "xastir". On other systems type "/usr/local/bin/xastir" to start the program. If you see errors at this point that say something like "Can't load xxx library" this means you forgot to either update /etc/ld.so.conf (or /etc/ld.so.conf.d directory on some systems) and run /sbin/ldconfig, or add the LD_LIBRARY_PATH variable for your shell, and the "ld" loader can't link the libraries with the Xastir executable to get it running in memory. Note that if you're running Xastir as SUID root, the LD_LIBRARY_PATH variable is ignored. To set a new language or change the language current choice, use this command line: xastir -l Current choices are: Dutch English French German Italian Portuguese Spanish ElmerFudd MuppetsChef OldeEnglish PigLatin PirateEnglish This option will be stored in the users config file for the next time Xastir is run. On new installs Xastir will default to English unless you use this command line option. CONNECTING TO AN INTERNET SERVER: Here are some lists of Internet servers: http://members.aol.com/wa8lmf3/miscinfo/APRServe.txt http://www.wa6oft.com/APRServe.txt http://www.aprs-is.net/aprsservers.htm http://www.aprs-is.net/APRSServers.htm Filter port syntax (for those ports that allow user-selectable filtering): http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm The procedure to connect to one of them is this: *) Select Interface->Properties. *) Click Add. *) Select Internet Server, click Add. *) Fill in the "Host" and "Port" boxes. *) Enter the Pass-code found by running "callpass" with your callsign in an xterm window. *) Set the togglebuttons and filter parameters per your preferences. The "filter" keyword is added by Xastir, so you don't need to add that word to the box. If the box has anything in it, "filter" is prepended to the text when Xastir sends the string to the server *) Optionally put in a comment. That shows up in the Interface and Properties dialogs to remind you of the details for that connection. *) Click OK. A short list of the first-tier servers (you may want to connect to the second-tier servers or regional/local servers instead): first.aprs.net ports 10151 (history) or 10152 (no history) second.aprs.net ports 10151 (history) or 10152 (no history) third.aprs.net ports 10151 (history) or 10152 (no history) fourth.aprs.net ports 10151 (history) or 10152 (no history) FESTIVAL NOTE: From: J. Lance Cotton: One thing that I found that I had to do to finally get festival to work was to get rid of the 'only localhost can connect to the server' pref in the festival configuration. I don't know if that's the default on a source install (I installed festival from RPM's), but it might be. I don't know why it doesn't let localhost connect, even though it's the only one specifically allowed. Here's what to do: Open the 'festival.scm' file (I found mine in /usr/share/festival/' and look for the line that starts like: (defvar server_access_list ... Make it look like: (defvar server_access_list nil Then restart the festival server. -Lance KJ5O Additional note from Alan Crosswell: If you run the festival_server script instead of festival -server, then the permissions for localhost get set up for you. You probably want to download some maps and additional data files. The instructions for this are in the README.MAPS. ----------------------------------------------------------------------- NOTES FOR DEVELOPERS: --------------------- Profiling: ---------- 1) "./configure --with-profiling" This will add "-pg" to the CFLAGS section of the Makefiles, which turns on the collection of profiling data while the executable is running (on Linux anyway). 2) "make clean" 3) "make install" (Don't do "make install-strip" here, as that will strip off the symbol table information that gprof requires) 4) "xastir &" 5) Let Xastir run for some period of time. 6) Close Xastir 7) "gprof /usr/local/bin/xastir | tee profile.txt" Gprof will use the Xastir binary and the gmon.out file created from running Xastir to give you the profile listing. Add the "-l" flag to the gprof line to give you a line-by-line profile listing, but be prepared for a long run-time and a lot of CPU to be used by gprof to generate it: "gprof -l /usr/local/bin/xastir | tee profile.txt" Also see this link, which talks about how to profile multi-threaded applications: http://sam.zoy.org/writings/programming/gprof.html With the method described, you compile/install their library code, then invoke Xastir like this: LD_PRELOAD=xastir/src/gprof-helper.so xastir & mv gmon.out gmon.old; gprof /usr/local/bin/xastir gmon.old \ | tee profile.txt; gprof -l /usr/local/bin/xastir gmon.old \ | tee profile2.txt Checking for Memory Leaks: -------------------------- A simple method for just checking malloc's/free's is to set MALLOC_CHECK to a 1 or a 2, at least on Linux. See the malloc man page for more info. For more thorough checks, use libgc: 1) Install libgc, the conservative garbage collector for C and C++. SuSE packages needed are "libgc1" and "gc-devel". If you must compile from sources instead, find libgc at: http://www.hpl.hp.com/personal/Hans_Boehm/gc Configure/install libgc like this: ./configure --enable-threads=posix Make sure that "-DGC_LINUX_THREADS" and "-D_REENTRANT" are defined in the Makefile if you're compiling it on Linux. Optional: Change Makefile to add "-DSAVE_CALL_CHAIN" on the DEFS line. This will provide more of a stack trace each time a leak is found. This is sometimes useful but much more verbose. make make check su make install exit (from root) 2) Now, back in the xastir directory: ./configure --with-libgc Make sure that "-fomit_frame_pointer" is _NOT_ in the Makefiles. This will mess up the optional stack trace if present. make clean make install xastir & Let Xastir run for some period of time. Libgc will dump messages to the xterm as memory leaks are found. Any Xastir memory leaks should have a filename and a line number listed. Memory leaks from lower-level libraries will be missing the detailed information, so they are easy to spot (and mostly useless for the purpose of finding and patching memory leaks). Note also that libgc will take Xastir's memory usage up quite a bit, so don't be surprised if Xastir uses two or three times the normal amount of memory while you're debugging memory leaks with libgc. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/archived_docs/README.Getting-Started000066400000000000000000001060151501463444000230320ustar00rootroot00000000000000 Hello new user, and welcome to Xastir! This document will take you through the steps necessary to get Xastir up and running in one of the following configurations: 1) Minimal install, which will get you up and running quickly. It's recommended that you try this configuration first then add to it. 2) Typical install including maps, weather alerts, geo-coding files, etc. so that full regular operation is achieved. 3) Maximum install with all configure options enabled and most of the useful maps loaded/enabled. All the bells and whistles. Note that you can start with either of the first two options and add only the options you wish in order to come up with your own custom configuration of Xastir. These instructions are written for Linux users. Windows users should refer to the README.CYGWIN document instead. Users of other operating systems should refer to the README document first, then the INSTALL document and the below instructions for further notes, and finally the Installation Notes section of the Xastir wiki at http://xastir.org/. Linux users may also benefit from reading the Installation Notes section of the wiki, because each distro of Linux has its own quirks, and many of those quirks are documented on the wiki. One question you might ask is whether you can just find a binary on the 'net somewhere and install it instead of compiling Xastir from sources. Yes, this is possible, but not what most Xastir users ultimately want. Xastir changes often enough (bug fixes and of course adding new features) that you're really limiting yourself by using pre-compiled binaries. Binaries are typically not updated all that often, if at all, so you'll forever be behind the curve. Most packaged versions of Xastir in package management systems tend to be a couple of years out of date, or even worse. Another reason to compile from sources is to customize it to use all of the features you have available on your system. As you add more libraries that Xastir can use, you can do a quick configure/compile/install and Xastir will be able to take advantage of them. For those that really must have the latest-latest: Download the Xastir sources using Git instead, then issue the command "git pull" periodically in order to snag the latest changes. If anything comes down the pipe, just configure/make/install and then use the latest version. This avoids large file downloads (after the initial download) as it just grabs _changes_ to the sources off the 'net each time you issue the "git pull" command. This is the power-user's method of keeping Xastir up-to-date. See README.GIT for details. After the three configuration sections there's a section on operating, which simply talks you through the initial configuration settings and how things work. After that you can refer to the Help menu option in Xastir itself, plus the INSTALL and README.* text files for additional information. Please note that the non-English help files lag severely behind the English help file. First of all, NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Before we begin, consider subscribing to the Xastir mailing list. That's where everyone is kept up-to-date on the latest features, plus lots of questions are asked/answered there on a weekly or sometimes daily basis. It's a great way to learn and to stay connected with the other Xastir users. See the mailing links on the left of the Xastir home page: http://xastir.org You must be subscribed in order to post messages there. So... Let's get started! -------------------------------------------------------------------- -------------------------------------------------------------------- Latest info: *) Xastir starts up with a default world map the first time you run it plus pops up a dialog where you can enter your callsign. Enter a callsign, then close/restart Xastir or save the configuration via "File->Configure->Save Config Now!". Either of these methods saves the callsign to disk. *) Xastir includes "Shapefile" map capability by default. Run the script: "/usr/local/share/xastir/scripts/get-NWSdata" as root to download/install NOAA Shapefile maps using the "wget" utility. You'll of course need wget installed in order to fetch the files using this method. Installing the NWS files enables weather alert support in Xastir. Verify that "Map->Enable Weather Alerts" is selected and that "Map->Disable All Maps" is _not_ selected, else you won't see weather alerts on your screen. -------------------------------------------------------------------- -------------------------------------------------------------------- Sources of help you may find useful: *) "FAQ" file *) "INSTALL" file: Non-Windows instructions for installing Xastir and optional map libraries may be found here. *) "README.md" file: General info and some OS-specific notes. *) "CONTRIBUTING.md" file: Info on how to contribute to the Xastir project. *) "README.GIT" file: Info on a more advanced way to keep up-to-date on the latest Xastir sources. *) "README.Getting-Started" file: The file you're reading. *) "README.MAPS" file: Much of the info about maps and where to get them may be found here. Also see the Xastir Documentation section, the Wiki pages, at *) "README.CYGWIN" file: For Windows/Cygwin users. *) "UPGRADE" file: Useful info for updating some old versions of Xastir. *) Xastir Web-based documentation, including a set of Wiki pages, found at *) Xastir man page, accessed by typing "man xastir" on a Unix or Unix-like system. This page is a bit out-of-date. *) "Help->Help Index" in the Xastir program itself. Note that only the English language variation of this is even approximately up-to-date. *) Mailing lists at *) User forums at -------------------------------------------------------------------- -------------------------------------------------------------------- Minimal Install: ---------------- First, let's describe it: This will get Xastir up and running with a few built-in map types. You'll be on the air or on the 'net quickly, then can build upon this working base to add more map libraries and other cool features later. Getting the package: -------------------- *) Option 1: Download one of release tarballs from http://xastir.org. There are links from that page or you can go to the github site (https://github.com/Xastir/Xastir) and click on "Releases" to see the entire set that is available. Once you have the file (which will generally be called "Xastir-Release-.tar.gz," create a subdirectory for it to reside. I usually do this: cd # Go to my home directory mkdir src # Make a "src" subdirectory cd src # Change to it mkdir xastir # Make an "xastir" subdirectory cd xastir # Change to it cp /path/filename . # Copy the downloaded file here tar xzvf filename # Un-archive the sources That last step will create a directory called Xastir-Release- underneath the first one, so your full path might be something like (starting at your home directory): ~/src/xastir/astir-Release-2.1.0 The path just listed is where you'll go in order to run the configure and make commands listed below. cd ~/src/xastir/Xastir-Release-2.1.0 from an xterm window should take you there. *) Option 2: An alternative is to use Git to snag the sources for you. Using this method you can periodically update to the latest released version, the latest "stable" version, or the latest development sources, and even switch back and forth between them at will. See README.GIT for info about that option. One of the advantages of Git is that you only pull down the changes since you last updated, instead of doing very large file downloads each time. Another advantage is that you can keep up with the latest features on a daily basis if you wish, nearly effortlessly. Configure: ---------- In order to complete the configure/compile/install of Xastir, you'll need some of the development tools and headers installed. Here's a list of a few items you'll need to have installed. Look for them in the development tools sections on your Linux distribution: autoconf automake bash binutils gcc gcc development headers cpp glibc glibc development headers? freetype2 freetype2 development headers openmotif (or Lesstiff or Motif) openmotif development headers (or Lesstiff or Motif) XFree86 XFree86 development headers XFree86 fonts XFree86 libraries make (GNU flavor, not BSD flavor) gzip m4 grep Note: Only install one of the Motif packages and the corresponding development package to go with it. Recommendation: OpenMotif. If you'd like to install additional packages at this point that may be needed later, install these as well: patch diffutils perl less bzip2 curl curl development headers git tar liblcms liblcms development headers libtiff less pcre2 pcre2 development headers (you can install the older PCRE library instead of PCRE2, but that is past its end of life and PCRE2 is preferred) tcl tcl development headers tk zip unzip wget ax25-apps ax25-doc ax25-tools libax25 festival festival development headers gawk ghostscript-x11 ghostscript-fonts ghostview gv GraphicsMagick GraphicsMagick development headers (ImageMagick 6 and ImageMagick6 development headers ONLY if you can't install GraphicsMagick) Note that some packages may have dependencies on yet more packages. Hopefully your package installation tool will take care of those for you. It's also common for at least one of these packages to forget to list some of it's dependencies (ImageMagick is known for that). In that case you may have to rely on the compiler to tell you what is missing, then go back and re-install a package or two. Note that the AX25 packages are only available on Linux systems. Now it is necessary to create the "configure" script that will be needed to configure Xastir for your system. In versions prior to release 2.1.8, this script was included in the Xastir tarballs, but it is no longer included. We're using "Release-X.Y.Z" generically here, replace X.Y.Z with the actual version you're downloading. cd ~/src/xastir/Xastir-Release-X.Y.Z/ ./bootstrap.sh You will then create a "build" directory in which to run the compilation of Xastir, and run Xastir's configure script in that directory. In the instructions below we describe making this build directory inside the Xastir source tree, so it would be mkdir -p ~/src/xastir/Xastir-Release-X.Y.Z/build cd ~/src/xastir/Xastir-Release-X.Y.Z/build ../configure If you do this, then the simplest path to Xastir's configure script is just "../configure". You could create this build directory anywhere, though, so long as you remember to replace "../configure" with the full path to Xastir's script, e.g, ~/src/xastir/Xastir-Release-X.Y.Z/configure. When you run the "../configure" step from the "build" directory, the script will attempt to figure out what facilities are available that Xastir can take advantage of. Sometimes the script guesses wrong and you must disable an option and try again. The correct way to do this is (Festival speech synthesizer is used as an example, not that I'm picking on Festival or anything): mkdir build cd build ../configure --without-festival That will guarantee that configure will skip Festival entirely, which will set up the Makefiles to skip it, and the Xastir binary will be created without any support for it. Some operating systems place their packaged third-party libraries into places where configure won't find them by default. In that case you may need to add additional options the help it out. Please look at the Installation Notes section of the Xastir wiki, where it is likely you'll find special instructions for your operating system. Other configure options are: --without-ax25 --without-festival --without-gpsman --without-shapelib --without-imagemagick --without-libproj --without-geotiff --without-dbfawk --without-map-cache --with-errorpopups That said, you probably won't have to use any of these! Type "../configure" all by itself and the script should eventually give you a summary of the packages that it will try to compile support into Xastir for. The only time you may want to add some of the above options is if the compile hangs up because of one of them. You can then add the option to configure, re-create the Makefiles to skip that feature, and get Xastir compiled without it. Once you get the problem solved, you can reconfigure and recompile to add that feature back in. At this point, if some things don't appear in the summary that you'd like/expect to appear, as long as you get to the "Type 'make' to build Xastir" message, you're doing fine. You can work on getting more things in there later. This is what you'd like to see at the end of the "../configure" run (minimum, there may be more "yes" answers): MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : no RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : no GraphicsMagick/ImageMagick (Raster maps) .. : no pcre (Shapefile customization) ............ : no Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : no FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no In other words, Xastir should build/compile with NO optional libraries installed! This will still give you USGS GNIS maps, APRSdos maps, WinAPRS maps, and PocketAPRS maps, plus audio alerts if you have a suitable audio player installed on your system. You'll also be able to attach a TNC either in command-line or KISS mode and connect it to Xastir. Mobile support will work with an attached serial GPS. Attached weather stations should work fine too. You won't get online maps or weather alerts with this configuration though. Worry about that stuff later once you get the minimal configuration working. Make: ----- Type "make". That stage should complete with no errors. You may have a warning or two show up, depending on your compiler version and your operating system. Make install: ------------- For this stage you need to have root privileges. "root" is the user on a Unix/Linux box that has the ultimate authority over everything. Follow these steps: su make install chmod 4755 /usr/local/bin/xastir (optional, see below) exit The first step takes you to root user privileges. You'll need to type in the root password when it asks for it. The "make install" step installs all of the pieces of Xastir in the appropriate places on your system. The "chmod" step sets up the Xastir executable so that it can assume root privileges at the points where it needs to, usually when it needs to access serial ports or AX.25 kernel networking ports. Note that if you don't need the above chmod command, don't use it. It will prevent creation of "core" files in case Xastir crashes, which makes debugging to figure out the root cause much more difficult. There are also some security risks in doing "chmod 4755", as it makes Xastir run as the root user at times. We've tried to minimize the risk by giving up root permissions when we don't absolutely require them, so the risks are smaller. At this point you have a minimal Xastir installed. Jump down to the "Operating Xastir" step below. -------------------------------------------------------------------- -------------------------------------------------------------------- Typical Install: ---------------- First, let's describe it: This will give you a working Xastir with local Shapefile maps, online street/topo/satellite-image maps, weather alerts, and audio alerts. Optionally you can add synthesized speech to the mix. You'll need to run /usr/local/share/xastir/scripts/get-NWSdata as root after you do the install in order to get the NOAA data files you'll need for the weather alerts. "get-NWSdata" requires "wget" in order to work. This is what you'd like to see at the end of the "./configure" run (minimum, there may be more "yes" answers): ------------------------------------------------------------------- MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : yes RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : yes GraphicsMagick/ImageMagick (Raster maps) .. : yes (GraphicsMagick) pcre (Shapefile customization) ............ : yes(PCRE2) Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : yes (libcurl) FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no ------------------------------------------------------------------- Note: You may see "ImageMagick" instead of "GraphicsMagick" and/or "wget" instead of "libcurl" for your installation of Xastir. Those are alternative packages that give similar functionality. also. -------------------------------------------------------------------- -------------------------------------------------------------------- Maximum Install: ---------------- First, let's describe it: This will give you a working Xastir with all of the non-debug "configure" options enabled, local maps, online street/topo/satellite-image maps, weather alerts, audio alerts, synthesized speech, Garmin RINO support, GPS download support, search for street address capability, FCC/RAC callsign lookups, and all of the supported map types. This is what you'd like to see at the end of the "./configure" run: ------------------------------------------------------------------- MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : yes RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : yes GraphicsMagick/ImageMagick (Raster maps) .. : yes (GraphicsMagick) pcre (Shapefile customization) ............ : yes(PCRE2) Berkeley DB map caching-Raster map speedups : yes internet map retrieval .................... : yes (libcurl) FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : yes libproj (USGS Topos & Aerial Photos) ...... : yes GeoTiff (USGS Topos & Aerial Photos) ...... : yes Festival (Text-to-speech) ................. : yes GPSMan/gpsmanshp (GPS downloads) .......... : yes ------------------------------------------------------------------- Note: You may see "ImageMagick" instead of "GraphicsMagick" and/or "wget" instead of "libcurl" for your installation of Xastir. Those are alternative packages that give similar functionality. You may see "(legacy)" after the "yes" for PCRE if you've installed the old, obsolete package "pcre" instead of "pcre2" (many Linux systems are starting to drop the old one, so the new one is preferred, but Xastir will work with either). TBD -------------------------------------------------------------------- -------------------------------------------------------------------- Operating Xastir: ----------------- Again, NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Assuming you want to start Xastir up in the English language, you can type (from an xterm window): xastir which will start up the program without giving you back a command-prompt in your xterm window (until Xastir exits), or you can type (from an xterm window): xastir & which will start Xastir in the background, giving you back your xterm for more commands. The typical way to start it is with "xastir &". Of course you can get fancier and attach it to your window manager's menus or create an icon on your desktop which starts it. Those are operating system/window manager-specific, so we won't cover how to do that here. The first time you start Xastir it will show a default map of the world plus pop up the File->Configure->Station dialog. Enter a callsign on that dialog and press the OK button. Changing the Language: If you want to start Xastir using some other language, you do that with command-line switches when you start Xastir. Once you use one of these switches, that language option becomes "sticky", meaning you won't have to enter that command-line switch again unless you wish to change languages. There are some command-line switches that you can If you type "xastir -?", which is an invalid command-line option, you'll see this: xastir: invalid option -- h Xastir Command line Options -c /path/dir Xastir config dir -f callsign Track callsign -i Install private Colormap -geometry WxH+X+Y Set Window Geometry -l Dutch Set the language to Dutch -l English Set the language to English -l French Set the language to French -l German Set the language to German -l Italian Set the language to Italian -l Portuguese Set the language to Portuguese -l Spanish Set the language to Spanish -l ElmerFudd Set the language to ElmerFudd -l MuppetsChef Set the language to MuppetsChef -l OldeEnglish Set the language to OldeEnglish -l PigLatin Set the language to PigLatin -l PirateEnglish Set the language to PirateEnglish -m Deselect Maps -p Disable popups -t Internal SIGSEGV handler enabled -v level Set the debug level Ignore those for now unless you need to change the Language. OK, Xastir should show up on your screen at this point. We're assuming that you're already running X-Windows graphical environment at this point. If you're in command-line Linux/Unix only, Xastir won't run. If you've configured in ShapeLib capability, you'll need to run /usr/local/share/xastir/scripts/get-NWSdata as the root user in order to get the NOAA data files you'll need for the weather alerts. The script requires "wget" in order to work. Run this script periodically (once every six months perhaps?) to keep your weather alert maps up-to-date. If you're not in the U.S. or one of it's possessions then you can safely ignore this download. Various ways to manipulate Xastir: Context-Dependent Operations: ----------------------------- Normal Draw-CAD Measure Move ------ -------- ------- ---- Cursor Arrow Pencil Crosshairs Crosshairs LeftClick SelectObject LeftDrag ZoomToArea ZoomToArea MeasureArea MoveObject MiddleClick ZoomOut SetCADPoint ZoomOut ZoomOut Alt-F, Alt-V, etc to bring up main menus via the keyboard. Use arrow keys to navigate menus and/or single letters corresponding to the "hot" letter (underlined lettter) for each menu item. "ESC" to back out of the menu system. Global Operations: ------------------ LeftClick Select Menu or GUI Item (when in menus or dialogs) LeftDblClick FetchAlertText (when in View->Wx Alerts dialog) RightClick OptionsMenu Home Center the map on your home station PageUp ZoomOut PageDown ZoomIn ArrowUp PanUp ArrowDown PanDown ArrowLeft PanLeft ArrowRight PanRight "=" GridSize++ "+" GridSize++ "Num+" GridSize++ "-" GridSize-- "Num-" GridSize-- "Space" Activate current widget "Tab" Rotate among widgets "Back-Tab" Rotate among widgets backwards Other Possible External Stimuli: -------------------------------- Send a SIGUSR1 to cause a snapshot to be taken. Send a SIGHUP to cause Xastir to save/quit/restart. Send a SIGINT, SIGQUIT, or SIGTERM to cause Xastir to quit. Connect to TCP port 2023 if Server Port is enabled to send/receive packets. Send to UDP port 2023 via the xastir_udp_client program to inject packets. Note that you can also tweak a define/recompile to reverse the left/right button functions. Configuring Xastir: ------------------- *) Note that the menu's have a dashed line near the top. If you click on that dashed line it acts like a cut-line for the menu and detaches that menu from the main menu. You can then move that menu off to another area of your screen. You might try that with the File->Configure menu at this time. *) Go to File->Configure->Station and set your callsign. Set up other parameters/comment fields on this dialog that may need setting. *) Go to File->Configure->Defaults and set parameters there. You have the main parameters set now. Next is to enable some interfaces so that you can see some packets come across. Easiest might be the Internet interfaces, assuming the computer you're on has Internet access and is hooked up to it currently. *) Run "callpass" in another Xterm window in order to generate your Pass-code number. Save that number as you'll need it for each Interface dialog where you might need to authenticate your callsign. Of course you can always run callpass again if you forget it! *) Go to Interface->Properties then click on "Add". Click "Internet Server". Another dialog will come up that allows you to enter the Host, and the Port. Enter your Pass-code number here. People often check the "Activate on Startup?" and the "Reconnect on NET failure?" options on this box. You may also assign a comment to this interface which describes the interface better for you. Click "OK" to create the interface. If you checked "Activate on Startup?" then the interface will start as well and you'll be receiving packets. Browse "http://www.aprs2.net/" to find a reasonable set of servers to start with. Another possibility is to use "rotate.aprs2.net" port 14580, which theoretically should rotate among the available second-tier servers. See "http://www.aprs2.net" for more info. You'll need to put in a filter string, such as "r/35/-106/500" which shows you stations that are within 500km of 35dN/106dW (Thanks for that one Tom!). For additional filter settings check out: http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm *) Start that interface from the Interface->Start/Stop dialog if it's not started already. You'll see icons in the lower right toggling and see callsigns in the lower left status box if packets are coming in. One thing about configuration: Most things don't get written to Xastir's config file until you choose either "File->Configure->Save Config Now!" or you exit Xastir. Map Selections however are immediate. *) Creating/starting interfaces for other types of devices is similar. If you're wanting to create AX.25 kernel networking ports you'll have to refer to the HAM HOWTO documents and perhaps the linux-hams mailing list for help. For AGWPE connections refer to that AGWPE docs and mailing list. It's recommended that if you run a local TNC, you run it in KISS mode. You can do that via the Serial KISS TNC interface, or via AX.25 Kernel Networking ports. Some of the more esoteric types of interfaces may require some questions on the Xastir list. Don't be afraid to ask them as we've all been there before. A Note About Paths: ------------------- New path methods were discussed early April, 2005, and are being implemented world-wide: "WIDE2-2" for fixed stations, balloons, aeronautical-mobile "WIDE1-1,WIDE2-1" for mobiles/portables With this system, "WIDE1-1" has replaced "RELAY". Never use "WIDE1-1" in anything but the first path slot. "RELAY", "WIDE", "TRACE", and "TRACEn-N" are deprecated and should not be used anymore. If you want to insert a single hop callsign later in the path use "WIDE2-1" instead, for example: "WIDE1-1,WIDE2-1" will go exactly two hops and use _either_ home fill-in digi's or mountaintop digi's for the first hop, mountaintop digi's only for the second hop. Home fill-in digi's (only where absolutely needed) should be set up to respond to "WIDE1-1" instead of "RELAY". A Note About the Map Directory: ------------------------------- The map directory (/usr/local/share/xastir/maps/) is free-form, meaning you can have links in there, subdirectories, etc. Organize it in any way that makes sense to you. From within the Map Chooser you can select a directory name, which will select every map underneath that directory, so keep that in mind while organizing your maps. Enabling Weather Alerts: ------------------------ You must have Shapelib compiled into Xastir. Xastir now comes with Shapelib support built-in. PRCE/dbfawk are optional. Install NOAA shapefile maps as specified in README.MAPS. These files must be installed into the /usr/local/share/xastir/Counties/ directory. You may use this script to download/install them for you: "/usr/local/share/xastir/scripts/get-NWSdata" which must be run as the root user, and requires "wget" to work. A neat trick: You can copy some of these maps into the /usr/local/share/xastir/maps directory somewhere (a new subdirectory under there is always fine), then you can select some of these maps as regular Xastir maps as well. Enabling FCC/RAC Callsign Lookup: --------------------------------- Run the /usr/local/share/xastir/scripts/get-fcc-rac.pl script as root, which will download and install the proper databases into the /usr/local/share/xastir/fcc/ directory. At that point the callsign lookup features in the Station Info dialog and in the "Station->Find Station" menu option should be functional. Enabling Map Feature Lookup: ---------------------------- Install USGS GNIS files into the /usr/local/share/xastir/GNIS/ directory. Call out the proper file when invoking the "Map->Locate Map Feature" menu option. Note that if you also link a subdirectory name under the maps directory back to the /usr/local/share/xastir/GNIS/ directory, you'll be able to use the GNIS files as maps under the Map Chooser as well. See README.MAPS for how to do this. Enabling Street Address Lookup: ------------------------------- Download the USA.geocode file and install it into the /usr/local/share/xastir/GNIS/ directory. This will enable the "Map->Find Address" menu option to work. Xastir will place a big "X" on the map at the street address it finds for you. This file is sometimes available at http://www.dementia.org/geocoder/tgr2003/ As an alternative you can download the individual state files that are located there. Enabling Audio Alarms: ---------------------- Download and install sample audio files from Xastir's GitHub download site: git clone http://github.com/Xastir/xastir-sounds Copy the files to your Xastir sounds directory, for instance: /usr/local/share/xastir/sounds/ Install a command-line audio player. Call out the path/name of that player in the File->Configure->Audio Alarms dialog. Common ones are vplay and auplay, but there are many others. Enable the types of alarms you desire in that same dialog. You should be able to test it manually from a shell by typing the command in something like this: vplay filename Once you find a command that works, type it into Xastir's Audio Alarms dialog exactly the same except omit the filename. Enabling Synthesized Speech: ---------------------------- *) MacOSX TBD *) Windows TBD *) Linux/FreeBSD/Solaris Install the Festival Speech Synthesizer. Configure/compile support for it into Xastir. Start up the Festival server before starting Xastir. Xastir should start up and connect to the server. Use the options in File->Configure->Speech to decide which things you'd like Xastir to speak to you about. Note that the Proximity Alert option in the File->Configure->Speech dialog uses the distances set in the File->Configure->Audio Alarms dialog. Enabling GPS Waypoint/Track/Route Download Support: --------------------------------------------------- Install GPSMan and gpsmanshp. Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. You'll see download options for each type on the Interface menu. Note that Xastir requires a version of gpsman at least as recent as 6.1. Older versions of gpsman may not work. Enabling Garmin RINO Support: ----------------------------- Install GPSMan (and gpsmanshp if you wish normal GPS download support as well). Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. In the "File->Configure->Timing" dialog you'll see an option for "RINO -> Objects Interval". That sets the interval at which Xastir will download waypoints from an attached RINO unit. Any waypoints that begin with "APRS" will have the "APRS" chopped off, and the remaining name will be used to create APRS(tm) Objects. Those objects will be plotted on the map and transmitted as well if transmit for objects/items is enabled. TBD Transmit Enable/Disable Options: -------------------------------- Each interface has a separate transmit enable. The Interface menu also has a few global transmit enables. All of these must be enabled for a particular interface to transmit. Also, for Internet servers, you typically need to authenticate with the server using your callsign/pass-code before you're allowed to inject packets into the Internet stream which may get gated out to RF. If you just want to talk to other Internet users, you don't need a pass-code to authenticate to the servers. Igating Options: ---------------- There are igating options on each local TNC interface. There are other global igating options on the File->Configure->Defaults dialog. The global option sets restrictions on all igating. Where stuff is kept: -------------------- Per-user configurations are kept in each user's ~/.xastir directory, by default. In particular the ~/.xastir/config/xastir.cnf file is where most of the configs are kept. This directory can be optionally specified using the -c /path/dir command line option. Make sure you specify a directory, not a file! Xastir will create the directory and several subdirectories if they do not exist when you start up. A few executables are installed in /usr/local/bin/. Scripts are installed in /usr/local/share/xastir/scripts. Maps are installed in /usr/local/share/xastir/maps/. Lots of other directories are under /usr/local/share/xastir/. More? ----- Anything else? Let's hear about what's still confusing or needs to be expanded in this document. Thanks! APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/bootstrap.sh000077500000000000000000000010001501463444000167110ustar00rootroot00000000000000#/bin/sh -e # # # Copyright (C) 2000-2023 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.2/callpass.1000066400000000000000000000013751501463444000162400ustar00rootroot00000000000000.TH callpass 1 2019-05-01 "The Xastir Group" .SH NAME callpass \- generate Pass-code associated with your callsign for authentication via xastir to APRS(tm) network. .SH SYNOPSIS .B callpass .I .SH DESCRIPTION Generate passcode for use in xastir authentication to APRS network for traffic delivery to cooperating systems. .SH EXAMPLES callpass nocall outputs 'Passcode for nocall is 12960' .SH NOTES There is no error or consistency check for callsign. This utility will generate a passcode for any string. .SH SEE ALSO xastir help file .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/callpass/000077500000000000000000000000001501463444000161505ustar00rootroot00000000000000Xastir-Release-2.2.2/callpass/.vimrc000066400000000000000000000014331501463444000172720ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/callpass/Makefile.am000066400000000000000000000003051501463444000202020ustar00rootroot00000000000000 # Copyright (C) 2000-2023 The Xastir Group MAINTAINERCLEANFILES=Makefile.in bin_PROGRAMS = callpass callpass_SOURCES = callpass.c callpass_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.2/callpass/callpass.c000066400000000000000000000043101501463444000201140ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include #include #include #define kKey 0x73e2 // This is the seed for the key #define true 1 static short doHash(char *theCall) { char rootCall[11]; // need to copy call to remove ssid from parse char *p1 = rootCall; short hash; short i, len = 0; char *ptr = rootCall; while ( (*theCall != '-') && (*theCall != '\0') ) { *p1++ = toupper( (int)(*theCall++) ); len++; } *p1 = '\0'; hash = kKey; // Initialize with the key value i = 0; while (i < len) // Loop through the string two bytes at a time { hash ^= (unsigned char)(*ptr++) << 8; // xor high byte with accumulated hash hash ^= (*ptr++); // xor low byte with accumulated hash i += 2; } return (short)(hash & 0x7fff); // mask off the high bit so number is always positive } short checkHash(char *theCall, short theHash) { return (short)(doHash(theCall) == theHash); } int main(int argc, char *argv[]) { char temp[11]; if (argc>1) { memmove(temp, argv[1], 11); // Process up to 10 characters temp[10] = '\0'; // Forced string terminator if (temp[0] != '\0') { printf("Passcode for %s is %d\n", temp, doHash(temp)); } } else { printf("Usage:callpass \n"); } return(0); } Xastir-Release-2.2.2/changes.txt000077500000000000000000000517561501463444000165400ustar00rootroot00000000000000 Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Changes.txt 04.01.2001 See ChangeLog for software changes... 11/13/2000 codebase version changed to 0.4.0, starting next development release 11/08/2000 0.3.6-2 -- cb modified color.c to behave with gcc 2.96 added callpass delete object patch for db.c - J.Stueve KE4NFJ 09/24/2000 Alpha 0.3.6b added time/date to buletins list. modified PHG routines. added the beginings to view all message traffic. 09/19/2000 Alpha 0.3.6a fixed/added sorting for bulletins. * *fixes by KE4NFJ 09/16/2000 Alpha 0.3.6 add the usage of comments in the nws-stations.txt file, "#" as first char on a line. add bulletins within a radius view screen. added speedups for pixmaps. * added Italian language # *modifications by VE6LFM #additions by IK0YUP 08/27/2000 Alpha 0.3.5a bug fix for the PHG not displaying. 08/26/2000 Alpha 0.3.5 changed WX alert minimum refresh from a int to a long. Updated the French language file. fixed a network socket closing problem. changing all posits (in and out) to High precision, Compressed format will output high precision. added igating (net to RF) of NWS weather messages. (to use this build a text file in the xastir users directory as .xastir/data/nws-stations.txt list each call or NWS station like "SECIND" that you would like to transmit via RF) 07/14/2000 Alpha 0.3.4a fixed a minor problem for some solaris systems.* * fixes/additions by KE4NFJ 07/10/2000 Alpha 0.3.4 (no changes from the pre-release) fixed symbol decoding for stations with an overlay character. added AEA to TAPR2 path decoding to fix MIC-E decoding with AEA type TNCs. modified station trails.+ speed ups for Pixmaps images.@ fixed output logic on mobile data. removed unused data from makefile. modified altitude decoding for "/A=XXXXXX". added "/A=XXXXXX" altitude encoding on output of station positions (with GPS input and not WX data output). added NETWORK_WAITTIME to config file, this sets the network time out value when doing host lookups and socket connections, default is 10 (no GUI Interface for this yet). added WX_ALERTS_REFRESH_TIME to config file, this sets the minimum seconds allowed between a WX Alert starting a redraw of maps on the screen, default is 30 (no GUI Interface yet). updated help file. + modifications by WE7U @ fixes by PE1DNN 06/12/2000 Alpha 0.3.3 fixed data position information output logic. fixed missing E/W logic in compressed posit formats.* * fixes/additions by KE4NFJ 05/31/2000 Alpha 0.3.2 fixes for Solaris.* fixed a bug in sending data via TNC, the first few chars were dropped on MFJ's with Paccom software installed. added support for image maps (.xpm format only) with .geo files for location. fixed small problem with weather alerts expiring incorrectly for Daylight Savings Time.* fixed some conditions for alert matching on weather alerts.* fixed path length.@ fixed Dos map problem dropping data, as in Ilchicgo.map.* fixes for WX-Alerts.* changed line tracking to not display line when the object is faster then 900 MPH, however I may make this an option, or a soft limit. fixes for 0.91 of lesstif, some scrolled text was not positioned correctly. added wx gust reset. removed some filtering on AX.25 ports.@ fixed data command/transmission problem for some TNCs. changed the default code compiling to not include debugging information, this reduces the executable code size by a huge amount. However I also added an option in the Makefile to compile with this information. changed Segmentation faults operation, if the program Segfaults, it will terminate, but now it should happen cleaner. changed the way broken pipes are handled, hopefully you won't see those again. added white as a background color. modified MIC-E decode logic for more support of the protocol.+ added transmission of compressed position data.* cleaned up decoding of compressed data.* added jump to last map position. fixed map sorting for case insensitive. * fixes/additions by KE4NFJ @ fixes by PE1DNN + modifications by WE7U and me (KC2GJS). Also I changed my CALL from KC0DGE to KC2GJS. 03/30/2000 Alpha 0.3.1 changed Baro reading on WX-200 to Sea Level vs. Local Level. added more space for and digits for some WX station display fields. added changes.. so Xastir will run on FreeBSD.+ fixed object decoding. fixed compressed format symbol decoding added compressed object decoding. added course and speed to compressed decoding. added logic to AX.25 interface so a "*" would be added to the digipeater call that's transmitting the packet.@ fixed bug in AX.25 interface, seems as if all AX.25 packet data is transmitted through the interface. Even if it is from a device not used by Xastir. Added code to "filter out" incoming packets that are from another device. @ fixed tab groups for keyboard movement on message boxes, tracking, locate station, and misc dialogs. removed transmitter off message popups, some found this annoying. changed to case insensitive sort on stations.* fixed bug in WX data output, rain in past 24hr was switched with rain since midnight on output of data. fixed a possible crash on shutdown of the network connections. added/fixed max station now only has a memory limit. The station buffer now allocates memory as needed and the max station's error popup will only show when no more memory can be allocated for stations.* changed message time intervals. + Additions by N3NYN @ fixes by PE1DNN, modified by KC0DGE * fixes by KE4NFJ 03/23/2000 Alpha 0.3.0 changed the station Info box size. changed net connect and host lookup return a good connect faster. modified net connect procedure.. used terminate thread instead of sigalarm. modified the size of the raw WX buffer. Added Net WX interface. modified symbol routines.* Added new symbols.* misc include file fixes.* modified Makefile so that compiling on RH5.2 and using the old AX.25 utils works.+ fixed the AX.25 port lockup on start up problem. Added Radio Shack WX200/Oregon Scientific WM-918 support. misc WX station fixes and changes. fixed dialogs to work on older system/KDE combo. Added WX data decode for APRS POS/WX format. Added popup message when MAX_STATIONS is exceeded. * additions by KE4NFJ + fix by HI8GN 03/14/2000 Alpha 0.2.9 changed it so any data from a good call sign goes into data base. changed serial port start up, if serial lock file errors on opening, still try to open port. fixed Query response for ?IGATE? to number of "local" stations and added message counter. added a few General Queries to the menu. added Query response for ?APRSP. changed Widget shells (Major code change) to support main window over child windows. fixed/changed some misc gui stuff. fixed New fcc data lookup (too slow!).. However it requires the following: **** NOTE to use the NEW data base file it must be sorted first!!! **** Make sure you have plenty of disk space for this as the file is BIG! To sort the file: sort +4 -t \| EN.dat >EN.dat.sorted rm EN.dat mv EN.dat.sorted EN.dat removed previously added reject logic for bad rain data, caused a segfult. fixed interface gui causing segfault if windows closed out of order. moved fcc/rac test to after window's opens. Added status for fcc/rac rebuilding index files. removed usleep out of threaded routines read_port() & write_port() as usleep is not thread safe on solaris, replaced usleep with select. fixed baud rate selection, 38400 and 57600 were reversed. fixed a problem in the Makefile where it couldn't find Lesstif Libs on some systems. fixed some memory leaks. * fixed data entry screens to remove added spaces in data input. Added Peet Bros Complete data mode for WX Station. & modified WX Station screen for more info if in Complete data mode. fixed bug in heard_via_tnc_in_past_hour. added second chance transmit of message if heard via tnc but not in past hour then try the last net connection the station was heard. fixed German ',' vs '.', stupidity on my part. added busy cursor (to map etc..) when working with interfaces. fixed bug in adding a WX port at 2400 bps.. on startup would go to 4800. fixed bug in starting interface (manually) when it is already up. fixed bug in connection to the net where the host is found but the connection is not made. cleared out some possible "broken-pipe" errors on closing a errored interface. cleaned up a possible segfault on messages with out acks. added some more WX rain checks.. Please Check me.. added Spanish Language support. + * fix by KE4NFJ & additions by KD6VPE + additions by HI8GN 03/08/2000 Alpha 0.2.8 added/changed color lookups, now has it's own file and colors should be consistent across various X managers. added local stations list. added some Query buttons to station info window. cleaned up buttons on dialogs. added Query responses for ?APRST ?PING? ?APRSM ?APRSD ?IGATE. moved more gui stuff to separate files. Added popup message windows for errors, status, query responses, etc. fixed/added updates to local station for last path heard and position/packet time. fixed a bug when transmitting messages via RF to a local station. ### NOTE THIS IS A BIG ONE!!!! added more reject logic for bad rain data, for the WX Station. 03/03/2000 Alpha 0.2.7 changed formula used on Qualimetrics Q-Net WX station decoding (another minor difference). fixed WX wind gust. found a WX rain bug. changed some more background colors. fixed a broken pipe bug on write. changed wx alert display routines.* added sound for wx alerts.* fixed Motif popup menu on map problem (FINALLY!!!!!). fixed bug in station lists. added save of station list size. fixed clipboard copy for call sign on station list (as long as the call does not move in the list). changed gethostbyname2 to gethostbyname for older systems. * additions by KE4NFJ 02/27/2000 Alpha 0.2.6 changed zoom status window size fixed a bug in auto map directory. fixed a bug in config not saving if no backup file exists. changed formula used on Qualimetrics Q-Net WX station decoding (minor difference). changed some background colors. added some extra debugging on the serial ports. fixed Q-Net transmit wx data (original routine needed Course and Speed so it can TX WX data). 02/26/2000 Alpha 0.2.5 More Motif stuff.* More Makefile Mods. * (and me) fixed port shutdown but data to be written bug. fixed a bug when sending raw WX data. hopefully fixed mouse button popup menu (zooming/panning) for Motif. added Qualimetrics Q-Net WX station decoding. fixed? Peet bros packet mode for WX station reading (wind/rain problem). fixed? alignment problem for headers on station/wx/mobile lists. * additions by KE4NFJ 02/25/2000 Alpha 0.2.4 fixed a bug in AX.25 status (input bytes). fixed the map redraw bug? Modified the Makefile. added time stamp in message box. 02/24/2000 Alpha 0.2.3 Added code to remove stale serial lock files. Added option for WX Alert Counties maps to appear above or below other loaded maps. Added Station List, Mobile Station List, and WX Station List. Modified WX station decoding. Added Transmitting of Raw WX data - Peet Bros. UII, U2k (data logging), U2k (Packet). Added WX station logging. Added option to compile with out AX.25 (look at Makefile, Let me know how it works for you!).* Added Host name on top bar.* Modified WX Alerts.* Added some Motif Conditions (start of better Motif vs LessTif support).* * additions by KE4NFJ 02/19/2000 Alpha 0.2.2 Added more WX station stuff and WX transmit !! PLEASE CHECK THIS fixed a bug in AX.25 Gui restart. Modified Makefile to be a little more generic. Changed operation of WX Alerts so screen updates don't hold the system up. 02/18/2000 Alpha 0.2.1 Ok first round is through some had problems, some had none. Deleted a include file giving some of you problem. Modified some of the interface code for displaying status. Fixed some bugs in the interface status display code. 02/17/2000 Alpha 0.2.0 0.1.4 is dead. I've decided not to continue with this version number because A good part of Xastir has been rewritten for the threaded I/O. I have also brought the functionality up to warrant a much higher version number. This version allows multiple TNC's and Internet connections. Complete rewrite of I/O (Too many changes to list). Added AX.25 support built in. @ Changed RAC look up for "VE" and "VA" only, rather than just "V". Changed I/O menus. Changed default menus. Fixed some IGate problems. Changed HOST lookup Added $ULTW WX data support. Added support for WX stations (beginning support so far). Modified WX support. Added WX Alert List (with WX Alert county maps. * * additions by KE4NFJ @ AX.25 Parts adopted from: aprs_tty.c by Henk de Groot, modified by KC0DGE 12/30/1999 Alpha 0.1.4 changed Mapping for higher precision display (Still testing) (Example 28.255 min instead of 28.25 min) NOTE: Your zoom and position in your xastir.cnf file will be based on the previous data and when you upgrade you may find your position and zoom in the wrong place when you first start it. added TNC format (8N1, 7E1, 7O1) to the TNC. cleaned up a possible TNC over-run error. changed some tracking constants for new map precision. added WX port code and dialogs. cleaned up some display code. cleaned up TNC code. changed automap detection, it should work better on odd sized maps. added more map support and better decoding. * fixed a map pan up bug. fixed WX gust missing bug in station info box. added support for dos maps. * added the start of station queries. added gpsd support (networked GPS). @ added support for filled map types * (and me) added support for background map colors, Selection in Maps menu. added two methods for displaying station labels. fixed a bug in weather from a Peet Bros U2K with negative temp. disabled problem in alerts routine deleted old debug command line, now is -v . added new command line language options. changed Makefile to work with the new command line language options. deleted use of HELP_DATA key in xastir.cnf file changed start up to check and make missing directories for user data. * additions by KE4NFJ @ additions by WE7U 11/14/1999 Alpha 0.1.3 fixed rain to show in mm instead of cm (in metric mode). fixed update to display for new data, not just position. added support for compressed map format. * fixed time values to the correct time_t rather than unsigned long. added Canadian Callsign Lookup. + added fast search and indexing of US and Canadian Callsign Lookup. + added check for new file to rebuild the search index for above. added support for new FCC file format. fixed an error in the make install for new a install. added support for other languages (with the language.sys file) (more to do). added support for multi color tracking lines. @ fixed additional tracking line bugs. added support for station position ambiguity. added support for NET to RF IGATE for messages. fixed message data to fit in with the spec. added Proximity and band opening alarms. # fixed Red Hat core dump when no files in map directory and using the map chooser. added I-Gate logging. added some Reject I-Gate logic. added I-Gate on ack's (oops forgot this!) fixed I-Gate to net logic (or at least made it more sane). moved Proximity and band opening alarms to work on any incoming packet not just new ones. added Language install added GNU LICENSE * additions by KE4NFJ + additions by VE3UNW @ additions by WE7U # additions by KD5AMB 10/22/1999 Alpha 0.1.2 fixed net connect core dump if the server was not available. removed source directory copy to /usr/local/src/xastir on install. (no really needed just messed up the developers. changed the zoom level to match with the actual level. added GPS GLL string decoding. * cleaned up station data base code.* changed some makefile options (runs smoother). started work on Igate to RF. fixed mistake in map loading stuff. + * additions by KE4NFJ (A big THANKS!!) + fixes by Chris Bell (THANKS!!) 10/01/1999 Alpha 0.1.1 !!!! Added/changed file structure to fit in the more standard FHS format. !!! added GPS support via HSP cable. added GPS time value. added APRS(tm) output in mobile format when GPS is active. added/fixed net/tnc clean up. fixed net data decode for servers that put out Carriage returns not Line feeds. (*) added more aprs decode support (for decoding CsT characters on RMC and GGA strings). (*) added environment values XASTIR_USER_BASE and XASTIR_DATA_BASE to set alternative directory locations for user data and common data. (-) added more aprs decode support (for handling some compressed mode lat/lon). (+) added course and speed decode for aprs mobile stations. added decoding of altitude in some formats other than GGA strings. fixed Track line bug. added more track lines. fixed decoding of some missed status data. added changes as per WE7U for grid lines every degree, However this is an auto selection on zoom level. added changes for Humidex (chill factor) only displays in metric. @ fixed grid lines so they don't erase map lines. added zoom info. fixed GPS drop off of last digit on some GPS (I hope). added install feature in makefile (fits in with above). added support for other users than root (!!! you need to have access to the devices you want to use still !!!). fixed some window close problems. Tested with version 0.89 of Lesstif (seems ok, no problems yet!!). added sorting of map files in map chooser. fixed station info box/send message core dump when message box open and info box closed. added Display for incoming packet data (with selection of data type). added Station Tracking. * additions by KE4NFJ (A big THANKS!!) + additions by WE7U (Again A big THANKS!!) - additions by KE4NFJ and modified by me. @ additions by VE3UNW (Again A big THANKS!!) 08/17/1999 Alpha 0.1.0 Do not use Lesstif version 0.88.9! It makes the use of radio buttons crash the program. Not sure why.. perhaps a bug in this version of Lesstif?! Ok first official canning of Alpha characters in the version numbers, This would have been 0.0.Kt4, but it gets too confusing. From now on, test versions, for that matter any version will be numeric digits only and no special tX on the end for test versions. Trying to keep it simple. fixed a "major stupid" bug, put any object to the East off its real location. added decoding for Peet Bros UM2. fixed some bugs in displaying temp on the station info screen. added sound alerts for messages. added Send message button for Station Info. added Multi-hosts for Internet connections. added GPS Support. fixed some core dump problems on incoming data. 07/22/1999 Alpha 0.0.Kt3 (test version for K) !!!!! This is a test version !!!!!! added wx display on maps. added timeout indicator when loading maps. added Net/Tnc status indicators. added auto message responder. added Power-gain circles. fixed Metric values. Meters should have been kilometers. fixed some misspellings. fix/add wx data now changes MPH to KPH and temp goes for F to C, inches go to cm. added PHG to station info. fixed hear via TNC statement in station info.. added decoding for Peet Bros. data logging mode record format for over air data. Hopefully fixed: Red Hat tnc & net down/up core dump problem. 06/26/1999 Alpha 0.0.Kt2 (test version for K) !!!!! This is a test version !!!!!! Fixed some minor bugs. Changed some window layout code, Hopefully it will be more consistent across window managers. More Speed ups, Some major speed up to display writing. More Message fixes. Changed the way you zoom and scroll the display. Added preset zoom levels. Added Station info display. Added Station tracking, with a trailing tracking line. Beginning work on weather data, station info will report data if available. Fixed net connection drop bug (hopefully). Fixed Red Hat map chooser bug. New, if the connection is dropped there is a new option under configure, Internet, That will allow you to reconnect to the net if this option is checked. Changed, The messaging system is going through an overhaul, hopefully not so much of a kludge. 06/02/1999 Alpha 0.0.J Major bug fixes for Red Hat users.. I hope I got them all.. 06/01/1999 Alpha 0.0.I First release of Xastir! Lots of things are not working.. No station information windows. It doesn't decode all of the APRS(tm) packets. Messaging works, however it is not finished. Currently there is no support for GPS data for setting your position. Xastir will read window/mac APRS(tm) map format and automatically select the correct map for your area win auto maps on. Currently this is slow and will be corrected in future versions. Most of the APRS(tm) are in place and will position on the map. Net interface is live, but also needs more work. Configuration screens are very basic.. In other words it is the first release of FREE Alpha version software! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html" Xastir-Release-2.2.2/config/000077500000000000000000000000001501463444000156135ustar00rootroot00000000000000Xastir-Release-2.2.2/config/.vimrc000066400000000000000000000014331501463444000167350ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/config/24kgrid.dbfawk000066400000000000000000000036331501463444000202460ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map USGS 24k grid shapefiles, which contains bounding # rectangles for USGS 1:24000 quadrangles. # The shapefile itself can be had from # http://data.geocomm.com/quadindex/ # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="NAME:STATE:LAT:LONG:MRC"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME:STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=65535; label_level=512; label_color=2; font_size=1; symbol=""} # per-field rules are applied to the dbffields that are read from each record. /^NAME=(.*)$/ {name="$1; next} /^STATE=(.*)$/ {name="$(name),$1; next} Xastir-Release-2.2.2/config/Makefile.am000066400000000000000000000076251501463444000176610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # configdir = ${pkgdatadir}/config EXTRA_DIST = \ language-Dutch.sys \ language-English.sys \ language-French.sys \ language-German.sys \ language-Italian.sys \ language-Portuguese.sys \ language-Spanish.sys \ language-ElmerFudd.sys \ language-MuppetsChef.sys \ language-OldeEnglish.sys \ language-PigLatin.sys \ language-PirateEnglish.sys \ xastir.rgb \ gps_wpt.dbfawk \ 24kgrid.dbfawk \ stored_track.dbfawk \ tgr2shp.dbfawk \ tgr2shppoly.dbfawk \ tgr2shppoly_2006.dbfawk \ tgrcty.dbfawk \ tgrkgl.dbfawk \ tgrlk.dbfawk \ tgrlpt.dbfawk \ tgrlpy.dbfawk \ tgrplc00.dbfawk \ tgrwat.dbfawk \ nwsc_ddmmyy.dbfawk \ nwsc_ddmmyy_09.dbfawk \ nwsc_ddmmyy_09b.dbfawk \ nwsc_ddmmyy_10.dbfawk \ nwsc_ddmmyy_10a.dbfawk \ nwsc_ddmmyy_13.dbfawk \ nwsc_ddmmyy_15.dbfawk \ nwsfz_ddmmyy_19.dbfawk \ nwsmzddmmyy.dbfawk \ nwsmzddmmyy_09.dbfawk \ nwsmzddmmyy_11.dbfawk \ nwsmzddmmyy_16.dbfawk \ nwsmzddmmyy_17.dbfawk \ nwsmzoddmmyy.dbfawk \ nwsozddmmyy.dbfawk \ nwsozddmmyy_09.dbfawk \ nwsozddmmyy_14.dbfawk \ nwsozddmmyy_14b.dbfawk \ nwsozddap12.dbfawk \ nwsw_ddmmyy.dbfawk \ nwsw_ddmmyy_09.dbfawk \ nwsw_ddmmyy_10.dbfawk \ nwsw_ddmmyy_13.dbfawk \ nwsw_ddmmyy_14.dbfawk \ nwsw_ddmmyy_14a.dbfawk \ nwsw_ddmmyy_17.dbfawk \ nwsw_ddmmyy_20.dbfawk \ nwsw_ddmmyy_22.dbfawk \ nwsw_ddjn12.dbfawk \ nwsz_ddmmyy.dbfawk \ nwsz_ddmmyy_09.dbfawk \ nwsz_ddmmyy_10.dbfawk \ nwsz_ddmmyy_10b.dbfawk \ nwsz_ddmmyy_10c.dbfawk \ nwsz_ddmmyy_11.dbfawk \ nwsz_ddmmyy_13.dbfawk \ nwsz_ddmmyy_19.dbfawk \ nwsz1ddmmyy.dbfawk \ nwszoddmmyy.dbfawk \ nwshzddmmyy.dbfawk \ nwshzddmmyy_old14.dbfawk \ OSM_Cloudmade_administrative.dbfawk \ OSM_Cloudmade_highway.dbfawk \ OSM_Cloudmade_natural.dbfawk \ OSM_Cloudmade_poi.dbfawk \ OSM_Cloudmade_water_and_coastline.dbfawk \ OSM_geofabrik_roads.dbfawk \ OSM_geofabrik_waterways.dbfawk \ predefined_EVENT.sys \ predefined_SAR.sys \ tl_2009_aiannh.dbfawk \ tl_2009_aits.dbfawk \ tl_2009_arealm.dbfawk \ tl_2009_areawater.dbfawk \ tl_2009_county.dbfawk \ tl_2009_cousub.dbfawk \ tl_2009_edges.dbfawk \ tl_2009_mil.dbfawk \ tl_2009_nn_county.dbfawk \ tl_2009_pointlm.dbfawk \ tl_2009_zcta5.dbfawk \ tnc-startup.aea \ tnc-startup.d700 \ tnc-startup.d72_d710 \ tnc-startup.kam \ tnc-startup.kpc2 \ tnc-startup.kpc3 \ tnc-startup.null \ tnc-startup.paccomm \ tnc-startup.pico \ tnc-startup.sys \ tnc-startup.thd7 \ tnc-startup.tnc2 \ tnc-startup.tnc2-ui \ tnc-stop.d700 \ tnc-stop.d72_d710 \ tnc-stop.sys \ tnc-stop.thd7 \ tnc-stop.tnc2-ui \ areawater.dbfawk \ arealm.dbfawk \ tabblock.dbfawk \ cousub.dbfawk \ cousub00.dbfawk \ edge.dbfawk \ featnames.dbfawk \ pointlm.dbfawk \ gfe_public_weather.dbfawk \ gfe_metro_areas.dbfawk \ gfe_fire_weather.dbfawk \ gfe_coastal_waters_warnings.dbfawk \ gfe_coastal_waters.dbfawk config_DATA = ${EXTRA_DIST} install-exec-hook: -rm -f $(DESTDIR)$(configdir)/nwsfz_ddmmyy.dbfawk language-ElmerFudd.sys: language-English.sys $(top_srcdir)/scripts/langElmerFudd.pl -split >$@ <$(srcdir)/language-English.sys language-MuppetsChef.sys: language-English.sys $(top_srcdir)/scripts/langMuppetsChef.pl -split >$@ <$(srcdir)/language-English.sys language-OldeEnglish.sys: language-English.sys $(top_srcdir)/scripts/langOldeEnglish.pl -split >$@ <$(srcdir)/language-English.sys language-PigLatin.sys: language-English.sys $(top_srcdir)/scripts/langPigLatin.pl -split >$@ <$(srcdir)/language-English.sys language-PirateEnglish.sys: language-English.sys $(top_srcdir)/scripts/langPirateEnglish.pl -split >$@ <$(srcdir)/language-English.sys Xastir-Release-2.2.2/config/OSM_Cloudmade_administrative.dbfawk000066400000000000000000000046021501463444000245130ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_administrative.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NAME:ADMIN_LEVE"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NAME:ADMIN_LEVE"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=105; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=(.+)$/ {name="$1";next} /^ADMIN_LEVE=2/ {lanes=4; color=105; label_level=65536; font_size=1; next} /^ADMIN_LEVE=4/ {lanes=3; color=105; display_level=64; label_level=512; font_size=1; next} /^ADMIN_LEVE=6/ {lanes=2; color=105; display_level=64; label_level=512; font_size=1; next} /^ADMIN_LEVE=8/ {lanes=1; color=105; display_level=64; label_level=512; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_Cloudmade_highway.dbfawk000066400000000000000000000135071501463444000231340ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_highway.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="TYPE:NAME:ONEWAY:LANES"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="TYPE:NAME:ONEWAY:LANES"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=State Highway (.*)$/ {name="$(name)Hwy $1"; next} /^NAME=State Route (.*)$/ {name="$(name)SR-$1"; next} /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=Interstate (.*) Northbound$/ {name="$(name)I-$1 N"; next} /^NAME=Interstate (.*) Southbound$/ {name="$(name)I-$1 S"; next} /^NAME=Interstate (.*) Eastbound$/ {name="$(name)I-$1 E"; next} /^NAME=Interstate (.*) Westbound$/ {name="$(name)I-$1 W"; next} /^NAME=Interstate (.*)$/ {name="$(name)I-$1"; next} /^NAME=Washington Highway (.*)$/ {name="$(name)Hwy $1"; next} /^NAME=(.+)$/ {name="$1";next} #/^LANES=(.+)$/ {lanes="$1";} # TYPE: /^TYPE=abandoned/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=bridleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=construction/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=crossing/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=cycleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=driveway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=footway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=ford/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=living_street/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} # Note: No display_level or label_level /^TYPE=motorway/ {lanes=4; color=4; label_level=65536; font_size=3; next} # Note: No display_level /^TYPE=motorway_link/ {lanes=3; color=2; label_level=16; font_size=1; next} /^TYPE=path/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=pedestrian/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=platform/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=primary/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^TYPE=primary_link/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^TYPE=raceway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=ramp/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=residential/ {lanes=1; color=44; display_level=64; label_level=16; font_size=1; next} /^TYPE=road/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=secondary/ {lanes=2; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=secondary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=service/ {lanes=1; color=8; display_level=64; label_level=16; font_size=1; next} /^TYPE=service; residential/ {lanes=7; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=steps/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=tertiary/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=tertiary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=t/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=track/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=trail/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=tr/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=trunk/ {lanes=3; color=8; display_level=128; label_level=16; font_size=3; next} /^TYPE=trunk_link/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=unclassified/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=unsurfaced/ {lanes=1; color=105; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_Cloudmade_natural.dbfawk000066400000000000000000000042771501463444000231460ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_natural.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NAME:TYPE"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NAME:TYPE:"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=4; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=(.+)$/ {name="$1";next} # TYPE: /^TYPE=water/ {lanes=1; color=9; display_level=64; label_level=16; font_size=1; next} /^TYPE=forest/ {lanes=1; color=10; fill-color=10; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_Cloudmade_poi.dbfawk000066400000000000000000000047001501463444000222560ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_poi.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="CATEGORY:NAME"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="CATEGORY:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=16; label_level=16; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^NAME=(.+)$/ {name="$1";next} /^CATEGORY=Automotive/ {color=4; font_size=1; next} /^CATEGORY=Eating&Drinking/ {color=4; font_size=1; next} /^CATEGORY=Government and Public Services/ {color=4; font_size=1; next} /^CATEGORY=Health care/ {color=4; font_size=1; next} /^CATEGORY=Leisure/ {color=4; font_size=1; next} /^CATEGORY=Lodging/ {color=4; font_size=1; next} /^CATEGORY=Night Life and Business/ {color=4; font_size=1; next} /^CATEGORY=Sports/ {color=4; font_size=1; next} /^CATEGORY=Tourism/ {color=4; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_Cloudmade_water_and_coastline.dbfawk000066400000000000000000000044141501463444000254760ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_water.dbf" and "*_coastline.dbf". Unfortunately both # DBF files have the same signature, so we need to have this dbfawk # file match both of them. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NATURAL:NAME"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NATURAL:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=34; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=15; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^NAME=(.+)$/ {name="$1";next} /^NATURAL=shoreline/ {lanes=1; display_level=65536; label_level=1; font_size=1; next} /^NATURAL=water/ {lanes=1; display_level=65536; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_geofabrik_roads.dbfawk000066400000000000000000000140621501463444000226350ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "geofabrik.ge" which are # named "roads.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="osm_id:name:ref:type:oneway:bridge:tunnel:maxspeed"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="type:name:oneway"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record # NOTE: Most of these came from the OSM Cloudmade dbfawk. They need to be re-done for the geofabrik.de files. /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=State Route (.*)$/ {name="$(name)SR-$1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Interstate (.*) Northbound$/ {name="$(name)I-$1 N"; next} /^name=Interstate (.*) Southbound$/ {name="$(name)I-$1 S"; next} /^name=Interstate (.*) Eastbound$/ {name="$(name)I-$1 E"; next} /^name=Interstate (.*) Westbound$/ {name="$(name)I-$1 W"; next} /^name=Interstate (.*)$/ {name="$(name)I-$1"; next} /^name=Washington Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=(.+)$/ {name="$1";next} #/^LANES=(.+)$/ {lanes="$1";} # type: # NOTE: Most of these came from the OSM Cloudmade dbfawk. They need to be re-done for the geofabrik.de files. /^type=abandoned/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=bridleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=construction/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=crossing/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=cycleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=driveway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=footway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=ford/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=living_street/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} # Note: No display_level or label_level /^type=motorway/ {lanes=4; color=4; label_level=65536; font_size=3; next} # Note: No display_level /^type=motorway_link/ {lanes=3; color=2; label_level=16; font_size=1; next} /^type=path/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=pedestrian/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=platform/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=primary/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^type=primary_link/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^type=raceway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=ramp/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=residential/ {lanes=1; color=44; display_level=64; label_level=16; font_size=1; next} /^type=road/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=secondary/ {lanes=2; color=8; display_level=256; label_level=64; font_size=1; next} /^type=secondary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=service/ {lanes=1; color=8; display_level=64; label_level=16; font_size=1; next} /^type=service; residential/ {lanes=7; color=4; display_level=64; label_level=16; font_size=1; next} /^type=steps/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=tertiary/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=tertiary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=t/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=track/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=trail/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=tr/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=trunk/ {lanes=3; color=8; display_level=128; label_level=16; font_size=3; next} /^type=trunk_link/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=unclassified/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=unsurfaced/ {lanes=1; color=105; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/OSM_geofabrik_waterways.dbfawk000066400000000000000000000042201501463444000235460ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "geofabrik.de" which are # named "waterways.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="osm_id:name:type:width"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="name:type:width"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=34; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=15; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^name=(.+)$/ {name="$1";next} #/^type=shoreline/ {lanes=1; display_level=65536; label_level=1; font_size=1; next} /^type=river/ {lanes=2; display_level=65536; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/arealm.dbfawk000066400000000000000000000042251501463444000202370ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for AREALM # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:ANSICODE:AREAID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # buildings /^MTFCC=K/ {display_level=256; filled=1 color=2; fill_color=2; label_level=128; next} # PLCC /^MTFCC=L/ {display_level=0; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/areawater.dbfawk000066400000000000000000000043161501463444000207520ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for AREAWATER # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:ANSICODE:HYDROID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # water /^MTFCC=H20/ {filled=1; color=97; fill_color=97; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; color=97; fill_color=97; label_color=26; display_level=1024;skip} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/cousub.dbfawk000066400000000000000000000043611501463444000202770ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for COUSUB # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:UR:FUNCSTAT"; dbfinfo ="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CNECTAFP:NECTAFP:NCTADVFP:FUNCSTAT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=G/ {display_level=512;color=11; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/cousub00.dbfawk000066400000000000000000000042031501463444000204320ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for COUSUB00 # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP00:COUNTYFP00:COUSUBFP00:COSBIDFP00:NAME00:NAMELSAD00:LSAD00:CLASSFP00:MTFCC00:UR00:FUNCSTAT00"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME00:MTFCC00"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAME00=(.*)$/ {name="$1";next} # item locations /^MTFCC00=G/ {display_level=512;color=11; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/edge.dbfawk000066400000000000000000000077341501463444000177120ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for EDGES # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # dbfinfo="STATEFP:COUNTYFP:COUNTYNS:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH"; dbfinfo="STATEFP:COUNTYFP:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH:PERSIST:GCSEFLG:OFFSETL:OFFSETR:TNIDF:TNIDT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="MTFCC:FULLNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=C3/ {display_level=0; next} # water /^MTFCC=H20/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} # buildings /^MTFCC=K/ {display_level=128; next} # PLCC /^MTFCC=L/ {display_level=1024; next} # legal / statistical boundary /^MTFCC=P0001/ {display_level=0; next} # water shoreline /^MTFCC=P0002/ {display_level=1240; color=9; fill_color=9; next} # water intermittent shoreline /^MTFCC=P0003/ {display_level=1240; color=9; fill_color=9; next} # non-visible boundary /^MTFCC=P0004/ {display_level=0; next} # railroad /^MTFCC=R/ {lanes=2; color=8; pattern=1; display_level=128; next} # Limited access road /^MTFCC=S11/ {lanes=4; color=11; display_level=1024; label_level=512; font_size=3; next} # secondary road /^MTFCC=S12/ {display_level=512; lanes=3; color=8; label_level=256; font_size=2; next} # local road /^MTFCC=S14/ {display_level=128; label_level=16; color=48; lanes=1; next} # 4WD off-road trail /^MTFCC=S15/ {lanes=1; color=4; display_level=64; font_size=1; next} # Freeway access / service drive /^MTFCC=S16/ {color=11; display_level=64; next} # walkway / stairway /^MTFCC=S17[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} # alley / private road /^MTFCC=S17[34]/ {lanes=1; color=40; pattern=2; display_level=64; next} # bike / bridle path /^MTFCC=S18/ {lanes=1; color=40; pattern=2; display_level=64; next} # road median /^MTFCC=S20/ {lanes=1; color=40; pattern=2; display_level=64; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/featnames.dbfawk000066400000000000000000000076021501463444000207430ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for FEATNAMES # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="TLID:FULLNAME:NAME:PREDIRABRV:PRETYPABRV:PREQUALABR:SUFDIRABRV:SUFTYPABRV:SUFQUALABR:PREDIR:PRETYP:PREQUAL:SUFDIR:SUFTYP:SUFQUAL:LINEARID:MTFCC:PAFLAG"; dbfinfo="TLID:FULLNAME:NAME:PREDIRABRV:PRETYPABRV:PREQUALABR:SUFDIRABRV:SUFTYPABRV:SUFQUALABR:PREDIR:PRETYP:PREQUAL:SUFDIR:SUFTYP:SUFQUAL:LINEARID:MTFCC:PAFLAG"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations #/^MTFCC=C3/ {display_level=0; next} # water /^MTFCC=H20/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} # buildings #/^MTFCC=K/ {display_level=256; color=25; next} # PLCC /^MTFCC=L/ {display_level=0; next} # legal / statistical boundary /^MTFCC=P0001/ {display_level=0; next} # water shoreline /^MTFCC=P0002/ {display_level=1240; color=9; fill_color=9; next} # water intermittent shoreline /^MTFCC=P0003/ {display_level=1240; color=9; fill_color=9; next} # non-visible boundary /^MTFCC=P0004/ {display_level=0; next} # railroad /^MTFCC=R/ {lanes=2; color=8; pattern=1; display_level=128; next} # Limited access road /^MTFCC=S11/ {display_level=2048; lanes=4; color=11; label_level=512; font_size=3; next} # secondary road /^MTFCC=S12/ {display_level=128; lanes=3; color=8; label_level=128; font_size=2; next} # local road /^MTFCC=S14/ {display_level=128; label_level=16; color=20; lanes=1; next} # 4WD off-road trail /^MTFCC=S15/ {lanes=1; color=69; display_level=64; font_size=1; next} # Freeway access / service drive /^MTFCC=S16/ {color=11; display_level=64; next} # walkway / stairway /^MTFCC=S17[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} # alley / private road /^MTFCC=S17[34]/ {lanes=1; color=40; pattern=2; display_level=64; next} # bike / bridle path /^MTFCC=S18/ {lanes=1; color=40; pattern=2; display_level=64; next} # road median /^MTFCC=S20/ {lanes=1; color=40; pattern=2; display_level=64; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/gfe_coastal_waters.dbfawk000066400000000000000000000040231501463444000226260ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canonical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DIST_NO:PT_1_NAME:PT_2_NAME:PART_STATE:DISP_ORDER:AREA_TYPE:NARR_FLAG:LEVEL:AAC_PARENT:RPT_SEAS:RPT_SWELL:ELEVATION"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/gfe_coastal_waters_warnings.dbfawk000066400000000000000000000040311501463444000245350ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:SEG:AAC_MW:PT_1_NAME:PT_2_NAME:PART_STATE:DISP_ORDER:AREA_TYPE:NARR_FLAG:LEVEL:AAC_PARENT:RPT_SEAS:RPT_SWELL:DESC_TEXT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/gfe_fire_weather.dbfawk000066400000000000000000000040141501463444000222570ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:SOURCE:FIREBAN_TH:BAN_FLAG:DISP_ORDER:NARR_FLAG:LEVEL:USE_GFDR:USE_FFDR:USE_SFDR:USE_HI_FDR:PW_AACS"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/gfe_metro_areas.dbfawk000066400000000000000000000037611501463444000221240ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DISP_ORDER:NARR_FLAG:AAC_PARENT:SUB_FLAG:DESCRIPTN:SURF_FLAG:ROAD_FLAG"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/gfe_public_weather.dbfawk000066400000000000000000000040041501463444000226070ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DISP_ORDER:NARR_FLAG:LEVEL:USE_GFDR:USE_FFDR:USE_SFDR:USE_HI_FDR:ALP_FLAG:SURF_FLAG:MW_AACS"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/gps_wpt.dbfawk000066400000000000000000000012531501463444000204570ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map dbf data that accompanies a shapefile created # by the "Fetch GPS Waypoints" option of Xastir. # # It simply attaches the name of the waypoint to the displayed waypoint. # BEGIN{ # identifies the signature we want to recognize dbfinfo="name:commt:date"; # and the fields we actually care about dbffields="name"; } # Executed at beginning of each record, reset defaults BEGIN_RECORD {key=""; lanes=1; color=3; name=""; filled=0; pattern=0; display_level=256; label_level=128; label_color=8; symbol="/. "} # Find the name, make sure it gets displayed along with the data. /^name=(.*)$/ {name="$1";} Xastir-Release-2.2.2/config/language-Dutch.sys000066400000000000000000001173571501463444000212210ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This is the Dutch Language file used for all the prompts in xastir # # Creator : Henk de Groot # Maintained by : The Xastir Group # Last Modified : Apr 28 2001, Henk de Groot # Modified 1.0.3 : Oct 19 2001, Han Sytsma # Modified 1.0.4 : Nov 22 2001, Henk de Groot # Modified 1.0.4 : Nov 25 2001, Henk de Groot # Modified 1.0.6 : Dec 16 2001, Henk de Groot # Modified 1.0.7 : Aug 27 2002, Han Sytsma # Modified 1.1.4 : Apr 15 2003, Han Sytsma # Modified 1.1.4 : May 20 2003, Han Sytsma # Modified 1.3.2 : Jun 08 2004, Han Sytsma # Modified 1.3.x : Sept 1 2004, Han Sytsma / # Henk de Groot # Modified 1.4.2 : Feb 14 2005, Han Sytsma # Modified 1.7.0 : Oct 15 2005, Han Sytsma # Modified 1.8.0 : Jan 9 2006, Han Sytsma # # comment lines with pound signs in front are ignored # File format as follows: # Id (10 chars alpha numeric)|(String associated with id)|QuickKeys|#comment # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|Bestand|B| MENUTB0002|Schermen|S| MENUTB0004|Kaarten|K| MENUTB0005|Beeld|l| MENUTB0006|Berichten|r| MENUTB0010|Interfaces|f| MENUTB0009|Help|H| # # Menu "File" PULDNFI001|Instelling|I| PULDNFI002|Open Log Bestand|O| PULDNFI003|Test|| PULDNFI004|Sluiten|S| PULDNFI007|Verander Debug Level|D| PULDNFI010|TNC Loggen|T| PULDNFI011|Net Loggen|N| PULDNFI012|IGate Loggen|G| PULDNFI013|WX Loggen|W| PULDNFI014|Activeer PNG Snapshots|A| PULDNFI015|Kaart Afdrukken|K| PULDNFI016|KML Snapshots|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Ontvangen Packets|P| PULDNVI003|Mobiele Stations|M| PULDNVI004|Alle Stations|A| PULDNVI009|Lokale Stations|S| PULDNVI012|Laatste Stations|L| PULDNVI005|Weerstations|W| PULDNVI008|Eigen Weer Gegevens|E| PULDNVI007|Weer Waarschuwingen|W| PULDNVI011|Berichten Verkeer|V| PULDNVI013|Tijdsduur Aktief|U| PULDNVI014|Tijdsduur Programma Beschikbaar|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistieken|| # # Menu "Configure" PULDNCF004|Station|t| PULDNCF001|Standaard|S| PULDNCF003|Tijdsinstelling|m| PULDNCF002|Coordinaten Aanduiding|C| PULDNCF006|Audio Alarm|A| PULDNCF007|Spraak|p| PULDNCF008|Instellingen nu bewaren!|I| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Kaart Kiezer|K| PULDNMP012|Ga naar Lokatie|G| PULDNMP014|Lokaliseer Kaart Functie|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Zet alle kaarten uit|Z| PULDNMP002|Automatische Kaart Keuze|A| PULDNMP003|Kaart Graadlijnen|G| PULDNMP004|Kaart Niveaus|| PULDNMP010|Kaartlabels|| PULDNMP009|Kleur Gevulde Gebieden|K| PULDNMP007|Kaart WX Waarschuwing|W| PULDNMP005|Achtergrond Kleur|c| PULDNMP006|Station Tekst Stijl|S| PULDNMP026|Icon Omranding Stijl|O| PULDNMP011|Muis Menu|M| PULDNMP008|Kaart Intensiteit|I| PULDNMP021|Automatische Kaartkeuze - Zet Raster Kaarten Uit|| PULDNMP022|Indexeer Kaarten bij het Starten|| PULDNMP023|Index: Voeg nieuwe kaarten toe|n| PULDNMP024|Index: Herindexeer ALLE kaarten|H| PULDNMP025|Fonts|| PULDNMP015|Xfont selectie|| PULDNMP027|Download Kaarten opnieuw (niet uit cache)|| PULDNMP028|Leeg de gehele kaarten cache!|| PULDNMP029|Zoek Adres|| PULDNMP030|Configureer USGS DRG|| PULDNMP031|Zet kaart begrenzing aan|| MPUPTGR017|Internet Kaarten Timeout (sec)|| # # PopUp "Configureer USGS DRG" MPUPDRG001|Selecteer weer te geven items:|| MPUPDRG002|Kleur onderliggende kaart (XOR)|| MPUPDRG003|Zwart|| MPUPDRG004|Wit|| MPUPDRG005|Blauw|| MPUPDRG006|Rood|| MPUPDRG007|Bruin|| MPUPDRG008|Groen|| MPUPDRG009|Paars|| MPUPDRG010|Geel|| MPUPDRG011|Licht Blauw|| MPUPDRG012|Licht Rood|| MPUPDRG013|Licht Paars|| MPUPDRG014|Licht Grijs|| MPUPDRG015|Licht Bruin|| # # PopUp "Kaart kiezer" WPUPMCP001|Kaart Kiezer|| PULDNMMC01|Wis|N| PULDNMMC02|Vector|V| PULDNMMC03|250k Topogr.|2| PULDNMMC04|100k Topogr.|1| PULDNMMC05|24k Topogr.|4| PULDNMMC06|Vouw Dirs Uit||| PULDNMMC07|Dirs/Kaarten Geselecteerd:|| PULDNMMC08|Maak Directories leeg|C| PULDNMMC09|Selecteer Alles|S| # # PullDown "Map Background Color" PULDNMBC01|Grijs|| PULDNMBC02|Mistig Roze|| PULDNMBC03|Marine Blauw|| PULDNMBC04|Staal Blauw|| PULDNMBC05|Zee Groen|| PULDNMBC06|Pastel Groen|| PULDNMBC07|Pastel Geel|| PULDNMBC08|Goud Geel|| PULDNMBC09|Roze Bruin|| PULDNMBC10|Vuur Rood|| PULDNMBC11|Wit|| PULDNMBC12|Zwart|| # # PullDown "Station text Style" PULDNMSL01|Zwarte Rand|| PULDNMSL02|Zwarte Schaduw en gevulde achtergrond|| PULDNMSL03|Tekst op Zwarte achtergond|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|Geen Omranding|G| PULDNMIO02|Zwarte Omranding|Z| PULDNMIO03|Grijze Omranding|G| PULDNMIO04|Witte Omranding|W| # # Switches PULDNOT001|Aan|| PULDNOT002|Uit|| PULDNOT003|Kort|| # # Menu "Display" PULDNDP014|Zoek station|Z| PULDNDP001|Volg station|V| PULDNDP022|Spoor downloaden|p| PULDNDP032|Filter gegevens|| PULDNDP040|Deselecteer alles|| PULDNDP041|Selecteer mijn|| PULDNDP042|Selecteer TNC|| PULDNDP027|- Selecteer directe stations|| PULDNDP043|- Selecteer via digi|| PULDNDP034|Selecteer net|| PULDNDP019|Geef verlopen gegevens weer|| PULDNDP044|Selecteer stations|| PULDNDP028|- Selecteer vaste stations|| PULDNDP029|- Selecteer bewegende stations|| PULDNDP030|- Selecteer weer stations|| PULDNDP053|- Selecteer CWOP WX stations|| PULDNDP045|Selecteer Objecten/Items|| PULDNDP026|- Selecteer weer Objecten/Items|| PULDNDP039|- Selecteer water Hoogte Objecten/Items|| PULDNDP031|- Selecteer andere Objecten/Items|| PULDNDP057|- Selecteer Aircraft Object/Artikelen|| PULDNDP058|- Selecteer Vessel Objecten/Artikelen|| PULDNDP033|Filter weergave|| PULDNDP010|Roepnaam|R| PULDNDP012|Symbolen|y| PULDNDP011|- Draai symbolen|D| PULDNDP007|Station spoor|t| PULDNDP003|Koers|K| PULDNDP004|Snelheid|S| PULDNDP017|- Geef snelheid kort traject weer|| PULDNDP002|Hoogte|H| PULDNDP009|Weer informatie|W| PULDNDP046|- Weer tekst|| PULDNDP018|-- Geef alleen temperatuur weer|| PULDNDP047|- Wind indicator|| PULDNDP054|Geef Aloha cirkels weer|| PULDNDP013|Zet stations nadering aan|| PULDNDP008|Stations Vermogen/Winst|V| PULDNDP021|- Activeer standaard vermogen/winst|| PULDNDP020|- Activeer mobiel vermogen/winst|| PULDNDP023|Geef DF cirkels weer|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activeer berekening op geschatte waarden|| PULDNDP036|- Geef boogsegment weer|| PULDNDP037|- Geef richting weer|| PULDNDP038|- Geef symbool weer|| PULDNDP005|Afst/koers|A| PULDNDP024|Geeft tijd laatste rapport|| PULDNDP015|Wis alle stations|W| PULDNDP016|Wis Alle sporen|S| PULDNDP025|Wis Object/Item geschiedenis|| PULDNDP048|Herlaad Object/Item geschiedenis|| PULDNDP049|Wis alle gemarkeerde bijnamen|| PULDNDP050|Wis gemarkeerde bijnamen geschiedenis|| PULDNDP051|Selecteer alleen gemarkeerde bijnamen|| PULDNDP052|- Label route punten|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Units PULDNUT001|Engels|| PULDNUT002|Metrisch|| # # Menu "Messages" PULDNMG001|Zend Bericht Naar|Z| PULDNMG002|Open Groeps Bericht|O| PULDNMG003|Wis alle uitgaande berichten|W| PULDQUS001|Algemene Stations Aanvraag|G| PULDQUS002|IGate Stations Aanvraag|I| PULDQUS003|WX Stations Aanvraag|t| PULDNMG004|Automatisch Antwoord Bericht|A| PULDNMG005|Automatisch Beantwoorden|B| PULDNMG006|Sateliet Bevestigings Mode|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface besturing|| PULDNTNT03|Zet verzenden van alle data uit|| PULDNTNT05|Zet verzenden positie uit|| PULDNTNT06|Zet verzenden van objecten uit|| PULDNTNT11|Zet server poort aan|| PULDNTNT01|Zend nu!|Z| PULDNTNT07|Volg GPS spoor|F| PULDNTNT08|Volg GPS routes|R| PULDNTNT09|Volg GPS routepunten|W| PULDNTNT10|Laad Garmin RINO routepunten|G| # # Menu "Help" PULDNHEL01|Informatie|A| PULDNHEL02|Help Onderwerpen|I| PULDNHEL03|NOOD BAKEN BAKEN MODUS INSCHAKELEN|E| PULDNHEL04|!!! NOOD BAKEN MODUS !!!|| PULDNHEL05|Over Xastir|| # # Mouse Menu Popup POPUPMA001|Opties|| POPUPMA00c|Centreer|C| POPUPMA015|Stations informatie|S| POPUPMA002|Zoom in|i| POPUPMA003|Zoom uit|u| POPUPMA004|Zoom niveau|n| POPUPMA005|Niveau 1|1| POPUPMA006|Niveau 16|6| POPUPMA007|Niveau 64|4| POPUPMA008|Niveau 256|2| POPUPMA009|Niveau 1024|0| POPUPMA010|Niveau 8192|8| POPUPMA017|Hele Wereld|H| POPUPMA016|Vorige pos/zoom|p| POPUPMA018|Plaats een Object|O| POPUPMA019|Verander een Object|V| POPUPMA025|Verplaats mijn station naar dit punt|H| POPUPMA011|Schuif Omhoog|c| POPUPMA012|Schuif Omlaag|h| POPUPMA013|Schuif naar Links|l| POPUPMA014|Schuif naar Rechts|r| POPUPMA020|Afstand meten|| POPUPMA021|Verplaatsen|| POPUPMA022|Volg me|| POPUPMA023|Functie toetsen actief!|| POPUPMA024|Schakel CapsLock/NumLock/ScrollLock/andere Toetsen UIT|| POPUPMA026|Centreer & zoom|| POPUPMA027|Breedtegraden|| POPUPMA028| Lengtegraden|| POPUPMA029|Teken CAD objecten|| POPUPMA030|Draw|| POPUPMA031|Sluit polygoon|| POPUPMA032|Wis CAD polygonen|| POPUPMA033|**NIET GEBRUIKT**|| POPUPMA034|Handmatig Zoom Niveau|| POPUPMA035|10% uit|| POPUPMA036|10% in|| POPUPMA037|Gebied|| POPUPMA038|Vierkant|| POPUPMA039|Vierkante voet|| POPUPMA040|Vierkante meters|| POPUPMA041|Richting|| POPUPMA042|Graden|| POPUPMA043|Pas meerduidige positie aan||# origineel ambigious mag ook meervoudige zijn? POPUPMA044|Positie meerduidigheid is aan, uw nieuwe positie kan verspringen.||# idem POPUPMA045|Voor gedefinierde objecten|| POPUPMA046|CAD polygonen|| POPUPMA047|Zet CAD objecten aan|| POPUPMA048|Zet CAD labels aan|| POPUPMA049|Zet CAD opemerkingen aan|| POPUPMA050|Zet CAD waarschijnlijkheid aan|| POPUPMA051|Zet CAD omgevingsgrootte aan|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stations|| BBARSTA000|%-9s Nieuw Object!|| BBARSTA001|%-9s Nieuw station!|| BBARSTA002|%-9s||# Nieuwe Gegevens (geeft alleen roepnaam weer) BBARSTA003|Kaarten Laden|| BBARSTA004|Kaarten Geladen|| BBARSTA005|Kaart Graadlijnen Aan|| BBARSTA006|Kaart Graadlijnen Uit|| BBARSTA007|Auto. Kaartkeuze is nu AAN|| BBARSTA008|Auto. Kaartkeuze is nu UIT|| BBARSTA009|Auto. Niveaukeuze is nu AAN|| BBARSTA010|Auto. Niveaukeuze is nu UIT|| BBARSTA011|Auto. Beantwoorden is UIT!|| BBARSTA012|Bestand Gereed|| BBARSTA013|GPS Poort Openen|| BBARSTA014|GPS Poort Sluiten|| BBARSTA015|Kreeg GPS RMC tekst|| BBARSTA016|Kreeg GPS GGA tekst|| BBARSTA017|Net verbinding naar host verbroken|| BBARSTA018|Verbindingstijd netwerk verstreken!|| BBARSTA019|Zoeken naar host %s|| BBARSTA020|Verbonden met %s|| BBARSTA021|Net verbinding mislukt!|| BBARSTA022|Kon socket niet binden!|| BBARSTA023|Geen IP voor host!|| BBARSTA024|Geen host gespecificeerd|| BBARSTA025|Host gevonden, Verbinding maken met %d|| BBARSTA026|Wachten op GPS gegevens via HSP..|| BBARSTA027|HSP vrijmaken, TNC gegevens ophalen..|| BBARSTA028|%s wordt geladen|| BBARSTA029|WX poort openen|| BBARSTA030|WX poort sluiten|| BBARSTA031|Zoeken naar hostnaam %d|| BBARSTA032|WX gegevens gedecodeerd|| BBARSTA033|Echo van de digipeater|| BBARSTA034|Weer waarschuwings kaarten laden|| BBARSTA035|Wachten op GPS gegevens via AUX..|| BBARSTA036|HSP vrijmaken, TNC gegevens ophalen..|| BBARSTA037|GPS tekst gedecodeerd|| BBARSTA038|Positie verandering bij mijn station|| BBARSTA039|Bezig met indexeren van: %s|| BBARSTA040|Amateur APRS(tm) station %s|| BBARSTA041|Wacht op GPS gegevens..|| BBARSTA042|Uitzenden van objecten/items|| BBARSTA043|Log bijwerken|| BBARSTA044|ALOHA afstand is %d%s|| BBARSTA045|Symbolen laden...|| BBARSTA046|Opnieuw laden van symbolen...|| BBARSTA047|Initialiseer mijn station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # PopUp "View - Incoming Packet Data" WPUPDPD001|Ontvangen packets bekijken|| WPUPDPD002|Alleen TNC gegevens|| WPUPDPD003|Alleen Net gegevens|| WPUPDPD004|TNC en Net gegevens|| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # PopUp "View - Find Station" WPUPLSP001|Lokaliseer station|| WPUPLSP002|Lokaliseer roepnaam|| WPUPLSP003|Hoofdlettergevoelig|| WPUPLSP004|Zoek exact|| WPUPLSP005|Lokaliseer nu!|| WPUPLSP006|Spoed lokaliseren!|| WPUPLSP007|FCC/RAC lokalisatie|| # # PopUp "Configure - Defaults" WPUPCFD001|Standaardinstellingen aanpassen|| WPUPCFD002|Na hoeveel tijd moet een station als oud beschouwd worden?|| WPUPCFD003|15 Minuten|| WPUPCFD004|30 Minuten|| WPUPCFD005|45 Minuten|| WPUPCFD006|1 Uur|| WPUPCFD007|90 Minuten|| WPUPCFD008|2 Uur|| WPUPCFD009|Na hoeveel tijd moet een station van het scherm verwijderd worden?|| WPUPCFD010|6 Uur|| WPUPCFD011|12 Uur|| WPUPCFD012|1 Dag|| WPUPCFD013|2 Dagen|| WPUPCFD014|1 Week|| WPUPCFD015|Station Zend Opties|| WPUPCFD016|Vast Station|| WPUPCFD017|Mobiel Station m/lokale tijd|| WPUPCFD018|Mobiel Station m/Zulu datum-tijd|| WPUPCFD019|Mobiel Station m/Zulu tijd-secondes|| WPUPCFD021|Stations Positie m/weer|| WPUPCFD022|Stations Positie, Zulu datum-tijd en weer|| WPUPCFD023|Verzend ruwe WX gegevens?|| WPUPCFD024|Comprimeer Object/Item gegevens bij uitzenden?|| WPUPCFD025|Activeer alternatief net?|| WPUPCFD026|Met welk interval positie gegevens verzenden?|| WPUPCFD027|Nieuwe berichten weergeven|| WPUPCFD028|Waarschuw als speciale functie toetsen aanstaan|| WPUPCFD029|Geef bulletins zonder afstand weer|| WPUPCFD030|Zet positie duplicaat controle uit|| WPUPCFD031|Laad voor gedefinierde objecten uit bestand|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configureer tijdsinstelling||| WPUPCFTM02|Interval verzenden positie (min)|| WPUPCFTM03|Tijd tot vervagen station (min)|| WPUPCFTM04|Max interval verzenden Object/Item (min)|| WPUPCFTM05|Tijd tot verdwijnen van kaart (uren)|| WPUPCFTM06|GPS status controle interval (sec)|| WPUPCFTM07|Tijd tot wissen station (dagen)|| WPUPCFTM08|Timeout berekening geschatte waarden (min)|| WPUPCFTM09|Seriele Inter-Char vertraging (ms)|| WPUPCFTM10|Nieuwe volg tijd (min)|| WPUPCFTM11|Nieuw volg Interval (graden)|| WPUPCFTM12|RINO -> Objecten Interval (min), 0 = Uitgeschakeld|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configureer coordinaten stelsel|| WPUPCFC002|Selecteer coordinaten weergave|| WPUPCFC003|dd.dddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM w/speciale zones|| # # PopUp "Configure GPS" WPUPCFG001|GPS Instelling|| WPUPCFG003|Eigen GPS poort|| WPUPCFG002|Gebruik GPS positie?|| WPUPCFG004|GPS opties|| WPUPCFG005|Losse GPS|| WPUPCFG006|Via TNC verbonden GPS (HSP Kabel)|| WPUPCFG007|Via TNC verbonden GPS met gebruik van CTL-E|| WPUPCFG008|GPS tijd (Lees elke)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuut|| WPUPCFG013|2 minuten|| WPUPCFG014|5 minuten|| WPUPCFG015|10 minuten|| WPUPCFG016|Via netwerk verbonden GPS|| WPUPCFG017|GPSD Host|| WPUPCFG018|GPSD Poort|| WPUPCFG019|Netwerk GPS via GPSD|| WPUPCFG020|Opnieuw verbinden na een fout?|| WPUPCFG021|Via netwerk verbonden WX|| WPUPCFG022|WX Host|| WPUPCFG023|WX Poort|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|TNC instelling|| WPUPCFT002|Gebruik TNC?|| WPUPCFT003|TNC poort|| WPUPCFT004|Poort instelling|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto paden|| WPUPCFT012|Pad 1: %s via || WPUPCFT013|Pad 2: %s via || WPUPCFT014|Pad 3: %s via || WPUPCFT015|Poort stijl|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|TNC instelling m/HSP GPS|| WPUPCFT024|Data type|| WPUPCFT025|Auto detectie|| WPUPCFT026|Binair type|| WPUPCFT027|ASCII type|| WPUPCFT028|TNC instelling m/AUX GPS|| WPUPCFT029|TNC instelling m/ONGELDIG ENUM: %d|| WPUPCFT030|Configureer KISS TNC|| WPUPCFT031|TNC configuratie bestanden|| WPUPCFT032|Bestandsnaam activeren TNC|| WPUPCFT033|Bestandsnaam deactiveren TNC|| WPUPCFT034|KISS parameters|| WPUPCFT035|TXDelay (10 ms stappen)|| WPUPCFT036|Persistence (0 tot 255)|| WPUPCFT037|SlotTime (10 ms stappen)|| WPUPCFT038|TxTail (10 ms stappen)|| WPUPCFT039|Vol Duplex|| WPUPCFT040|Configureer Multi-Port KISS TNC|| WPUPCFT041|Radio poort|| WPUPCFT042|Twijfelachtige UNPROTO route!|| WPUPCFT043|Gebruik liever een kortere route zoals WIDE2-2 of WIDE1-1,WIDE2-2|| WPUPCFT044|Twijfelachtige IGATE route!|| WPUPCFT045|Uitzenden met twijfelachtige UNPROTO route!|| WPUPCFT046|Uitzenden met twijfelachtige IGATE route!|| WPUPCFT047|Initialisser KISS-modus bij opstarten|| # # PopUp "Configure WX Port" WPUPCFWX01|WX Poort instelling|| WPUPCFWX02|Weerstation apparaat|| WPUPCFWX03|Regenmeter correctie (globale instelling)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Geen correctie|| # # PopUp "Configure - Station" WPUPCFS001|Stations Instelling|| WPUPCFS002|Roepnaam|| WPUPCFS003|Breedte graden|| WPUPCFS004|gra|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Lengte graden|| WPUPCFS008|(E/W)|| WPUPCFS009|Station Symbool|| WPUPCFS010|Groep/overlay|| WPUPCFS011|Symbool|| WPUPCFS028|Selecteer|| WPUPCFS012|Vermogenswinst|| WPUPCFS013|PHG uitschakelen|| WPUPCFS014|Antenne winst|| WPUPCFS015|Antenne versterking|| WPUPCFS016|Omni|| WPUPCFS017|Commentaar:|| WPUPCFS018|Positie onzekerheid|| WPUPCFS019|Geen|| WPUPCFS020|.11 mijl omtrek|| WPUPCFS021|1.15 mijl omtrek|| WPUPCFS022|11.51 mijl omtrek|| WPUPCFS023|69.09 mijl omtrek|| WPUPCFS024|.18 kilometer omtrek|| WPUPCFS025|1.85 kilometer omtrek|| WPUPCFS026|18.53 kilometer omtrek|| WPUPCFS027|111.19 kilometer omtrek|| WPUPCFS029|Verstuur gecomprimeerde positie|C| # # PopUp "Object/Item" POPUPOB001|Object/Item|| POPUPOB002|Naam|| POPUPOB003|Plaats object|| POPUPOB004|Verwijder object|| POPUPOB005|Verander object|| POPUPOB006|Maak een nieuw object|| POPUPOB007|Oppervlakte object|| POPUPOB008|Activeer oppervlakte object|| POPUPOB009|Heldere kleur|| POPUPOB010|Kleur-Vulling|| POPUPOB011|Cirkel|| POPUPOB012|Rechtse lijn '/'|| POPUPOB013|Linkse lijn '\'|| POPUPOB014|Driehoek|| POPUPOB015|Rechthoek|| POPUPOB016|Zwart|| POPUPOB017|Blauw|| POPUPOB018|Groen|| POPUPOB019|Cyaan|| POPUPOB020|Rood|| POPUPOB021|Violet|| POPUPOB022|Geel|| POPUPOB023|Grijs|| POPUPOB024|Offset omhoog:|| POPUPOB025|Offset links (behalve '/'):|| POPUPOB026|Doorgang:|| POPUPOB027|Algemene Opties|| POPUPOB028|Lokatie|| POPUPOB029|Activeer markering|| POPUPOB030|Gegevens:|| POPUPOB031|Gemarkeerd object|| POPUPOB032|Activeer compressie|| POPUPOB033|Verwijder item|| POPUPOB034|Wijzig item|| POPUPOB035|Hoogte (voet):|| POPUPOB036|Snelheid (knopen):|| POPUPOB037|Richting:|| POPUPOB038|DF object|| POPUPOB039|Signaal - Hoogte(HAAT) - Versterking - Richting|| POPUPOB040|Straal breedte - Richting|| POPUPOB041|Rondstraler|| POPUPOB042|Richtantenne|| POPUPOB043|Onbruikbaar|| POPUPOB044|Neem object over|| POPUPOB045|Neem item over|| POPUPOB046|DF richting:|| POPUPOB047|Waarschijnlijkheids ringen|| POPUPOB048|Kaartbeeld Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Internet Instelling|| WPUPCFI002|Host || WPUPCFI003|Poort || WPUPCFI004|(Alternatieve hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Poort1|| WPUPCFI007|Host2|| WPUPCFI008|Poort2|| WPUPCFI009|Wachtwoord|| WPUPCFI010|(Bij Geen Blanco Laten)|| WPUPCFI011|Verbinding herstellen bij NET fout?|| WPUPCFI012|Laten Werken als I-Gate?|| WPUPCFI013|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFI014|I-Gate transacties loggen?||| WPUPCFI015|Filter parameters|| # # PopUp "Configure Database" WPUPCFID01|Database Instelling (TBD)|| WPUPCFID02|Host || WPUPCFID03|Poort || WPUPCFID04|(Alternatieve hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Poort1|| WPUPCFID07|Host2|| WPUPCFID08|Poort2|| WPUPCFID09|Wachtwoord|| WPUPCFID10|(Bij Geen Blanco Laten)|| WPUPCFID11|Verbinding herstellen bij NET fout?|| WPUPCFID12|Laten werken als I-Gate?|| WPUPCFID13|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFID14|I-Gate transacties loggen?||| WPUPCFID15|Filter parameters|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configureer AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Poort || WPUPCFIA04|(Alternatieve hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Poort1|| WPUPCFIA07|Host2|| WPUPCFIA08|Poort2|| WPUPCFIA09|Wachtwoord|| WPUPCFIA10|(Bij geen blanco laten)|| WPUPCFIA11|Verbinding herstellen bij NET fout?|| WPUPCFIA12|Laten werken als I-Gate?|| WPUPCFIA13|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFIA14|I-Gate transacties loggen?|| WPUPCFIA15|Zend op radio poort|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Audio alarm instellen|| WPUPCFA002|Audio afspeel commando|| WPUPCFA003|Alarm bij|| WPUPCFA004|Audio bestand om af te spelen|| WPUPCFA005|Nieuw Station|| WPUPCFA006|Nieuw Bericht|| WPUPCFA007|Nadering|| WPUPCFA008|Band opening|| WPUPCFA009|Minimale afstand|| WPUPCFA010|Maximale afstand|| WPUPCFA011|Weer waarschuwing|| # # PopUp "Configure Speech" WPUPCFSP01|Spraak instellen|| WPUPCFSP02|Uitvoer spraak bij:|| WPUPCFSP03|Nieuw station|| WPUPCFSP04|Waarschuwing nieuw bericht|| WPUPCFSP05|Nieuwe bericht inhoud|| WPUPCFSP06|Naderings waarschuwing|| WPUPCFSP07|Band opening|| WPUPCFSP08|Nieuwe weer waarschuwing|| WPUPCFSP09|Naderings waarschuwing van gevolgd station|| # # PopUp "Track Station" WPUPTSP001|Volg station|| WPUPTSP002|Volg roepnaam|| WPUPTSP003|Hoofdlettergevoelig|| WPUPTSP004|Exact dit station|| WPUPTSP005|Volg nu!|| WPUPTSP006|Stop met volgen|| WPUPTSP007|Download spoor|| WPUPTSP008|Roepnaam|| WPUPTSP009|Begin volgen (uren geleden)|| WPUPTSP010|Volgduur (uren)|| # # PopUp "Messages" WPUPMSB001|Stuur bericht, venster %d|| WPUPMSB002|Stuur groeps bericht, venster %d|| WPUPMSB003|Stations roepnaam:|| WPUPMSB004|Groeps roepnaam:|| WPUPMSB005|Nieuwe/Refresh roepnaam|| WPUPMSB006|Nieuwe groep|| WPUPMSB007|Wis bericht geschiedenis|| WPUPMSB008|Bericht:|| WPUPMSB009|Stuur nu!|| WPUPMSB010|Pad:|| WPUPMSB011|Breek alle openstaande berichten af|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Zend uit|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*AFGEBROKEN*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # PopUp "Auto Reply" WPUPARM001|Automatich antwoord bericht|| WPUPARM002|Antwoord:|| # # PopUp "Help Index" WPUPHPI001|Help inhoud|| WPUPHPI002|Bekijken|| # # PopUp "Station Info" WPUPSTI000|Object van: %s|| WPUPSTI001|Stations informatie|| WPUPSTI002|Stuur bericht|| WPUPSTI003|Doorzoek FCC databank|| WPUPSTI004|Doorzoek RAC databank|| WPUPSTI005|Packets ontvangen: %d Laatst Gehoord: || WPUPSTI006|Gehoord via de TNC aan device %d, || WPUPSTI007|Gehoord || WPUPSTI008|laatste via lokaal|| WPUPSTI009|laatste via TNC op device %d|| WPUPSTI010|laatste via internet op device %d|| WPUPSTI011|laatste via bestand|| WPUPSTI012|laatste via onbekend|| WPUPSTI013|, en is van positie veranderd|| WPUPSTI014|Huidig Vermogen en Winst:|| WPUPSTI016|Hoogte: %.0f%s || WPUPSTI017|Richting: %s || WPUPSTI018|Snelheid: %.1fkm/h|| WPUPSTI019|Snelheid: %.1fmph|| WPUPSTI020|%0.1f Mijl|| WPUPSTI021|%0.1f km|| WPUPSTI022|Afstand vanaf mijn station %s, Koers vanaf mijn station %s|| WPUPSTI023|Laatste positie || WPUPSTI024|Weer Gegevens %c:%s|| WPUPSTI025|Wind Richting: %s Snelheid: %03d km/h|| WPUPSTI026|Wind Richting: %s Snelheid: %s mph|| WPUPSTI027| Piek: %03d km/h|| WPUPSTI028| Piek: %s mph|| WPUPSTI029|Temperatuur: %02.1fC || WPUPSTI030|Temperatuur: %sF || WPUPSTI031|Vochigheid: %s%% || WPUPSTI032|Gevoels temperatuur: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Sneeuw: %0.1f (cm/24h)|| WPUPSTI035|Sneeuw: %0.0f (inch/24h)|| WPUPSTI036|Regen: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (inch/h) || WPUPSTI039|%0.2f (mm/dag) || WPUPSTI040|%0.2f (inch/dag) || WPUPSTI041|%0.2f (mm/sinds middernacht)|| WPUPSTI042|%0.2f (inch/sinds middernacht)|| WPUPSTI043|Data pad: %s|| WPUPSTI044|Commentaar %02d/%02d %02d:%02d : %s|| WPUPSTI045|Wis spoor|| WPUPSTI046|Totaal regen: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (inch)|| WPUPSTI049|Vraag trace|| WPUPSTI050|Vraag uitstaande berichten|| WPUPSTI051|Vraag direkte stations|| WPUPSTI052|Vraag versie|| WPUPSTI053|Verander object|| WPUPSTI054|Sla spoor op|| WPUPSTI055|Echo vanaf:|| WPUPSTI056|Zet automatisch bijwerken aan|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF richting: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Ontbrandings temp: %02.1fC || WPUPSTI061|Ontbrandings temp: %sF || WPUPSTI062|Vochtigheids gehalte in brandstof: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Vraag NWS waarschuwing|| WPUPSTI065|Gemarkeerde bijnaam: %s|| WPUPSTI066|Geef station een bijnaam|| WPUPSTI067|Huidig bereik: %d miles|| WPUPSTI068|geen|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|bereik|| WPUPSTI073|SLECHTE PHG|| WPUPSTI074|SLECHTE SHG|| WPUPSTI075|DF bereik|| WPUPSTI076|Geen signaal gedetecteerd|| WPUPSTI077|Detecteerbaar signaal (Wellicht)|| WPUPSTI078|Detecteerbaar signaal maar niet bruikbaar)|| WPUPSTI079|Zwak signaal, nauwelijks leesbaar|| WPUPSTI080|Verruist maar bruikbaar signaal|| WPUPSTI081|Enige ruis, goed bruikbaar signaal|| WPUPSTI082|Goed signaal met enig waarneembare ruis|| WPUPSTI083|Bijna ruisvrij siganal|| WPUPSTI084|Volledig ruisvrij signaal|| WPUPSTI085|Extreem sterk & volledig ruisvrij signaal|| WPUPSTI086|VERKEERDE RICHTING|| WPUPSTI087|SLECHTE NRQ|| WPUPSTI088|DF openingshoek|| WPUPSTI089|DF Lengte|| WPUPSTI090|Ongeldig|| WPUPSTI091|Verander volgspoor kleur|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA omtrek: %d %s|| WPUPALO002|Stations binnen ALOHA omtrek: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiel (bewegend): %d|| WPUPALO005| Mobiel (anders): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Vaste stations: %d|| WPUPALO008|Laatst berekening %d %s %d %s geleden.|| WPUPALO666|ALOHA omtrek nog niet berekend|| # # # FCC-RAC Call Look up STIFCC0001|FCC databank doorzoeken|| STIFCC0002|RAC databank doorzoeken|| STIFCC0003|Naam:|| STIFCC0004|Straat:|| STIFCC0005|Plaats:|| STIFCC0006|Staat:|| STIFCC0007|Postcode:|| STIFCC0008|Basis || STIFCC0009|Geavanceerd || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # # FCC-RAC Call Look up STIFCC0100|FCC index is oud, bezig met herindexeren|| STIFCC0101|Zoeken roepnaam|| STIFCC0102|Roepnaam niet gevonden!|| STIFCC0103|RAC index is oud, bezig met herindexeren|| # # # Band open message UMBNDO0001|op een afstand van|| # # Universal Options UNIOP00001|OK|| UNIOP00002|Annuleren|| UNIOP00003|Sluiten|| UNIOP00004|Mijlen|| UNIOP00005|Km|| UNIOP00006|Device|| UNIOP00007|Toevoegen|| UNIOP00008|Wissen|| UNIOP00009|Eigenschappen|| UNIOP00010|Uitzenden toestaan?|| UNIOP00011|Activeren bij opstarten?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|inch|| UNIOP00018|mm/dag|| UNIOP00019|inch/dag|| UNIOP00020|mm/uur|| UNIOP00021|inch/uur|| UNIOP00022|mm/mid|| UNIOP00023|inch/mid|| UNIOP00024|graden|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Stel de systeem klok in vanuit GPS?|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Toepassen||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Station Kiezer|| # # DISPLAY WX ALERT WPUPWXA001|Wx Waarschuwing|| WPUPWXA002|Wx Waarschuwingen lijst|| # # PopUp "Configure - Interfaces" WPUPCIF001|Geinstalleerde interfaces|| WPUPCIF002|Kies interface type|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configureer AX.25 TNC|| WPUPCAX002|AX.25 device naam|| # # Interface device names IFDNL00000|Geen|| IFDNL00001|Serieele TNC|| IFDNL00002|Serieele TNC met GPS op een HSP kabel|| IFDNL00003|Serieele GPS|| IFDNL00004|Serieele WX|| IFDNL00005|Internet server|| IFDNL00006|AX25 TNC|| IFDNL00007|Netwerk GPS (via gpsd)|| IFDNL00008|Netwerk WX|| IFDNL00009|Serieele TNC met GPS op een AUX kabel|| IFDNL00010|Serieele KISS TNC|| IFDNL00011|Database via netwerk (nog niet geimplementeerd)|| IFDNL00012|AGWPE via Netwerk|| IFDNL00013|Serieele Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s via serieel device %s %s|| IFDIN00001|%s %2d %s verbonden met %s:%d %s|| IFDIN00002|%s %2d %s gebruikt device genaamd %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006|INACTIEF || IFDIN00007| ACTIEF || IFDIN00008| FOUT || IFDIN00009|ONBEKENDE|| # # PopUp "Interface control" IFPUPCT000|Interface Besturing|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Start Alle|| IFPUPCT004|Stop Alle|| # # IGate control IGPUPCF000|IGate Opties|| IGPUPCF001|Schakel al het IGate verkeer uit|| IGPUPCF002|Sta ALLEEN RF naar Inet verkeer toe|| IGPUPCF003|Sta RF->Inet en Inet->RF verkeer toe|| IGPUPCF004|IGate -> RF Path || # # WX Station WXPUPSI000|WX station|| WXPUPSI001|WX station type|| WXPUPSI002|Huidige gegevens|| WXPUPSI003|Wind koers|| WXPUPSI004|Wind snelheid|| WXPUPSI005|Wind piek|| WXPUPSI006|Temp|| WXPUPSI007|Regen totaal|| WXPUPSI008|Regen dag totaal|| WXPUPSI009|Baro|| WXPUPSI010|Vochtigheid|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (in gegevens logmode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (in packet mode)|| WXPUPSI014|Regen huidig uur tot.|| WXPUPSI015|Regen laatste 24uur tot.|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (complete mode)|| WXPUPSI018|Dauw punt|| WXPUPSI019|Wind piek|| WXPUPSI020|Wind koude gevoel|| WXPUPSI021|Warmte index|| WXPUPSI022|3-Uur Baro|| WXPUPSI023|Max Temp.|| WXPUPSI024|Min Temp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|Alle stations|| LHPUPNI001|Mobiele stations|| LHPUPNI002|Weer stations|| LHPUPNI003|Lokale stations (via TNC)|| LHPUPNI004|Laatste stations|| LHPUPNI005|Objecten & Items|| LHPUPNI006|Eigen Objecten & Items|| LHPUPNI010|#|| LHPUPNI011|Roepnaam|| LHPUPNI012|#Comprimeer|| LHPUPNI013|Pos Tijd|| LHPUPNI014|Pad|| LHPUPNI015|PHG|| LHPUPNI016|Commentaar|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Breedte gr|| LHPUPNI104|Lengte gr|| LHPUPNI105|#Comprimeer|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Breedte/Lengte of UTM|| # # Maps WX Alert styles PULDNMAT01|Waarschuwings kaarten boven de andere|| PULDNMAT02|Waarschuwings kaarten onder de andere|| # # Error/popup messages POPEM00001|Lokaliseer fout!|| POPEM00002|Station %s is niet gevonden!|| POPEM00003|Spoor-volg fout!|| POPEM00004|Interface fout!|| POPEM00005|Ongeldige AX.25 poort naam %s|| POPEM00006|Ongeldige AX.25 poort naam %s|| POPEM00007|Ongeldige roepnaam %s|| POPEM00008|Ongeldige AX.25 doeladres roepnaam of digipeater|| POPEM00009|Kan AX.25 socket niet openen, %s|| POPEM00010|Kan AX.25 socket niet binden, %s|| POPEM00011|Kan geen verbinding met AX.25 roepnaam maken, %s|| POPEM00012|AX.25 fout bij uitvoer van UI|| POPEM00013|AX.25 probleem met axports bestand|| POPEM00014|AX.25 ongeldige poort naam %s|| POPEM00015|Fout bij het openen van interface %d hardware Fout|| POPEM00016|Fout bij het openen interface %d Time Out|| POPEM00017|Geen interfaces meer beschikbaar!|| POPEM00018|Gegevens Aanvraag - Enkele Bericht Regel|| POPEM00019|Verzenden is uit voor poort %d|| POPEM00020|Database Fout!|| POPEM00021|AX.25 ondersteunig is niet mee gecompileerd in deze Xastir Versie!|| POPEM00022|Invoer Fout!|| POPEM00023|Geen lokatie naam gegeven!|| POPEM00024|Gegeven lokatie naam is in gebruik!|| POPEM00025|Niet gevonden!|| POPEM00026|Volgen begint op het moment van verschijnen|| POPEM00027|Incorrecte gegevens. Zijn er velden leeg?|| POPEM00028|Kan bestand niet openen|| POPEM00029|Gevonden!|| POPEM00030|Weer station symbool|| POPEM00031|Veranderd in WX symbool '/_', andere opties: '\_' '/W' and '\W'|| POPEM00032|Waarschuwing: gebruik nationaal weer service symbool!|| POPEM00033|Geen GPS gegevens!|| POPEM00034|Zet Mijn Positie TX uit totdat geldige GPS gegevens beschikbaar zijn!|| POPEM00035|Waarschuwing|| POPEM00036|Let op|| POPEM00037|HSP interface aanwezig: GPS timing is verhoogd|| POPEM00038|Naam komt overeen met bestaand Object/Item/Station|| POPEM00039|Niet toegestane tekens gevonden, deze worden door punten vervangen|| POPEM00040|Handmatig ingestelde uitgaande route is verloren gegaan|| POPEM00041|Bezig met een ander bestand te bewerken. Wacht even en probeer opnieuw|| POPEM00042|Niet een eigen object! Probeer het object eerst over te nemen.|| POPEM00043|Geen Object/Item!|| POPEM00044|Opzoeken in Findu database: Mislukt|| POPEM00045|Opzoeken in Findu database: Gereed|| POPEM00046|Berkeley DB headers en gedeelde bibliotheek komen niet overeen! Kaart cache uitgeschakeld.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Kaart lokatie|| JMLPO00002|GA!|| JMLPO00003|Nieuwe lokatie naam:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Beperk reikwijdte tot (0, is geen limiet)|| BULMW00003|Verander reikwijdte|| # # All Message Traffic AMTMW00001|Alle berichten verkeer|| AMTMW00002|Beperk reikwijdte tot (0, is geen limiet)|| # # Speech Strings SPCHSTR001|kilometers|| SPCHSTR002|meters|| SPCHSTR003|mijl|| SPCHSTR004|yards|| SPCHSTR005|%s, afstand is %d %s.|| SPCHSTR006|%s, afstand is %.1f %s.|| SPCHSTR007|%s, afstand is %d %s %s %s.|| SPCHSTR008|%s, afstand is %.1f %s %s %s.|| SPCHSTR009|Nieuwe weer waarschuwing|| SPCHSTR010|Nieuwe roepnaam|| SPCHSTR011|Gehoord, D X, %s, op een afstand van %.1f %s|| # # SPCHDIRN00|ten noorden van|| SPCHDIRS00|ten zuiden van|| SPCHDIRE00|ten oosten van|| SPCHDIRW00|ten westen van|| SPCHDIRNE0|ten noordoosten van|| SPCHDIRNW0|ten noordwesten van|| SPCHDIRSE0|ten zuidoosten van|| SPCHDIRSW0|ten zuidwesten van|| # # Symbol Selection Dialog SYMSEL0001|Selecteer symbool|| SYMSEL0002|Primaire symbolen Databank|| SYMSEL0003|Secondaire symbolen Databank|| # # Print Properties Dialog PRINT0001|Print eigenschappen|| PRINT0002|Papier formaat|| PRINT0003|Draai beeld automatisch|| PRINT0004|Draai beeld 90. CCW|| PRINT0005|Pas schaal beeld automatisch aan|| PRINT0006|Schaal:|| PRINT0007|Forceer standaard witte achtergrondkleur|| PRINT0008|Print in Zwart/Wit|| PRINT0016|Inverteer kleuren|| PRINT0009|Postscript resolutie:|| PRINT0010|Voorbeeld|| PRINT0011|Print naar bestand|| PRINT0012|Bezig met printen naar bestand...|| PRINT0013|Converteren naar postscript...|| PRINT0014|Gereed met aanmaken print bestand|| PRINT0015|Printer status|| # # Print Properties Dialog PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Locate Feature Dialog FEATURE001|Naam:|| FEATURE002|Provincie:|| FEATURE003|Land:|| FEATURE004|Kaart quadrant:|| FEATURE005|Type:|| FEATURE006|GNIS Bestand:|| FEATURE007|Adres:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding Bestand|| # # Coordinate Calculator Dialog COORD001|Coordinaten berekening|| COORD002|Bereken|| COORD003|Bereken|| COORD004|Wis|| COORD005|UTM|| COORD006|Breedtegraden of|| COORD007|Lengtegraden of|| COORD008|Zone|| COORD009|UTM Oostelijk|| COORD010|UTM Noordelijk|| COORD011| Decimale graden: || COORD012| Graden/Decimale minuten: || COORD013| Graden/Minuten/Dec. seconden: || COORD014| Universal Transverse Mercator: || COORD015| Militair Referentie raster: || COORD016| Maidenhead lokatie raster: || COORD017| ** Sorry, uw invoer is niet herkend! **|| COORD018| ** Gebruik een van onderstaande invoer formaten: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|Hoge Waarde (secs):|| SMARTB003|Hoge Snelheid (mph):|| SMARTB004|Hoge Snelheid (kph):|| SMARTB005|Lage Waarde (mins):|| SMARTB006|Lage Snelheid (mph):|| SMARTB007|Lage Snelheid (kph):|| SMARTB008|Minimale Draaiing (deg):|| SMARTB009|Draai Hoek:|| SMARTB010|Wacht Tijd (secs):|| SMARTB011|Schakel SmartBeaconing in(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Stel Gamma Correctie bij|| GAMMA002|Gamma Correctie|| # # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Miniem|| MAPFONT004|Map Font Klein|| MAPFONT005|Map Font Gemiddeld|| MAPFONT006|Map Font Groot|| MAPFONT007|Map Font Enorm|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV Font ID|| # # # # Distance/Bearing on status line PULDNDB001|Afst/Richting Status|| # # # GPS Transfer Operations GPS001|GPS overdracht|| GPS002|Bestandsnaam|| GPS003|Selecteer kleur|| GPS004|Rood|| GPS005|Groen|| GPS006|Zwart|| GPS007|Wit|| GPS008|Oranje|| GPS009|Blauw|| GPS010|Geel|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Kaart eigenschappen|| MAPP002|Max Min Kaart Teken USGS Auto|| MAPP003|Zoom Zoom Laag Vulling DRG Kaart Path/Bestandsnaam|| MAPP004|Verander Laag->|| MAPP005|Vulling->|| MAPP006|Ja|| MAPP007|Nee|| MAPP008|AutoKaart->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Dag|| TIME002|Dagen|| TIME003|Uur|| TIME004|Uren|| TIME005|Minuut|| TIME006|Minuten|| TIME007|Seconde|| TIME008|Secondes|| # # # Map Caching CACHE001|Kaart in cache|| CACHE002|Kaart uit cache laden|| CACHE003|Kaart niet in cache gevonden...|| # # # Map Screen Misc RANGE001|BEREIK SCHAAL|| # # # GPS Status GPSS001|WAAS of PPS|| GPSS002|DGPS|| GPSS003|Geldig SPS|| GPSS004|Ongeldig|| GPSS005|Sats/beeld|| GPSS006|Repareer|| GPSS007|!GPS data is ouder dan 30 seconden!|| GPSS008|Simulatie|| GPSS009|Handmatig|| GPSS010|Ingeschat op|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Opmerking:|| CADPUD004|Waarschijnlijkheid (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Toon/Bewerk details|| CADPUD008|Afbreken|| CADPUD009|Wis CAD objecten?|| CADPUD010|Wis alles|| CADPUD011|Wis selectie|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/language-English.sys000066400000000000000000001102661501463444000215330ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the English Language file used for all the prompts in xastir # # Creator : Frank Giannandrea # Maintained by : The Xastir Group # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|File|F| MENUTB0002|View|V| MENUTB0004|Map|M| MENUTB0005|Station|S| MENUTB0006|Message|e| MENUTB0010|Interface|I| MENUTB0009|Help|H| # # Menu "File" PULDNFI001|Configure|C| PULDNFI002|Open Log File|O| PULDNFI003|Test|T| PULDNFI004|Exit|x| PULDNFI007|Change Debug Level|D| PULDNFI010|TNC Logging|| PULDNFI011|Net Logging|| PULDNFI012|IGate Logging|| PULDNFI013|WX Logging|| PULDNFI014|PNG Snapshots|| PULDNFI015|Print|P| PULDNFI016|KML Snapshots|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Incoming Data|I| PULDNVI003|Mobile Stations|M| PULDNVI004|All Stations|A| PULDNVI009|Local Stations|S| PULDNVI012|Last Stations|L| PULDNVI005|Weather Stations|W| PULDNVI008|Own Weather Data|D| PULDNVI007|Weather Alerts|e| PULDNVI011|Message Traffic|T| PULDNVI013|Uptime|U| PULDNVI014|Program Uptime|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Menu "Configure" PULDNCF004|Station|S| PULDNCF001|Defaults|D| PULDNCF003|Timing|T| PULDNCF002|Coordinate System|o| PULDNCF006|Audio Alarms|A| PULDNCF007|Speech|p| PULDNCF008|Save Config Now!|C| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Map Chooser|M| PULDNMP012|Map Display Bookmarks|B| PULDNMP014|Locate Map Feature|F| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Disable All Maps|| PULDNMP002|Enable Auto Maps|| PULDNMP003|Enable Map Grid|| PULDNMP004|Enable Map Levels|| PULDNMP010|Enable Map Labels|| PULDNMP009|Enable Area Color Fills|| PULDNMP007|Enable Weather Alerts|| PULDNMP005|Background Color|C| PULDNMP006|Station Text Style|T| PULDNMP026|Icon Outline Style|O| PULDNMP011|Mouse Pointer Menu|P| PULDNMP008|Map Intensity|I| PULDNMP021|Auto Map - Disable Raster Maps|| PULDNMP022|Index New Maps on Startup|| PULDNMP023|Index: Add New Maps|N| PULDNMP024|Index: Reindex ALL Maps!|R| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Find Address|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # PopUp "Map Chooser" WPUPMCP001|Map Chooser|| PULDNMMC01|Clear|C| PULDNMMC02|Vector|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Expand Dirs|| PULDNMMC07|Dirs/Maps Selected:|| PULDNMMC08|Clear Dirs|C PULDNMMC09|Select All|S| # # PullDown "Map Background Color" PULDNMBC01|Gray|| PULDNMBC02|Misty Rose|| PULDNMBC03|Navy Blue|| PULDNMBC04|Steel Blue|| PULDNMBC05|Med. Sea Green|| PULDNMBC06|Pale Green|| PULDNMBC07|Pale Goldenrod|| PULDNMBC08|Goldenrod Yellow|| PULDNMBC09|Rosy Brown|| PULDNMBC10|Fire brick Red|| PULDNMBC11|White|| PULDNMBC12|Black|| # # PullDown "Station text Style" PULDNMSL01|Black Border|B| PULDNMSL02|Black Shadow|S| PULDNMSL03|Text on Black|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|No Outline|N| PULDNMIO02|Black Outline|B| PULDNMIO03|Grey Outline|G| PULDNMIO04|White Outline|W| # # Switches PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Short|| # # Menu "Stations" PULDNDP014|Find Station|F| PULDNDP001|Track Station|T| PULDNDP022|Fetch Findu Trail|u| PULDNDP032|Filter Data|| PULDNDP040|Select None|| PULDNDP041|Select Mine|| PULDNDP042|Select TNC|| PULDNDP027|- Select Direct|| PULDNDP043|- Select Via Digi|| PULDNDP034|Select Net|| PULDNDP019|Include Expired Data|| PULDNDP044|Select Stations|| PULDNDP028|- Select Fixed Stations|| PULDNDP029|- Select Moving Stations|| PULDNDP030|- Select WX Stations|| PULDNDP053| - Select CWOP WX Stations|| PULDNDP045|Select Objects/Items|| PULDNDP026|- Select WX Objects/Items|| PULDNDP039|- Select Water Gauge Objects/Items|| PULDNDP057|- Select Aircraft Objects/Items|| PULDNDP058|- Select Vessel Objects/Items|| PULDNDP031|- Select Other Objects/Items|| PULDNDP033|Filter Display|| PULDNDP010|Display Callsign|| PULDNDP012|Display Symbol|| PULDNDP011|- Rotate Symbol|| PULDNDP007|Display Trail|| PULDNDP003|Display Course|| PULDNDP004|Display Speed|S| PULDNDP017|- Display Short Speed|| PULDNDP002|Display Altitude|| PULDNDP009|Display Weather Info|| PULDNDP046|- Display Weather Text|| PULDNDP018|-- Temperature Only|| PULDNDP047|- Display Wind Barb|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Display Position Ambiguity|| PULDNDP008|Display Power/Gain|| PULDNDP021|- Use Default Power/Gain|| PULDNDP020|- Display Mobile Power/Gain|| PULDNDP023|Display DF Attributes|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Enable Dead-Reckoning|| PULDNDP036|- Display Arc|| PULDNDP037|- Display Course|| PULDNDP038|- Display Symbol|| PULDNDP005|Display Dist/Bearing|| PULDNDP024|Display Last Report Age|| PULDNDP015|Clear All Stations!!!|A| PULDNDP016|Clear All Trails!!!|C| PULDNDP025|Clear Object/Item History|| PULDNDP048|Reload Object/Item History|| PULDNDP049|Clear All Tactical Calls|| PULDNDP050|Clear Tactical Call History|| PULDNDP051|Select Tactical Calls Only|| PULDNDP052|- Label Trailpoints|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Units PULDNUT001|Enable English Units|E| PULDNUT002|Metric|M| # # Menu "Messages" PULDNMG001|Send Message To|S| PULDNMG002|Open Group Messages|O| PULDNMG003|Clear All Outgoing Messages|C| PULDQUS001|General Stations Query|G| PULDQUS002|IGate Stations Query|I| PULDQUS003|WX Stations Query|W| PULDNMG004|Modify Auto Reply Message|A| PULDNMG005|Enable Auto Reply Message|| PULDNMG006|Satellite Ack Mode|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface Control|C| PULDNTNT03|Disable Transmit: ALL|| PULDNTNT05|Disable Transmit: My Position|| PULDNTNT06|Disable Transmit: Objects/Items|| PULDNTNT11|Enable Server Ports|P| PULDNTNT01|Transmit Now!|T| PULDNTNT07|Fetch GPS Track|F| PULDNTNT08|Fetch GPS Routes|R| PULDNTNT09|Fetch GPS Waypoints|W| PULDNTNT10|Fetch Garmin RINO Waypoints|G| # # Menu "Help" PULDNHEL01|About|A| PULDNHEL02|Help Index|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # # Mouse Menu Popup POPUPMA001|Options|| POPUPMA00c|Center|C| POPUPMA015|Station Info|S| POPUPMA002|In|I| POPUPMA003|Out|O| POPUPMA004|Zoom Level|L| POPUPMA005|Level 1|1| POPUPMA006|Level 16|6| POPUPMA007|Level 64|4| POPUPMA008|Level 256|2| POPUPMA009|Level 1024|0| POPUPMA010|Level 8192|8| POPUPMA017|Entire World|E| POPUPMA016|Last Map Pos/Zoom|P| POPUPMA018|Object/Item->Create|b| POPUPMA019|Object/Item->Modify|M| POPUPMA025|Move My Station Here|H| POPUPMA011|Pan up|u| POPUPMA012|Pan down|d| POPUPMA013|Pan left|l| POPUPMA014|Pan right|r| POPUPMA020|Measure|| POPUPMA021|Move|| POPUPMA022|TrackMe|| POPUPMA023|Modifiers Found!|| POPUPMA024|Please turn OFF CapsLock/NumLock/ScrollLock/other modifiers|| POPUPMA026|Center & Zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Draw CAD Objects|| POPUPMA030|Draw|| POPUPMA031|Close Polygon|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position ambiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stations|| BBARSTA000|%-9s New object!|| BBARSTA001|%-9s New station!|| BBARSTA002|%-9s||# new data (only display the call) BBARSTA003|Loading Maps...|| BBARSTA004|Maps Loaded|| BBARSTA005|Map Lat/Long Grid On|O| BBARSTA006|Map Lat/Long Grid Off|f| BBARSTA007|The use of Auto Maps, is now ON|| BBARSTA008|The use of Auto Maps, is now OFF|| BBARSTA009|The use of Map Levels is now ON|| BBARSTA010|The use of Map Levels is now OFF|| BBARSTA011|Auto Reply Message OFF!|| BBARSTA012|File done..|| BBARSTA013|Opening GPS Port|| BBARSTA014|Closing GPS Port|| BBARSTA015|Got GPS RMC String|| BBARSTA016|Got GPS GGA String|| BBARSTA017|Net disconnected from host|| BBARSTA018|Net connection timed out!|| BBARSTA019|Looking up host %s|| BBARSTA020|Connected to %s|| BBARSTA021|Net Connection Failed!|| BBARSTA022|Could not bind socket!|| BBARSTA023|No IP for Host!|| BBARSTA024|No Host Specified|| BBARSTA025|Host found, Connecting %d|| BBARSTA026|Waiting for GPS data via HSP..|| BBARSTA027|Clearing HSP getting TNC data..|| BBARSTA028|Loading %s|| BBARSTA029|Opening WX Port|| BBARSTA030|Closing WX Port|| BBARSTA031|Looking up hostname %d|| BBARSTA032|Decoded WX Data|| BBARSTA033|Echo from digipeater|| BBARSTA034|Loading Weather Alert Maps|| BBARSTA035|Waiting for GPS data via AUX..|| BBARSTA036|Clearing AUX getting TNC data..|| BBARSTA037|GPS Data Complete|| BBARSTA038|Position change on my station|| BBARSTA039|Indexing %s|| BBARSTA040|Amateur APRS(tm) Station %s|| BBARSTA041|Waiting for GPS data..|| BBARSTA042|Transmitting objects/items|| BBARSTA043|Logging|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # # PopUp "View - Incoming Packet Data" WPUPDPD001|Display Packet Data|| WPUPDPD002|TNC Data only|T| WPUPDPD003|Net Data only|N| WPUPDPD004|TNC and Net Data|a| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # PopUp "View - Find Station" WPUPLSP001|Locate Station|| WPUPLSP002|Locate Callsign|| WPUPLSP003|Match Case|C| WPUPLSP004|Match Exact|E| WPUPLSP005|Locate Now!|N| WPUPLSP006|Emergency Locate!|| WPUPLSP007|FCC/RAC Lookup|| # # PopUp "Configure - Defaults" WPUPCFD001|Configure Defaults|| WPUPCFD002|After what interval of time will a station be considered old?|| WPUPCFD003|15 min|1| WPUPCFD004|30 min|3| WPUPCFD005|45 min|4| WPUPCFD006|1 hr|H| WPUPCFD007|90 min|9| WPUPCFD008|2 hrs|2| WPUPCFD009|After what interval of time will a station not be displayed?|| WPUPCFD010|6 hrs|6| WPUPCFD011|12 hrs|o| WPUPCFD012|1 Day|D| WPUPCFD013|2 Days|y| WPUPCFD014|1 Week|W| WPUPCFD015|Transmit Station Option|| WPUPCFD016|Fixed Station|F| WPUPCFD017|Mobile Station w/local time|l| WPUPCFD018|Mobile Station w/Zulu date-time|Z| WPUPCFD019|Mobile Station w/Zulu time-seconds|u| WPUPCFD021|Station Position w/weather|S| WPUPCFD022|Station Position, Zulu date-time, and weather|t| WPUPCFD023|Transmit Raw WX data?|R| WPUPCFD024|Transmit compressed objects/items?|C| WPUPCFD025|Activate Alternate net?|A| WPUPCFD026|Send position reports at what intervals?|| WPUPCFD027|Pop up new bulletins|| WPUPCFD028|Warn if Modifier Keys|| WPUPCFD029|View zero-distance bulletins|| WPUPCFD030|Disable Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configure Timing|| WPUPCFTM02|Posit TX Interval (min)|| WPUPCFTM03|Station Ghosting Time (min)|| WPUPCFTM04|Object/Item Max TX Interval (min)|| WPUPCFTM05|Station Clear Time (hours)|| WPUPCFTM06|GPS Check Interval (sec)|| WPUPCFTM07|Station Delete Time (days)|| WPUPCFTM08|Dead-Reckoning Timeout (min)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|New Track Time (min)|| WPUPCFTM11|New Track Interval (degrees)|| WPUPCFTM12|RINO -> Objects Interval (min), 0 = Disabled|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configure Coordinate System|| WPUPCFC002|Select Coordinate System|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM w/special zones|| # # PopUp "Configure GPS" WPUPCFG001|Configure GPS|| WPUPCFG003|Stand alone GPS port|| WPUPCFG002|Use GPS Position?|| WPUPCFG004|GPS Options|| WPUPCFG005|Stand-alone GPS|| WPUPCFG006|TNC Connected GPS (HSP Cable)|| WPUPCFG007|TNC Connected GPS using CTL-E|| WPUPCFG008|GPS Time (Sample every)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 min|| WPUPCFG013|2 min|| WPUPCFG014|5 min|| WPUPCFG015|10 min|| WPUPCFG016|Network Connected GPS|| WPUPCFG017|GPSD Host|| WPUPCFG018|GPSD Port|| WPUPCFG019|Network GPS via GPSD|| WPUPCFG020|Reconnect on failure?|| WPUPCFG021|Network Connected WX|| WPUPCFG022|WX Host|| WPUPCFG023|WX Port|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|Configure TNC|| WPUPCFT002|Use TNC?|| WPUPCFT003|TNC Port|| WPUPCFT004|Port Settings|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto Paths|| WPUPCFT012|Path 1: %s via || WPUPCFT013|Path 2: %s via || WPUPCFT014|Path 3: %s via || WPUPCFT015|Port Style|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configure TNC w/HSP GPS|| WPUPCFT024|Data Type|| WPUPCFT025|Auto detect|| WPUPCFT026|Binary Type|| WPUPCFT027|ASCII Type|| WPUPCFT028|Configure TNC w/AUX GPS|| WPUPCFT029|Configure TNC w/INVALID ENUM: %d|| WPUPCFT030|Configure KISS TNC|| WPUPCFT031|TNC Configuration Files|| WPUPCFT032|TNC Setup Filename|| WPUPCFT033|TNC Shutdown Filename|| WPUPCFT034|KISS Parameters|| WPUPCFT035|TXDelay (10 ms units)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (10 ms units)|| WPUPCFT038|TxTail (10 ms units)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configure Multi-Port KISS TNC|| WPUPCFT041|Radio Port|| WPUPCFT042|Interface Properties: Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Interface Properties: Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # # PopUp "Configure WX Port" WPUPCFWX01|Configure WX Port|| WPUPCFWX02|Weather Station device|| WPUPCFWX03|Rain Gauge Correction (Global Setting)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|No Correction|| # # PopUp "Configure - Station" WPUPCFS001|Configure Station|| WPUPCFS002|Callsign|| WPUPCFS003|LAT|| WPUPCFS004|deg|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/W)|| WPUPCFS009|Station Symbol|| WPUPCFS010|Group/overlay|| WPUPCFS011|Symbol|| WPUPCFS028|Select|| WPUPCFS012|Power - Height (HAAT) - Gain - Directivity|| WPUPCFS013|Disable PHG|| WPUPCFS014|Antenna Height|| WPUPCFS015|Antenna Gain|| WPUPCFS016|Omni|| WPUPCFS017|Comment:|| WPUPCFS018|Position Ambiguity|| WPUPCFS019|None|| WPUPCFS020|.11 miles|| WPUPCFS021|1.15 miles|| WPUPCFS022|11.51 miles|| WPUPCFS023|69.09 miles|| WPUPCFS024|.18 kilometres|| WPUPCFS025|1.85 kilometres|| WPUPCFS026|18.53 kilometres|| WPUPCFS027|111.19 kilometres|| WPUPCFS029|Send compressed posits|C| # # PopUp "Object/Item" POPUPOB001|Object/Item|| POPUPOB002|Name:|| POPUPOB003|Create New Object|| POPUPOB004|Delete Object|| POPUPOB005|Modify Object|| POPUPOB006|Create New Item|| POPUPOB007|Area Object|| POPUPOB008|Area Object|| POPUPOB009|Bright Color|| POPUPOB010|Color-Fill|| POPUPOB011|Circle|| POPUPOB012|Line-Right '/'|| POPUPOB013|Line-Left '\'|| POPUPOB014|Triangle|| POPUPOB015|Rectangle|| POPUPOB016|Black|| POPUPOB017|Blue|| POPUPOB018|Green|| POPUPOB019|Cyan|| POPUPOB020|Red|| POPUPOB021|Violet|| POPUPOB022|Yellow|| POPUPOB023|Grey|| POPUPOB024|Offset Up:|| POPUPOB025|Offset Left (Except '/'):|| POPUPOB026|Corridor:|| POPUPOB027|Generic Options|| POPUPOB028|Location|| POPUPOB029|Signpost|| POPUPOB030|Signpost Text|| POPUPOB031|Signpost Object|| POPUPOB032|Enable Compression|| POPUPOB033|Delete Item|| POPUPOB034|Modify Item|| POPUPOB035|Altitude (ft):|| POPUPOB036|Speed (knots):|| POPUPOB037|Course:|| POPUPOB038|DF Object|| POPUPOB039|Signal - Height(HAAT) - Gain - Directivity|| POPUPOB040|Beam Width - Bearing|| POPUPOB041|Omni Antenna|| POPUPOB042|Beam Antenna|| POPUPOB043|Useless|| POPUPOB044|Adopt Object|| POPUPOB045|Adopt Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Configure Internet|| WPUPCFI002|Host || WPUPCFI003|Port || WPUPCFI004|(Secondary hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Port1|| WPUPCFI007|Host2|| WPUPCFI008|Port2|| WPUPCFI009|Pass-code|| WPUPCFI010|(Leave Blank if None)|| WPUPCFI011|Reconnect on NET failure?|| WPUPCFI012|Run as an I-Gate?|| WPUPCFI013|Broadcast messages via TNC when an I-Gate?|| WPUPCFI014|Log I-Gate Transactions?|| WPUPCFI015|Filter Parameters|| # # PopUp "Configure Database" WPUPCFID01|Configure Database (TBD)|| WPUPCFID02|Host || WPUPCFID03|Port || WPUPCFID04|(Secondary hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Port1|| WPUPCFID07|Host2|| WPUPCFID08|Port2|| WPUPCFID09|Pass-code|| WPUPCFID10|(Leave Blank if None)|| WPUPCFID11|Reconnect on NET failure?|| WPUPCFID12|Run as an I-Gate?|| WPUPCFID13|Broadcast messages via TNC when an I-Gate?|| WPUPCFID14|Log I-Gate Transactions?|| WPUPCFID15|Filter Parameters|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configure AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Port || WPUPCFIA04|(Secondary hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Port1|| WPUPCFIA07|Host2|| WPUPCFIA08|Port2|| WPUPCFIA09|Pass-code|| WPUPCFIA10|(Leave Blank if None)|| WPUPCFIA11|Reconnect on NET failure?|| WPUPCFIA12|Run as an I-Gate?|| WPUPCFIA13|Broadcast messages via TNC when an I-Gate?|| WPUPCFIA14|Log I-Gate Transactions?|| WPUPCFIA15|Transmit RadioPort|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Configure Audio Alarms|| WPUPCFA002|Audio Play Command|| WPUPCFA003|Alarm on|| WPUPCFA004|Audio file to Play|| WPUPCFA005|New Station|| WPUPCFA006|New Message|| WPUPCFA007|Proximity|| WPUPCFA008|Band Opening|| WPUPCFA009|Minimum Distance|| WPUPCFA010|Maximum Distance|| WPUPCFA011|Weather Alert|| # # PopUp "Configure Speech" WPUPCFSP01|Configure Speech|| WPUPCFSP02|Speech Output on:|| WPUPCFSP03|New Station|| WPUPCFSP04|New Message Alert|| WPUPCFSP05|New Message Body|| WPUPCFSP06|Proximity Alert|| WPUPCFSP07|Band Opening|| WPUPCFSP08|New Weather Alert|| WPUPCFSP09|Tracked Station Proximity Alert|| # # PopUp "Track Station" WPUPTSP001|Track Station|| WPUPTSP002|Track Callsign|| WPUPTSP003|Match Case|| WPUPTSP004|Match Exact|| WPUPTSP005|Track Now!|| WPUPTSP006|Clear Tracking|| WPUPTSP007|Download Trail|| WPUPTSP008|Callsign|| WPUPTSP009|Start Trail (hrs ago)|| WPUPTSP010|Trail Length (hrs)|| # # PopUp "Messages..." WPUPMSB001|Send Message Box %d|| WPUPMSB002|Send Group Message Box %d|| WPUPMSB003|Station's Call:|| WPUPMSB004|Group's Call:|| WPUPMSB005|New/Refresh Call|| WPUPMSB006|New Group|| WPUPMSB007|Clear Msg History|| WPUPMSB008|Message:|| WPUPMSB009|Send Now!|| WPUPMSB010|Path:|| WPUPMSB011|Cancel Pending Msgs|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # PopUp "Auto Reply" WPUPARM001|Change Auto Reply|| WPUPARM002|Reply:|| # # PopUp "Help Index" WPUPHPI001|Help Index|| WPUPHPI002|View|| # # PopUp "Station Info" WPUPSTI000|Object from: %s|| WPUPSTI001|Station Info|| WPUPSTI002|Send Message|| WPUPSTI003|Search FCC Database|| WPUPSTI004|Search RAC Database|| WPUPSTI005|Packets received: %d Last Heard: || WPUPSTI006|Heard via the TNC on device %d, || WPUPSTI007|Heard || WPUPSTI008|last via Local|| WPUPSTI009|last via TNC on device %d|| WPUPSTI010|last via Internet on device %d|| WPUPSTI011|last via File|| WPUPSTI012|last via Unknown|| WPUPSTI013|, and has moved|| WPUPSTI014|Current Power Gain:|| WPUPSTI016|Altitude: %.0f%s || WPUPSTI017|Course: %s || WPUPSTI018|Speed: %.1f km/h|| WPUPSTI019|Speed: %.1f mph|| WPUPSTI020|%0.1f miles|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distance from my station: %s Bearing from my station: %s|| WPUPSTI023|Last Position: || WPUPSTI024|Weather Data %c:%s|| WPUPSTI025|Wind Course: %s Speed: %03d km/h|| WPUPSTI026|Wind Course: %s Speed: %s mph|| WPUPSTI027| Gust: %03d km/h|| WPUPSTI028| Gust: %s mph|| WPUPSTI029|Temperature: %02.1fC || WPUPSTI030|Temperature: %sF || WPUPSTI031|Humidity: %s%% || WPUPSTI032| Humidex: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Snow: %0.1f (cm/24h)|| WPUPSTI035|Snow: %0.0f (inch/24h)|| WPUPSTI036|Rain: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (inch/h) || WPUPSTI039|%0.2f (mm/day) || WPUPSTI040|%0.2f (inch/day) || WPUPSTI041|%0.2f (mm/since midnight)|| WPUPSTI042|%0.2f (inch/since midnight)|| WPUPSTI043|Data path: %s|| WPUPSTI044|Comment %02d/%02d %02d:%02d : %s|| WPUPSTI045|Clear Track|| WPUPSTI046|Total Rain: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (inch)|| WPUPSTI049|Trace Query|| WPUPSTI050|Un-Acked Messages Query|| WPUPSTI051|Direct Stations Query|| WPUPSTI052|Station Version Query|| WPUPSTI053|Modify Object/Item|| WPUPSTI054|Store Track|| WPUPSTI055|Echoed from:|| WPUPSTI056|Enable Automatic Updates|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF Bearing: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Fuel Temp: %02.1fC || WPUPSTI061|Fuel Temp: %sF || WPUPSTI062|Fuel Moisture: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Fetch NWS Alert|| WPUPSTI065|Tactical Call: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # # FCC-RAC Call Look up STIFCC0001|FCC Database Lookup|| STIFCC0002|RAC Database Lookup|| STIFCC0003|Name:|| STIFCC0004|Street:|| STIFCC0005|City:|| STIFCC0006|State:|| STIFCC0007|Zip:|| STIFCC0008|Basic || STIFCC0009|Advanced || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # # FCC-RAC indexing/searching STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Band open message UMBNDO0001|at distance of|| # # # Universal Options UNIOP00001|OK|| UNIOP00002|Cancel|| UNIOP00003|Close|| UNIOP00004|miles|| UNIOP00005|km|| UNIOP00006|Device|| UNIOP00007|Add|| UNIOP00008|Delete|| UNIOP00009|Properties|| UNIOP00010|Allow Transmitting?|| UNIOP00011|Activate on Startup?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|inch|| UNIOP00018|mm/day|| UNIOP00019|inch/day|| UNIOP00020|mm/hr|| UNIOP00021|inch/hr|| UNIOP00022|mm/mid|| UNIOP00023|inch/mid|| UNIOP00024|deg|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Set System Clock from GPS Data?|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Apply|| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Station Chooser|| # # DISPLAY WX ALERT WPUPWXA001|Wx Alerts|| WPUPWXA002|Wx Alert List|| # # PopUp "Configure - Interfaces" WPUPCIF001|Installed Interfaces|| WPUPCIF002|Choose Interface Type|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configure AX.25 TNC|| WPUPCAX002|AX.25 Device name|| # # Interface device names IFDNL00000|None|| IFDNL00001|Serial TNC|| IFDNL00002|Serial TNC w/GPS on a HSP cable|| IFDNL00003|Serial GPS|| IFDNL00004|Serial WX|| IFDNL00005|Internet Server|| IFDNL00006|AX25 TNC|| IFDNL00007|Networked GPS (via gpsd)|| IFDNL00008|Networked WX|| IFDNL00009|Serial TNC w/GPS on AUX port|| IFDNL00010|Serial KISS TNC|| IFDNL00011|Networked Database (Not Implemented Yet)|| IFDNL00012|Networked AGWPE|| IFDNL00013|Serial Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s %s %s|| IFDIN00001|%s %2d %s %s:%d %s|| IFDIN00002|%s %2d %s device %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| DOWN || IFDIN00007| UP || IFDIN00008|ERROR || IFDIN00009|UNKNWN|| # # PopUp "Interface control" IFPUPCT000|Interface Control|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Start All|| IFPUPCT004|Stop All|| # # IGate control IGPUPCF000|IGate Options|| IGPUPCF001|Disable all IGate traffic|| IGPUPCF002|Allow RF to Inet traffic ONLY|| IGPUPCF003|Allow RF->Inet and Inet->RF traffic|| IGPUPCF004|Igate -> RF Path || # # WX Station WXPUPSI000|WX Station|| WXPUPSI001|WX Station Type|| WXPUPSI002|Current Data|| WXPUPSI003|Wind Course|| WXPUPSI004|Wind Speed|| WXPUPSI005|Wind Gust|| WXPUPSI006|Temp|| WXPUPSI007|Total Rain|| WXPUPSI008|Today's Rain Total|| WXPUPSI009|Baro|| WXPUPSI010|Humidity|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (Data Logging Mode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (Packet Mode)|| WXPUPSI014|Current HR Rain Tot.|| WXPUPSI015|Last 24 Rain Total|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Dew Point|| WXPUPSI019|High Wind|| WXPUPSI020|Wind Chill|| WXPUPSI021|Heat Index|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|High Temp.|| WXPUPSI024|Low Temp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|All Stations|| LHPUPNI001|Mobile Stations|| LHPUPNI002|Weather Stations|| LHPUPNI003|Local Stations (via TNC)|| LHPUPNI004|Last Stations|| LHPUPNI005|Objects & Items|| LHPUPNI006|Own Objects & Items|| LHPUPNI010|#|| LHPUPNI011|Call Sign|| LHPUPNI012|#Pack|| LHPUPNI013|Pos Time|| LHPUPNI014|Path|| LHPUPNI015|PHG|| LHPUPNI016|Comments|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon or UTM|| # # Maps WX Alert styles PULDNMAT01|Show Alert maps above other maps|| PULDNMAT02|Show Alert maps under other maps|| # # Error/popup messages POPEM00001|Locate Error!|| POPEM00002|Station %s was not found!|| POPEM00003|Tracking Error!|| POPEM00004|Interface Error!|| POPEM00005|Invalid AX.25 port name %s|| POPEM00006|Invalid AX.25 port name %s|| POPEM00007|Invalid callsign %s|| POPEM00008|Invalid AX.25 destination callsign or digipeater|| POPEM00009|Cannot open AX.25 socket, %s|| POPEM00010|Cannot bind AX.25 socket, %s|| POPEM00011|Cannot connect to AX.25 callsign, %s|| POPEM00012|AX.25 error on output of UI|| POPEM00013|AX.25 problem with axports file|| POPEM00014|AX.25 invalid port name %s|| POPEM00015|Error opening interface %d Hard Fail|| POPEM00016|Error opening interface %d Time Out|| POPEM00017|No more interfaces Available!|| POPEM00018|Data Query - Single Message Line|| POPEM00019|Port transmitting is off for port %d|| POPEM00020|Database Error!|| POPEM00021|AX.25 support not compiled into Xastir!|| POPEM00022|Input Error!|| POPEM00023|No location name specified!|| POPEM00024|Location name specified is in use!|| POPEM00025|Not Found!|| POPEM00026|Tracking will commence when it appears|| POPEM00027|Improper info. Some fields empty?|| POPEM00028|Can't open file|| POPEM00029|Found It!|| POPEM00030|Weather Station Symbol|| POPEM00031|Changed to WX symbol '/_', other options: '\_' '/W' and '\W'|| POPEM00032|Warning: Using National Weather Service Symbol!|| POPEM00033|No GPS Data!|| POPEM00034|Disabling My Position TX Until Valid GPS Data!|| POPEM00035|Warning|| POPEM00036|Notice|| POPEM00037|HSP interface present: GPS timing has been increased|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Map Display Bookmarks|| JMLPO00002|Activate!|| JMLPO00003|New Name:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Limit Range to (0, is no limit)|| BULMW00003|Change Range|| # # All Message Traffic AMTMW00001|All Message Traffic|| AMTMW00002|Limit Range to (0, is no limit)|| # # Speech Strings SPCHSTR001|kilometers|| SPCHSTR002|meters|| SPCHSTR003|miles|| SPCHSTR004|yards|| SPCHSTR005|%s, distance is %d %s.|| SPCHSTR006|%s, distance is %.1f %s.|| SPCHSTR007|%s, distance is %d %s %s %s.|| SPCHSTR008|%s, distance is %.1f %s %s %s.|| SPCHSTR009|New Weather Alert|| SPCHSTR010|New Station|| SPCHSTR011|Heard, D X, %s, at distance of %.1f %s|| # # SPCHDIRN00|north of|| SPCHDIRS00|south of|| SPCHDIRE00|east of|| SPCHDIRW00|west of|| SPCHDIRNE0|northeast of|| SPCHDIRNW0|northwest of|| SPCHDIRSE0|southeast of|| SPCHDIRSW0|southwest of|| # # Symbol Selection Dialog SYMSEL0001|Select Symbol|| SYMSEL0002|Primary Symbol Table|| SYMSEL0003|Secondary Symbol Table|| # # Print Properties Dialog PRINT0001|Print Properties|| PRINT0002|Paper Size|| PRINT0003|Auto-Rotate Image|| PRINT0004|Rotate Image 90 CCW|| PRINT0005|Auto-Scale Image|| PRINT0006|Scale:|| PRINT0007|Force default background color to white|| PRINT0008|Print in Black and White|| PRINT0016|Reverse Colors|| PRINT0009|Postscript Resolution:|| PRINT0010|Preview|| PRINT0011|Print to File|| PRINT0012|Dumping image to file...|| PRINT0013|Converting to Postscript...|| PRINT0014|Finished creating print file|| PRINT0015|Print Status|| # # Print Dialog PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Locate Feature and Find Address Dialogs FEATURE001|Name:|| FEATURE002|State/Province:|| FEATURE003|County:|| FEATURE004|Map Quad:|| FEATURE005|Type:|| FEATURE006|GNIS File:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Coordinate Calculator Dialog COORD001|Coordinate Calculator|| COORD002|Calc|| COORD003|Calculate|| COORD004|Clear|| COORD005|UTM|| COORD006|Latitude or|| COORD007|Longitude or|| COORD008|Zone|| COORD009|UTM Easting|| COORD010|UTM Northing|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|High Rate (secs):|| SMARTB003|High Speed (mph):|| SMARTB004|High Speed (kph):|| SMARTB005|Low Rate (mins):|| SMARTB006|Low Speed (mph):|| SMARTB007|Low Speed (kph):|| SMARTB008|Minimum Turn (deg):|| SMARTB009|Turn Slope:|| SMARTB010|Wait Time (secs):|| SMARTB011|Enable SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Adjust Gamma Correction|| GAMMA002|Gamma Correction|| # # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Tiny|| MAPFONT004|Map Font Small|| MAPFONT005|Map Font Medium|| MAPFONT006|Map Font Large|| MAPFONT007|Map Font Huge|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # # # Distance/Bearing on status line PULDNDB001|Dist/Bearing Status|| # # # GPS Transfer Operations GPS001|GPS Transfer|| GPS002|Filename|| GPS003|Select Color|| GPS004|Red|| GPS005|Green|| GPS006|Black|| GPS007|White|| GPS008|Orange|| GPS009|Blue|| GPS010|Yellow|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Map Properties|| MAPP002|Max Min Map USGS Auto|| MAPP003|Zoom Zoom Layer Fill DRG Map Path/Filename|| MAPP004|Change Layer->|| MAPP005|Filled->|| MAPP006|Yes|| MAPP007|No|| MAPP008|Automaps->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Day|| TIME002|Days|| TIME003|Hour|| TIME004|Hours|| TIME005|Minute|| TIME006|Minutes|| TIME007|Second|| TIME008|Seconds|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data and other CAD dialogs CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || #"XASTIR Map of (upper left) to (lower right). Lat/Long grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| #"XASTIR Map of (upper left) to (lower right). UTM zones, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # DB_POSTGIS XADBMST002|Postgreql with Postgis|| # DB_MYSQL_SPATIAL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| #XASTIR_SCHEMA_CAD XASCHEMA02|Xastir CAD Schema|| #XASTIR_SCHEMA_COMPLEX XASCHEMA03|Xastir full Schema|| #XASTIR_SCHEMA_APRSWORLD XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/language-French.sys000066400000000000000000001206051501463444000213450ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This is the French Language file used for all the prompts in xastir # # Creator : Richard VE2DJE ve2dje@amsat.org # Maintained by : The Xastir Group # Merci : Jacques Chion, F6CWO, qui a contribu une grande part des # traductions rcentes. (N7TAP) # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|Fichier|F| MENUTB0002|Examiner|E| MENUTB0004|Cartes|a| MENUTB0005|Stations|S| MENUTB0006|Messages|M| MENUTB0010|Interfaces|I| MENUTB0009|Aide|A| # # Menu "File" PULDNFI001|Configurer|C| PULDNFI002|Ouvrir le journal|O| PULDNFI003|Test|e| PULDNFI004|Quitter|Q| PULDNFI007|Changer niveau de dbogage|d| PULDNFI010|Activer archivage TNC|T| PULDNFI011|Activer archivage rseau|r| PULDNFI012|Activer archivage IGate|I| PULDNFI013|Activer archivage mto|m| PULDNFI014|Activer copie d'cran PNG|| PULDNFI015|Imprimer carte|p| PULDNFI016|Instantan KML|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Donnes entrantes|D| PULDNVI003|Stations mobiles|m| PULDNVI004|Toutes stations|T| PULDNVI009|Stations locales|l| PULDNVI012|Stations rcentes|r| PULDNVI005|Stations mto|m| PULDNVI008|Mes donnes mto|o| PULDNVI007|Alertes mto|A| PULDNVI011|Trafic des messages|i| PULDNVI013|Dure de fonctionnement|f| PULDNVI014|Dure de fonctionnement du logiciel|| PULDNVI015|Etat du GPS|| PULDNVI016|Statistiques ALOHA|| # # Menu "Configure" PULDNCF004|Station|S| PULDNCF001|Dfauts|D| PULDNCF003|Temporisations|T| PULDNCF002|Systme des coordonnes|C| PULDNCF006|Alertes sonores|A| PULDNCF007|Parole|P| PULDNCF008|Sauvegarder la configuration maintenant !|a| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Choix des cartes|C| PULDNMP012|Aller |l| PULDNMP014|Localiser lment cartographique|F| PULDNMP016|Dsactiver Zoom/Pan/Accueil rapide|| PULDNMP013|Dsactiver toutes cartes|D| PULDNMP002|Activer cartographie automatique|A| PULDNMP003|Activer quadrillage|q| PULDNMP004|Activer niveaux de cartes|n| PULDNMP010|Activer annotation des cartes|n| PULDNMP009|Activer remplissage de zones|r| PULDNMP007|Activer alertes mto|M| PULDNMP005|Couleur de fond|f| PULDNMP006|Style du texte de station|S| PULDNMP026|Style du contour d'icne|O| PULDNMP011|Menu souris|e| PULDNMP008|Intensit des cartes|I| PULDNMP021|Cartographie automatique - dsactiver cartes trames|| PULDNMP022|Indexer nouvelles cartes au dmarrage|| PULDNMP023|Index: Ajouter nouvelles cartes|R| PULDNMP024|Index: Re-indexer toutes cartes|A| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-tlcharger les cartes (pas partir du cache)|| PULDNMP028|Vider le cache des cartes|| PULDNMP029|Trouver l'adresse|| PULDNMP030|Configurer USGS DRG|| PULDNMP031|Activer bordure des cartes|| MPUPTGR017|Temporisation de carte Internet (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Slectionner ce qui doit tre affich :|| MPUPDRG002|Colorer la carte sous-jaante (XOR)|| MPUPDRG003|Noir|| MPUPDRG004|Blanc|| MPUPDRG005|Bleu|| MPUPDRG006|Rouge|| MPUPDRG007|Marron|| MPUPDRG008|Vert|| MPUPDRG009|Pourpre|| MPUPDRG010|Jaune|| MPUPDRG011|Bleu clair|| MPUPDRG012|Rouge clair|| MPUPDRG013|Pourpre clair|| MPUPDRG014|Gris clair|| MPUPDRG015|Marron clair|| # # PopUp "Map Chooser" WPUPMCP001|Choix de cartes|| PULDNMMC01|Effacer|A| PULDNMMC02|Vectorielles|V| PULDNMMC03|Topogr. 250k|2| PULDNMMC04|Topogr. 100k|1| PULDNMMC05|Topogr. 24k|4| PULDNMMC06|Agrandir rpertoires||| PULDNMMC07|Rps/cartes choisies:|| PULDNMMC08|Dselct. rps|C| PULDNMMC09|Choisir tout|S| # # PullDown "Map Background Color" PULDNMBC01|Gris|| PULDNMBC02|Rose|| PULDNMBC03|Bleu marine|| PULDNMBC04|Bleu acier || PULDNMBC05|Vert moyen|| PULDNMBC06|Vert ple|| PULDNMBC07|Jaune ple|| PULDNMBC08|Blanc crme|| PULDNMBC09|Brun ros|| PULDNMBC10|Rouge brique|| PULDNMBC11|Blanc|| PULDNMBC12|Noir|| # # PullDown "Station text Style" PULDNMSL01|Bordure noire|n| PULDNMSL02|Ombr avec toile de fond|O| PULDNMSL03|Blanc sur noir|B| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|Pas de contour|N| PULDNMIO02|Contour noir|B| PULDNMIO03|Contour gris|G| PULDNMIO04|Contour blanc|W| # # Switches PULDNOT001|Ouvrir|| PULDNOT002|Fermer|| PULDNOT003|Court|| # # Menu "Stations" PULDNDP014|Localiser une station|L| PULDNDP001|Suivre une station|S| PULDNDP022|Rcuprer piste Findu|| PULDNDP032|Filtrer donnes|| PULDNDP040|Ne rien afficher|| PULDNDP041|Ma station|| PULDNDP042|Choisir TNC|| PULDNDP027|- Stations en direct|| PULDNDP043|- Stations via digi|| PULDNDP034|Stations via le net|| PULDNDP019|Inclure donnes primes|| PULDNDP044|Afficher les stations|| PULDNDP028|- Stations fixes|| PULDNDP029|- Stations mobiles|| PULDNDP030|- Stations mto|| PULDNDP053| - Stations mto CWOP|| PULDNDP045|Objets/articles|| PULDNDP026|- Objets/articles mto|| PULDNDP039|- Objets/articles indicateurs d'eau||#' PULDNDP031|- Autres objets/articles|| PULDNDP057|- Selecte Aircraft objets/articles|| PULDNDP058|- Slectionnez l'objet du navire/Articles|| PULDNDP033|Filtrer affichage|| PULDNDP010|Afficher indicatif|n| PULDNDP012|Afficher symbole|c| PULDNDP011|- Pivoter symbole|o| PULDNDP007|Afficher piste|p| PULDNDP003|Afficher cap|r| PULDNDP004|Afficher vitesse|v| PULDNDP017|- Afficher vitesse abrge|| PULDNDP002|Afficher altitude|A| PULDNDP009|Afficher info mto|I| PULDNDP046|- Afficher texte mto|| PULDNDP018|-- Seulement la temprature|| PULDNDP047|- Indicateur de vent|| PULDNDP054|Afficher cercle Aloha|| PULDNDP013|Afficher ambigut de position|b| PULDNDP008|Afficher puissance/gain|g| PULDNDP021|- Activer puissance/gain dfaut|| PULDNDP020|- Activer puissance/gain mobile|| PULDNDP023|Afficher attributs DF|| PULDNDP123|Afficher largeur faiseau recherche auto (DF)|| PULDNDP223|Afficher relev recherche auto (DF)|| PULDNDP035|Activer point estim|| PULDNDP036|- Afficher arc|| PULDNDP037|- Afficher cap|| PULDNDP038|- Afficher symbole|| PULDNDP005|Afficher distance/relvement|d| PULDNDP024|Afficher ge du dernier rapport|| PULDNDP015|Effacer toutes stations !!!|E| PULDNDP016|Effacer toutes pistes !!!|f| PULDNDP025|Effacer histoire des objets/articles|| PULDNDP048|Recharger histoire des objets/articles|| PULDNDP049|Effacer indicatifs tactiques|| PULDNDP050|Effacer historique des indicatifs tactiques|| PULDNDP051|Choisir seulement les indicatifs tactiques|| PULDNDP052|- Annoter les points de piste|| PULDNDP055|Exporter Tout|E| PULDNDP056|Exporter vers fichier KML|| # # Units PULDNUT001|Activer mesures anglaises|| PULDNUT002|Mtres|| # # Menu "Messages" PULDNMG001|Composer un message |C| PULDNMG002|Ouvrir les messages de groupe|g| PULDNMG003|Effacer tout message expdier|E| PULDQUS001|Intrroger toutes les stations|I| PULDQUS002|Intrroger les stations IGate|n| PULDQUS003|Intrroger les stations mto|m| PULDNMG004|Configurer la rponse automatique|o| PULDNMG005|Activer la rponse automatique|R| PULDNMG006|Mode "Satellite Ack"|M| PULDNMG007|Voir les messages en attente|V| # # Menu "Interfaces" PULDNTNT04|Contrle de l'interface|C| PULDNTNT03|Dsactiver transmission: Tout|| PULDNTNT05|Dsactiver transmission: Ma position|| PULDNTNT06|Dsactiver transmission: Objets/Articles|| PULDNTNT11|Activer serveur sur port 2023|| PULDNTNT01|Transmettre maintenant !|T| PULDNTNT07|Extraire piste GPS|F| PULDNTNT08|Extraire routes GPS|R| PULDNTNT09|Extraire points de cheminement GPS|W| PULDNTNT10|Extraire points de cheminement Garmin RINO|G| # # Menu "Help" PULDNHEL01|Information|I| PULDNHEL02|Index de l'Aide|A|#' PULDNHEL03|ACTIVER MODE BALISE DE DETRESSE|E| PULDNHEL04|!!! MODE BALISE DE DETRESSE !!!|| PULDNHEL05| propos de Xastir|| # # # Mouse Menu Popup POPUPMA001|Options|O| POPUPMA00c|Centrer|C| POPUPMA015|Information sur la station|| POPUPMA002|Zoom +|s| POPUPMA003|Zoom -|i| POPUPMA004|Niveau de zoom|N| POPUPMA005|Niveau 1|1| POPUPMA006|Niveau 16|6| POPUPMA007|Niveau 64|4| POPUPMA008|Niveau 256|2| POPUPMA009|Niveau 1024|0| POPUPMA010|Niveau 8192|8| POPUPMA017|Monde entier|M| POPUPMA016|Pos/zoom prcdent|| POPUPMA018|Objet/Article->Crer|| POPUPMA019|Objet/Article->Modifier|| POPUPMA025|Dplacer ma station ici|H| POPUPMA011|Nord|| POPUPMA012|Sud|| POPUPMA013|Ouest|| POPUPMA014|Est|| POPUPMA020|Mesurer|| POPUPMA021|Dplacer|| POPUPMA022|Me suivre|| POPUPMA023|Modificateurs trouvs !|| POPUPMA024|SVP dsactiver CapsLock/NumLock/ScrollLock/autres|| POPUPMA026|Centre & zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Dessiner objets CAD|| POPUPMA030|Dessiner|| POPUPMA031|Fermer polygone|| POPUPMA032|Effacer polygones CAD|| POPUPMA033|**NOT USED**|| POPUPMA034|Changer niveau de zoom|| POPUPMA035|10% arrire|| POPUPMA036|10% avant|| POPUPMA037|Aire|| POPUPMA038|carr|| POPUPMA039|pieds carrs|| POPUPMA040|mtres carrs|| POPUPMA041|Relvement|| POPUPMA042|degrs|| POPUPMA043|Modifier ambigut de position|| POPUPMA044|Ambigut de position est active, votre nouvelle position pourra sauter.|| POPUPMA045|Objets prdfinis|| POPUPMA046|Polygones CAD|| POPUPMA047|Activer les objets CAD|| POPUPMA048|Activer les tiquettes CAD|| POPUPMA049|Activer les commentaires CAD|| POPUPMA050|Activer la probabilit CAD|| POPUPMA051|Activer la taille de la surface CAD|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|mtres|| POPUPMA055|mi| # # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Sv|| BBARSTH001|%d/%d stations|| BBARSTA000|%-9s Nouvel objet !|| BBARSTA001|%-9s Nouvelle station !|| BBARSTA002|%-9s|| BBARSTA003|Chargement de cartes...|| BBARSTA004|Cartes charges|| BBARSTA005|Quadrillage de carte Lat/Long activ|| BBARSTA006|Quadrillage de carte Lat/Long dsactiv|| BBARSTA007|Carte automatique active|| BBARSTA008|Carte automatique dsactive|| BBARSTA009|Niveau de cartes activ|| BBARSTA010|Niveau de cartes dsactiv|| BBARSTA011|Rponse automatique dsactive|| BBARSTA012|Fichier termin...|| BBARSTA013|Ouverture du port GPS|| BBARSTA014|Fermeture du port GPS|| BBARSTA015|Rception de message GPS RMC|| BBARSTA016|Rception de message GPS GGA|| BBARSTA017|Rseau dconnect de l'hte|| BBARSTA018|Connexion rseau dpassement de temps !|| BBARSTA019|Recherche de l'hte %s||#' BBARSTA020|Connect %s|| BBARSTA021|chec de la connexion !|| BBARSTA022|Incapable de relier le socket !|| BBARSTA023|Hte inconnu !|| BBARSTA024|Serveur non spcifi||#' BBARSTA025|Hte trouv, connexion en cours %d|| BBARSTA026|Attente de donnes du GPS par HSP|| BBARSTA027|Fermeture port HSP rception donne TNC..|| BBARSTA028|Chargement de %s|| BBARSTA029|Ouverture port mto|| BBARSTA030|Fermeture port mto|| BBARSTA031|Recherche d'hte %d||#' BBARSTA032|Donnes mto dcodes|| BBARSTA033|cho de digipeater|| BBARSTA034|Chargement de cartes alertes mto|| BBARSTA035|Attente de dones du GPS par AUX|| BBARSTA036|Fermeture port GPS rception donne TNC..|| BBARSTA037|GPS mto dcodes|| BBARSTA038|Placez le changement sur ma station|| BBARSTA039|Cration de l'index de %s|| BBARSTA040|Station d'amateur APRS(tm) %s||#' BBARSTA041|Attente de donnes GPS..|| BBARSTA042|Transmission objets/articles|| BBARSTA043|Journalisation|| BBARSTA044|Le rayon ALOHA est de %d%s|| BBARSTA045|Chargement de symboles...|| BBARSTA046|Rechargement des symboles...|| BBARSTA047|Initialisation de ma station...|| BBARSTA048|Dmarrer interfaces...|| BBARSTA049|Lit les dalles...|| BBARSTA050|Tlcharge les dalles...|| BBARSTA051|Tlcharge dalle %li de %li|| # # # PopUp "View - Incoming Packet Data" WPUPDPD001|Affichage de donnes paquet|| WPUPDPD002|Donnes du TNC seulement|| WPUPDPD003|Donnes du rseau seulement|| WPUPDPD004|Donnes du TNC et du rseau|| WPUPDPD005|TNC|| WPUPDPD006|Rseau|| WPUPDPD007|Capacit Station|| WPUPDPD008|Seulement les miens|| # # PopUp "View - Find Station" WPUPLSP001|Localiser une station|| WPUPLSP002|Localiser l'indicatif||#' WPUPLSP003|Casse exacte|C| WPUPLSP004|Correspondance exacte|E| WPUPLSP005|Localiser maintenant !|L| WPUPLSP006|Localiser dtresse !|| WPUPLSP007|Recherche indicatif FCC/RAC|| # # PopUp "Configure - Defaults" WPUPCFD001|Configurer dfauts|| WPUPCFD002|Au bout de combien de temps une station sera-t-elle considre ge ?|| WPUPCFD003|15 min|1| WPUPCFD004|30 min|3| WPUPCFD005|45 min|4| WPUPCFD006|1 heure|h| WPUPCFD007|90 min|9| WPUPCFD008|2 heures|2| WPUPCFD009|Au bout de combien de temps une station ne sera-t-elle plus affiche ?|| WPUPCFD010|6 heures|6| WPUPCFD011|12 heures|e| WPUPCFD012|1 jour|j| WPUPCFD013|2 jours|o| WPUPCFD014|1 semaine|s| WPUPCFD015|Option de transmission|| WPUPCFD016|Station fixe|| WPUPCFD017|Station mobile + heure locale|| WPUPCFD018|Station mobile + date/heure Zulu|| WPUPCFD019|Station mobile + heure/secondes Zulu|| WPUPCFD021|Position de station + mto|| WPUPCFD022|Position de station + date/heure Zulu + mto|| WPUPCFD023|Transmettre les donnes mto non traites ?|| WPUPCFD024|Transmettre les objets/articles sous forme comprsss ?|| WPUPCFD025|Activer rseau alterne ?|A| WPUPCFD026|Transmettre position quel intervalle ?|| WPUPCFD027|Afficher bulletins nouveaux|| WPUPCFD028|Alerter si cls modificatrices (Verr.Num.)|| WPUPCFD029|Voir bulletins avec distance zro|| WPUPCFD030|Dsactiver identif. de duplic. posit.|| WPUPCFD031|Charger des objets prdfinis partir d'un fichier|| WPUPCFD032|Mon parcour en une seule couleur|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configurer temporisation|| WPUPCFTM02|Intervalle transmission de position (min)|| WPUPCFTM03|Dlai d'affichage faible d'une station (min)|| WPUPCFTM04|Intervalle maximum de transmission des objets/articles (min)||#' WPUPCFTM05|Dlai de suppression d'affichage d'une station (heures)|| WPUPCFTM06|Intervalle de lecture GPS (sec)|| WPUPCFTM07|Dlai de suppression d'une station (jours)|| WPUPCFTM08|Expiration de point estim (min)|| WPUPCFTM09|Dlai inter-char port srie (ms)|| WPUPCFTM10|Dlai nouvelle piste (min)|| WPUPCFTM11|Espace nouvelle piste (degrs)|| WPUPCFTM12|RINO -> Intervalle d'objets (min), 0 = Dsactiv|| WPUPCFTM13|Intervalle de capture instantan (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configurer systme de coordonnes|| WPUPCFC002|Choisir systme de coordonnes|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM avec zones spciales|| # # PopUp "Configure GPS" WPUPCFG001|Configurer GPS|| WPUPCFG003|Port GPS seulement|| WPUPCFG002|Utiliser la position GPS ?|| WPUPCFG004|Options du GPS|| WPUPCFG005|GPS seul|| WPUPCFG006|TNC branch au GPS (Cble HSP)|| WPUPCFG007|TNC branch au GPS avec CTL-E|| WPUPCFG008|Intervalle de temps GPS|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 min|| WPUPCFG013|2 min|| WPUPCFG014|5 min|| WPUPCFG015|10 min|| WPUPCFG016|GPS branch rseau|| WPUPCFG017|Hte GPSD|| WPUPCFG018|Port GPSD|| WPUPCFG019|GPS rseau via GPSD|| WPUPCFG020|Reconnexion sur chec ?|| WPUPCFG021|Connexion mto rseau|| WPUPCFG022|Hte mto|| WPUPCFG023|Port mto|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|Configurer le TNC|| WPUPCFT002|Utiliser le TNC ?|| WPUPCFT003|Port TNC|| WPUPCFT004|Configuration du port|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Voies UnProto|| WPUPCFT012|Voie 1: %s via || WPUPCFT013|Voie 2: %s via || WPUPCFT014|Voie 3: %s via || WPUPCFT015|Type de port|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurer TNC +HSP GPS|| WPUPCFT024|Type de donnes|| WPUPCFT025|Auto detection|| WPUPCFT026|Type binaire|| WPUPCFT027|Type ASCII|| WPUPCFT028|Configurer TNC +AUX GPS|| WPUPCFT029|COnfigurer TNC +INVALID ENUM: %d|| WPUPCFT030|Configurer TNC KISS|| WPUPCFT031|Fichiers de configuration du TNC|| WPUPCFT032|Nom du fichier de dmarrage du TNC|| WPUPCFT033|Nom du fichier d'arrt du TNC||#' WPUPCFT034|Paramtres KISS|| WPUPCFT035|TXDelay (unit 10 ms)|| WPUPCFT036|Persistance (0 255)|| WPUPCFT037|SlotTime (unit 10 ms)|| WPUPCFT038|TxTail (unit 10 ms)|| WPUPCFT039|Full duplex|| WPUPCFT040|Configurer TNC Multi-Port KISS|| WPUPCFT041|Port radio|| WPUPCFT042|Proprits d'interface: Chemin UNPROTO douteux !|| WPUPCFT043|SVP choisissez un chemin plus court tel que WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Proprits d'interface: Chemin IGATE douteux !|| WPUPCFT045|Transmission avec chemin UNPROTO douteux !|| WPUPCFT046|Transmission avec chemin IGATE douteux !|| WPUPCFT047|Initialiser mode KISS au dmarrage|| # # # PopUp "Configure WX Port" WPUPCFWX01|Configurer port mto|| WPUPCFWX02|Port mto|| WPUPCFWX03|Correction globale de pluviomtre|| WPUPCFWX04|.1 pouce/2.5mm|| WPUPCFWX05|.01 pouce/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Pas de correction|| # # PopUp "Configure - Station" WPUPCFS001|Configurer la station|| WPUPCFS002|Indicatif|| WPUPCFS003|LAT|| WPUPCFS004|deg|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/O)|| WPUPCFS009|Symbole de station|| WPUPCFS010|Groupe/superposition|| WPUPCFS011|Symbole|| WPUPCFS028|Choisir|| WPUPCFS012|Puissance - Hauteur (HAAT) - Gain - Directivit|| WPUPCFS013|Dsactiver PHG|| WPUPCFS014|Hauteur de l'antenne||#' WPUPCFS015|Gain de l'antenne||#' WPUPCFS016|Omni|| WPUPCFS017|Commentaire:|| WPUPCFS018|Ambigut de position|| WPUPCFS019|Rien|| WPUPCFS020|.11 milles|| WPUPCFS021|1.15 milles|| WPUPCFS022|11.51 milles|| WPUPCFS023|69.09 milles|| WPUPCFS024|.18 kilomtres|| WPUPCFS025|1.85 kilomtres|| WPUPCFS026|18.53 kilomtres|| WPUPCFS027|111.19 kilomtres|| WPUPCFS029|Transmettre positions compresses|C| # # PopUp "Object/Item" POPUPOB001|Objet/Article|| POPUPOB002|Nom|| POPUPOB003|Crer nouvel objet|| POPUPOB004|Supprimer objet|| POPUPOB005|Modifier objet|| POPUPOB006|Crer nouvel article|| POPUPOB007|Objet polygonal|| POPUPOB008|Objet polygonal|| POPUPOB009|Couleur vive|| POPUPOB010|Remplis de couleur|| POPUPOB011|Cercle|| POPUPOB012|Ligne-droite '/'|| POPUPOB013|Ligne-gauche '\'||#' POPUPOB014|Triangle|| POPUPOB015|Rectangle|| POPUPOB016|Noir|| POPUPOB017|Bleu|| POPUPOB018|Vert|| POPUPOB019|Cyan|| POPUPOB020|Rouge|| POPUPOB021|Violet|| POPUPOB022|Jaune|| POPUPOB023|Gris|| POPUPOB024|Dcalage haut:|| POPUPOB025|Dcalage gauche (sauf '/'):|| POPUPOB026|Couloir:|| POPUPOB027|Options gnriques|| POPUPOB028|Placement|| POPUPOB029|Activer panneau|| POPUPOB030|Texte sur le panneau||#' POPUPOB031|Panneau|| POPUPOB032|Activer compression|| POPUPOB033|Supprimer article|| POPUPOB034|Modifier article|| POPUPOB035|Altitude (pieds):|| POPUPOB036|Vitesse (noeuds):|| POPUPOB037|Cap:|| POPUPOB038|Objet DF|| POPUPOB039|Signal - Hauteur (HAAT) - Gain - Directivit|| POPUPOB040|Largeur de faisceau - Relvement|| POPUPOB041|Antenne omni|| POPUPOB042|Antenne dirige|| POPUPOB043|Inutile|| POPUPOB044|Adopter objet|| POPUPOB045|Adopter article|| POPUPOB046|Relvement DF:|| POPUPOB047|Cercles de probabilit|| POPUPOB048|Objet Map View|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Configurer Internet|| WPUPCFI002|Hte || WPUPCFI003|Port || WPUPCFI004|(Hte secondaire)|| WPUPCFI005|Hte1|| WPUPCFI006|Port1|| WPUPCFI007|Hte2|| WPUPCFI008|Port2|| WPUPCFI009|Code d'accs||#' WPUPCFI010|(Laisser vide si nul)|| WPUPCFI011|Reconnexion sur erreur rseau ?|| WPUPCFI012|Fonction IGate ?|| WPUPCFI013|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFI014|Archivage des transactions IGate ?||| WPUPCFI015|Paramtres du filtre|| # # PopUp "Configure Database" WPUPCFID01|Configurer base de donnes (TBD)|| WPUPCFID02|Hte || WPUPCFID03|Port || WPUPCFID04|(Hte secondaire)|| WPUPCFID05|Hte1|| WPUPCFID06|Port1|| WPUPCFID07|Hte2|| WPUPCFID08|Port2|| WPUPCFID09|Code d'accs||#' WPUPCFID10|(Laisser vide si nul)|| WPUPCFID11|Reconnexion sur erreur rseau ?|| WPUPCFID12|Fonction IGate ?|| WPUPCFID13|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFID14|Archivage des transactions IGate ?||| WPUPCFID15|Paramtres du filtre|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configurer AGWPE|| WPUPCFIA02|Hte || WPUPCFIA03|Port || WPUPCFIA04|(Hte secondaire)|| WPUPCFIA05|Hte1|| WPUPCFIA06|Port1|| WPUPCFIA07|Hte2|| WPUPCFIA08|Port2|| WPUPCFIA09|Code d'accs||#' WPUPCFIA10|(Laisser vide si nul)|| WPUPCFIA11|Reconnexion sur erreur rseau ?|| WPUPCFIA12|Fonction IGate ?|| WPUPCFIA13|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFIA14|Archivage des transactions IGate ?||| WPUPCFIA15|RadioPort de transmission|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Configurer alarmes sonores|| WPUPCFA002|Commande audio utiliser|| WPUPCFA003|Alarme pour:|| WPUPCFA004|Fichier sonore|| WPUPCFA005|Nouvelle station|| WPUPCFA006|Nouveau message|| WPUPCFA007|Proximit|| WPUPCFA008|Ouverture de bande|| WPUPCFA009|Distance minimum|| WPUPCFA010|Distance maximum|| WPUPCFA011|Alerte mto|| # # PopUp "Configure Speech" WPUPCFSP01|Configurer parole|| WPUPCFSP02|Parole pour:|| WPUPCFSP03|Nouvelle station|| WPUPCFSP04|Alerte nouveau message|| WPUPCFSP05|Texte nouveau message|| WPUPCFSP06|Proximit|| WPUPCFSP07|Ouverture de bande|| WPUPCFSP08|Alerte mto|| WPUPCFSP09|Station suivie proximit||#' # # PopUp "Track Station" WPUPTSP001|Suivre station|| WPUPTSP002|Suivre l'indicatif||#' WPUPTSP003|Casse exacte|| WPUPTSP004|Correspondance exacte|| WPUPTSP005|Suivre maintenant !|| WPUPTSP006|Annuler suivi|| WPUPTSP007|Tlcharger piste|| WPUPTSP008|Indicatif|| WPUPTSP009|Dbut de piste (depuis .. heures)|| WPUPTSP010|Longueur de piste (heures)|| # # PopUp "Messages..." WPUPMSB001|Boite d'envoi %d||#' WPUPMSB002|Boite d'envoi au groupe %d||#' WPUPMSB003|Indicatif de station:|| WPUPMSB004|Ident. du groupe:|| WPUPMSB005|Nouvel/Refresh indicatif|| WPUPMSB006|Nouveau groupe|| WPUPMSB007|Effacer histoire de messages|| WPUPMSB008|Message:|| WPUPMSB009|Transmettre maintenant !|| WPUPMSB010|Voie:|| WPUPMSB011|Annuler messages en suspens|| WPUPMSB012|RAZ minuterie Temporisateur|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*EXPIRATION*|| WPUPMSB017|*ANNULE*|| WPUPMSB018|*REJETE*|| WPUPMSB019|Changer chemin|| WPUPMSB020|Utiliser chemin(s) par dfaut|| WPUPMSB021|Direct (pas de chemin)|| WPUPMSB022|Chemin inverse (pour info):|| # # PopUp "Auto Reply" WPUPARM001|Modifier rponse automatique|| WPUPARM002|Rponse:|| # # PopUp "Help Index" WPUPHPI001|Index d'Aide||#' WPUPHPI002|Lire|| # # PopUp "Station Info" WPUPSTI000|Objet de: %s|| WPUPSTI001|Information de station|| WPUPSTI002|Composer un message|| WPUPSTI003|Chercher dans la base FCC|| WPUPSTI004|Chercher dans la base RAC|| WPUPSTI005|Paquets recu: %d Dernire transmission: || WPUPSTI006|Entendu sur le TNC %d, || WPUPSTI007|Entendu || WPUPSTI008|dernirement sur port local|| WPUPSTI009|dernirement sur TNC %d|| WPUPSTI010|dernirement sur Internet %d|| WPUPSTI011|dernirement dans fichier|| WPUPSTI012|dernirement sur inconnu|| WPUPSTI013|, et a boug|| WPUPSTI014|Puissance/gain/etc.:|| WPUPSTI016|Altitude: %.0f%s || WPUPSTI017|Cap: %s || WPUPSTI018|Vitesse: %.1f km/h|| WPUPSTI019|Vitesse: %.1f milles/h|| WPUPSTI020|%0.1f milles|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distance de ma station: %s Relvement de ma station: %s|| WPUPSTI023|Dernire position : || WPUPSTI024|Donnes mto %c:%s|| WPUPSTI025|Cap des vents: %s Vitesse: %03d km/h|| WPUPSTI026|Cap des vents: %s Vitesse: %s milles/h|| WPUPSTI027| Rafales: %03d km/h|| WPUPSTI028| Rafales: %s milles/h|| WPUPSTI029|Temprature: %02.1fC || WPUPSTI030|Temprature: %sF || WPUPSTI031|Humidit: %s%% || WPUPSTI032| Humidex: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Neige: %0.1f (cm/24h|| WPUPSTI035|Neige: %0.0f (pouces/24h)|| WPUPSTI036|Pluie: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (pouces/h) || WPUPSTI039|%0.2f (mm/jour) || WPUPSTI040|%0.2f (pouces/jour) || WPUPSTI041|%0.2f (mm/depuis minuit)|| WPUPSTI042|%0.2f (pouces/depuis minuit)|| WPUPSTI043|Route des donnes: %s|| WPUPSTI044|Commentaire %02d/%02d %02d:%02d : %s|| WPUPSTI045|Effacer la piste|| WPUPSTI046|Pluie Totale: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (pouces)|| WPUPSTI049|Informations suivi|| WPUPSTI050|Messages non confirms|| WPUPSTI051|Info station en direct|| WPUPSTI052|Info station version|| WPUPSTI053|Modifier objet/article|| WPUPSTI054|Sauver piste|| WPUPSTI055|Echo de:|| WPUPSTI056|Activer actualisation automatique|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Relvement DF: %s|| WPUPSTI059|Etat %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp combustible: %02.1fC || WPUPSTI061|Temp combustible: %sF || WPUPSTI062|Humidit combustible: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Chercher alerte NWS|| WPUPSTI065|Indicatif tactique: %s|| WPUPSTI066|Assigner un indicatif tactique|| WPUPSTI067|Porte actuelle : %d milles|| WPUPSTI068|nul|| WPUPSTI069|dfaut|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|porte|| WPUPSTI073|Mauvais PHG|| WPUPSTI074|Mauvais SHG|| WPUPSTI075|Porte DF|| WPUPSTI076|Pas de signal dtect|| WPUPSTI077|Signal dtect (peut-tre))|| WPUPSTI078|Signal dtect non dcodable|| WPUPSTI079|Signal faible, parfois dcodable|| WPUPSTI080|Signal brouill mais copiable|| WPUPSTI081|Un peu de bruit, avec un signal facilement dcodable|| WPUPSTI082|Bon signal avec un peu de bruit|| WPUPSTI083|Signal presque sans bruit|| WPUPSTI084|Signal sans bruit|| WPUPSTI085|Signal trs fort sans bruit|| WPUPSTI086|MAUVAIS RELEVEMENT|| WPUPSTI087|MAUVAIS NRQ|| WPUPSTI088|Largeur de faisceau DF|| WPUPSTI089|Longueur DF|| WPUPSTI090|Invalide|| WPUPSTI091|Changer la couleur de la piste|| WPUPSTI092|Effacer relvements DF|| # # # PopUp "ALOHA Statistics" WPUPALO001|Rayon ALOHA: %d %s|| WPUPALO002|Stations dans le cercle ALOHA: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (en mouvement): %d|| WPUPALO005| Mobiles (autres): %d|| WPUPALO006| Stations mto: %d|| WPUPALO007| Stations fixes: %d|| WPUPALO008|Dernier calcul il y a %d %s %d %s.|| WPUPALO666|Rayon ALOHA pas encore calcul|| # # # FCC-RAC Call Look up STIFCC0001|Recherche base de donnes FCC|| STIFCC0002|Recherche base de donnes RAC|| STIFCC0003|Nom:|| STIFCC0004|Adresse:|| STIFCC0005|Ville:|| STIFCC0006|Etat:|| STIFCC0007|Code postal:|| STIFCC0008|License de base || STIFCC0009|License avance || STIFCC0010|5 mots/min || STIFCC0011|12 mots/min || # # # FCC-RAC Call Look up STIFCC0100|Index FCC ancien, restauration|| STIFCC0101|Recherche d'indicatif|| STIFCC0102|Indicatif non trouv !|| STIFCC0103|Index RAC ancien, restauration|| # # # Band open message UMBNDO0001| une distance de|| # # # Universal Options UNIOP00001|OK|| UNIOP00002|Annuler|| UNIOP00003|Fermer|| UNIOP00004|milles|| UNIOP00005|km|| UNIOP00006|Priphrique|| UNIOP00007|Ajouter|| UNIOP00008|Supprimer|| UNIOP00009|Proprits|| UNIOP00010|Permettre transmission ?|| UNIOP00011|Activer au dmarrage ?|| UNIOP00012|km/h|| UNIOP00013|milles/h|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pouces|| UNIOP00018|mm/jour|| UNIOP00019|pouces/jour|| UNIOP00020|mm/h|| UNIOP00021|pouces/h|| UNIOP00022|mm/minuit|| UNIOP00023|pouces/minuit|| UNIOP00024|deg|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|pouces Hg|| UNIOP00028|mm Hg|| UNIOP00029|Rgler l'horloge systme sur celle du GPS ?|| UNIOP00030|Rpteur digi ?|| UNIOP00031|m|| UNIOP00032|Appliquer||| UNIOP00033|Annuler|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|jour|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Choix de station|| # # DISPLAY WX ALERT WPUPWXA001|Alerte mto|| WPUPWXA002|Liste d'alertes mto|| # # PopUp "Configure - Interfaces" WPUPCIF001|Interfaces installes|| WPUPCIF002|Choix du type d'interface|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configurer TNC AX.25|| WPUPCAX002|Nom de l'interface AX.25||#' # # Interface device names IFDNL00000|Aucune|| IFDNL00001|TNC port srie|| IFDNL00002|TNC srie + GPS sur cble HSP|| IFDNL00003|GPS port srie|| IFDNL00004|Mto port srie|| IFDNL00005|Serveur Internet|| IFDNL00006|TNC AX25|| IFDNL00007|GPS rseau (par gpsd)|| IFDNL00008|Mto par rseau|| IFDNL00009|TNC srie + GPS sur cble AUX|| IFDNL00010|TNC KISS srie|| IFDNL00011|Base de donnes par rseau (pas encore implment)|| IFDNL00012|AGWPE par rseau|| IFDNL00013|TNC Multi-Port KISS srie|| IFDNL00014|Base de donnes SQL (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s sur port srie %s %s|| IFDIN00001|%s %2d %s connect %s:%d %s|| IFDIN00002|%s %2d %s avec interface nomme %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006|INACTIF|| IFDIN00007| ACTIF || IFDIN00008|ERREUR || IFDIN00009|INCONNU|| # # PopUp "Interface control" IFPUPCT000|Contrle d'interface||#' IFPUPCT001|Dmarrer|| IFPUPCT002|Arrter|| IFPUPCT003|Dmarrer toutes|| IFPUPCT004|Arrter toutes|| # # IGate control IGPUPCF000|Options IGate|| IGPUPCF001|Arrter traffic Internet|| IGPUPCF002|Autoriser RF vers Internet seulement|| IGPUPCF003|Autoriser RF->Inet et Inet->RF|| IGPUPCF004|Voie Igate -> RF || # # WX Station WXPUPSI000|Station mto|| WXPUPSI001|Type de station mto|| WXPUPSI002|Donnes courantes|| WXPUPSI003|Cap des vents|| WXPUPSI004|Vitesse des vents|| WXPUPSI005|Rafales|| WXPUPSI006|Temprature|| WXPUPSI007|Prcipitation totale|| WXPUPSI008|Prcipitation totale journalire|| WXPUPSI009|Baromtre|| WXPUPSI010|Humidit|| WXPUPSI011|Peet Bros ULTIMETER 2000 (mode acquisition de donnes)|| WXPUPSI012|Peet Bros ULTIMETER II|| WXPUPSI013|Peet Bros ULTIMETER 2000 (mode paquet)|| WXPUPSI014|Prcipitation horaire totale|| WXPUPSI015|Total prcipitation 24 hrs|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 (mode complet)|| WXPUPSI018|Point de rose|| WXPUPSI019|Vents max.|| WXPUPSI020|Facteur olien|| WXPUPSI021|Facteur humidex|| WXPUPSI022|Baro 3 heures|| WXPUPSI023|Temprature max.|| WXPUPSI024|Temprature min.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|Toutes stations|| LHPUPNI001|Stations mobiles|| LHPUPNI002|Stations mto|| LHPUPNI003|Stations locales (via TNC)|| LHPUPNI004|Dernires stations|| LHPUPNI005|Objets et articles|| LHPUPNI006|Mes objets et articles|| LHPUPNI010|No.|| LHPUPNI011|Indicatif|| LHPUPNI012|#Paq|| LHPUPNI013|Heure dernire pos.|| LHPUPNI014|Chemin|| LHPUPNI015|PHG|| LHPUPNI016|Commentaires|| LHPUPNI100|Cap|| LHPUPNI101|Vit.|| LHPUPNI102|Alt.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Paq|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|Cap|| LHPUPNI201|Vit|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon ou UTM|| # # Maps WX Alert styles PULDNMAT01|Voir cartes alertes au dessus des autres cartes|| PULDNMAT02|Voir cartes alertes en desous des autres cartes|| # # Error/popup messages POPEM00001|Erreur localisation !|| POPEM00002|Station %s non trouve !|| POPEM00003|Erreur de suivi !|| POPEM00004|Erreur d'interface !||#' POPEM00005|Nom de port AX.25 invalide %s|| POPEM00006|Nom de port AX.25 invalide %s|| POPEM00007|Indicatif invalide %s|| POPEM00008|Destination AX25 indicatif ou relais digi invalide|| POPEM00009|Erreur ouverture socket AX.25, %s|| POPEM00010|Erreur liaison socket AX.25, %s|| POPEM00011|Pas de connection l'indicatif AX.25 %s||#' POPEM00012|Erreur AX.25 sur sortie UI|| POPEM00013|Problme avec fichier axports|| POPEM00014|Nom de port AX.25 invalide %s|| POPEM00015|Erreur ouverture d'interface %d Erreur majeure||#' POPEM00016|Erreur ouverture d'interface %d Dpassement de temps||#' POPEM00017|Plus d'interfaces disponible !||#' POPEM00018|Demande de donne - Message une ligne|| POPEM00019|Transmission hors service port %d|| POPEM00020|Erreur base de donnes !|| POPEM00021|Support AX.25 non compil dans Xastir !||#' POPEM00022|Erreur d'entre !||#' POPEM00023|Aucun nom de lieu spcifi !|| POPEM00024|Le nom de lieu spcifi est en cours d'utilisation !||#' POPEM00025|Pas trouv !|| POPEM00026|Suivi commencera quand elle apparatra|| POPEM00027|Mauvaise info. Certains champs vides ?|| POPEM00028|Ne peut ouvrir fichier|| POPEM00029|Trouv !|| POPEM00030|Symbole de station mto|| POPEM00031|Chang en symbole mto '/_', autres possibilits: '\_' '/W' et '\W'|| POPEM00032|Attention: utilise symbole du "National Weather Service" !|| POPEM00033|Pas de donnes GPS !|| POPEM00034|TX de ma position dsactiv jusqu'a rception de bonnes donnes GPS !||#' POPEM00035|Avertissement|| POPEM00036|Avis|| POPEM00037|Interface HSP prsente: temporisation GPS augmente|| POPEM00038|Conflit de nom avec un Objet/Item/Station dj existant|| POPEM00039|Caractre illgal, remplac par un point|| POPEM00040|Le chemin de sortie personnalis a t perdu|| POPEM00041|Traitement d'un autre fichier en cours. Attendez, puis ressayez|| POPEM00042|L'object ne m'appartient pas ! Essayez d'adopter l'objet d'abord.|| POPEM00043|Ce n'est pas un objet ou article !|| POPEM00044|Rcupration de piste Findu : chec|| POPEM00045|Rcupration de piste Findu : Termin|| POPEM00046|La bibliothque Berkeley DB ne correspond pas ! Dsactivation du cache des cartes.|| POPEM00047|Toutes les transmissions sont DESACTIVEES. Les balises d'urgences ne seront PAS envoyes!|| POPEM00048|Mode balise d'URGENCE!|| POPEM00049|MODE BALISE D'URGENCE, transmission toutes les 60 secondes!|| POPEM00050|Interfaces ou trans.position DESACTIVEES. Les balises d'urgences ne seront PAS envoyes!|| POPEM00051|Rseau alternatif (ALTNET) activ (Menu Fichier->Configurer->Defauts)|| POPEM00052|Indicatif est VIDE!|| POPEM00053|Message est VIDE!|| POPEM00054|Vous essayez de communiquer avec vous mme!|| # # Jump Location JMLPO00001|Afficher Cartes Favorites|| JMLPO00002|Aller !|| JMLPO00003|Nouveau nom de lieu:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Limiter la porte (0, aucune limite)|| BULMW00003|Changer porte|| # # All Message Traffic AMTMW00001|Tout trafic des messages|| AMTMW00002|Limiter la porte (0, aucune limite)|| # # Speech Strings SPCHSTR001|kilomtres|| SPCHSTR002|mtres|| SPCHSTR003|milles|| SPCHSTR004|yards|| SPCHSTR005|%s, distance est %d %s.|| SPCHSTR006|%s, distance est %.1f %s.|| SPCHSTR007|%s, distance est %d %s %s %s.|| SPCHSTR008|%s, distance est %.1f %s %s %s.|| SPCHSTR009|Nouvelle alerte mto|| SPCHSTR010|Nouvel indicatif|| SPCHSTR011|Reu, D X, %s, une distance de %.1f %s|| # # SPCHDIRN00|au nord de|| SPCHDIRS00|au sud de|| SPCHDIRE00| l'est de|| SPCHDIRW00| l'ouest de|| SPCHDIRNE0|au nord-est de|| SPCHDIRNW0|au nord-ouest de|| SPCHDIRSE0|au sud-est de|| SPCHDIRSW0|au sud-ouest de|| # # Symbol Selection Dialog SYMSEL0001|Choisir symbole|| SYMSEL0002|Table de symboles primaire|| SYMSEL0003|Table de symboles secondaire|| # # Print Properties Dialog PRINT0001|Proprits d'impression|| PRINT0002|Taille du papier|| PRINT0003|Rotation automatique d'image|| PRINT0004|Tourner image 90 gauche|| PRINT0005|Proportion automatique d'image|| PRINT0006|chelle:|| PRINT0007|Forcer le fond tre blanc|| PRINT0008|Imprimer en noir et blanc|| PRINT0016|Inverser couleurs|| PRINT0009|Rsolution Postscript:|| PRINT0010|Prvisualiser|| PRINT0011|Imprimer dans un fichier|| PRINT0012|Sauvegarde de l'image dans un fichier...|| PRINT0013|Conversion Postscript...|| PRINT0014|Cration du fichier d'impression finie|| PRINT0015|Etat d'impression|| # # Print Properties Dialog PRINT1001|Directement :|| PRINT1002|Via Previewer:|| # # Locate Feature Dialog FEATURE001|Nom:|| FEATURE002|Etat/Province:|| FEATURE003|Comt:|| FEATURE004|Quadrant de carte:|| FEATURE005|Type :|| FEATURE006|Fichier GNIS :|| FEATURE007|Adresse :|| FEATURE008|Ville :|| FEATURE009|Marquer la destination|| FEATURE010|Code postal :|| FEATURE011|Fichier Geocoding|| # # Coordinate Calculator Dialog COORD001|Calculatrice de coordones|| COORD002|Calc|| COORD003|Calculer|| COORD004|Effacer|| COORD005|UTM|| COORD006|Latitude ou|| COORD007|Longitude ou|| COORD008|Zone|| COORD009|UTM vers l'est|| COORD010|UTM vers le nord|| COORD011| Degrs dcimaux: || COORD012| Degrs/Minutes dcimales: || COORD013| Degrs/Minutes/secondes dc.: || COORD014| Universal Transverse Mercator: || COORD015|Syst. de rf. grille militaire: || COORD016| Grille Locator Maidenhead: || COORD017| ** Dsol, entre non reconnue ! **|| COORD018| ** SVP utilisez l'un de ces formats d'entre: **|| # # # Smart Beaconing Dialog SMARTB001|Balise intelligente (Smart Beaconing)|| SMARTB002|Intervalle maximal (secs):|| SMARTB003|Vitesse haute (m/h):|| SMARTB004|Vitesse haute (k/h):|| SMARTB005|Intervalle minimal (mins):|| SMARTB006|Vitesse basse (m/h):|| SMARTB007|Vitesse basse (k/h):|| SMARTB008|Virage minimum (deg):|| SMARTB009|Pente de virage:|| SMARTB010|Temps d'attente (secs):||#' SMARTB011|Activer SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Ajuster correction de gamma|| GAMMA002|Correction de gamma|| # # # # Map labels font Dialog MAPFONT001|Changer police de caratres|| MAPFONT002|Police de caratres|| MAPFONT003|Police de caratre des cartes Minusc|| MAPFONT004|Police de caratre des cartes Petite|| MAPFONT005|Police de caratre des cartes Moyenne|| MAPFONT006|Police de caratre des cartes Large|| MAPFONT007|Police de caratre des cartes Enorme|| MAPFONT008|Police de caratre des cartes Border|| MAPFONT009|Police de caratre des menus|| MAPFONT010|Police de caratre des Stations|| MAPFONT011|Police de caratre de l'ID ATV|| # # # # Distance/Bearing on status line PULDNDB001|Etat dist/relvement|| # # # GPS Transfer Operations GPS001|Transfert GPS|| GPS002|Nom de fichier|| GPS003|Choisir couleur|| GPS004|Rouge|| GPS005|Vert|| GPS006|Noir|| GPS007|Blanc|| GPS008|Orange|| GPS009|Bleu|| GPS010|Jaune|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Caractristiques des cartes|| MAPP002|Max Min Carte Afficher USGS Auto|| MAPP003|Zoom Zoom Couche Remplie DRG Cartes Voie/Fichier|| MAPP004|Modifier Couche->|| MAPP005|Remplie->|| MAPP006|Oui|| MAPP007|Non|| MAPP008|AutoCartes->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|jour|| TIME002|jours|| TIME003|heure|| TIME004|heures|| TIME005|minute|| TIME006|minutes|| TIME007|seconde|| TIME008|secondes|| # # # Map Caching CACHE001|La carte se trouve dans le cache|| CACHE002|Chargement de la carte en mmoire|| CACHE003|Carte non trouve dans le cache...|| # # # Map Screen Misc RANGE001|CHELLE|| # # # GPS Status GPSS001|WAAS ou PPS|| GPSS002|DGPS|| GPSS003|SPS valide|| GPSS004|Invalide|| GPSS005|Sats/vue|| GPSS006|Repre|| GPSS007|! Les donnes GPS ont plus de 30 secondes !|| GPSS008|Simulation|| GPSS009|Manuel|| GPSS010|Estim|| GPSS011|RTK flottant|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Object surface|| CADPUD002|Etiquette surface:|| CADPUD003|Commentaire:|| CADPUD004|Probabilit (%):|| CADPUD005|OK|| CADPUD006|Dialogue CAD|| CADPUD007|Montrer/diter les dtails|| CADPUD008|Annulerl|| CADPUD009|Effacer les objets CAD ?|| CADPUD010|Tout effacer|| CADPUD011|Effacer la slection|| CADPUD012|Continue|| CADPUD013|pointillis|| CADPUD014|Double pointillis|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|Carte XASTIR de %s (haut gauche) %s (bas droit). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|carte XASTIR de %s (haut gauche) %s %s (bas droit). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|Carte XASTIR Map de %s (haut gauche) %s (bas droit). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql avec Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Schma simple Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Schma CAD Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Schma complet Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|Schma APRSWorld|| Xastir-Release-2.2.2/config/language-German.sys000066400000000000000000001154451501463444000213570ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the German Language file used for all the prompts in xastir # Dies ist die deutsche Sprachdatei fr Menus und Textausgaben in Xastir # # Creator : Kai Altenfelder, DL3LBA # Maintained by : The Xastir Group # Modified by : 08.04.2007, Rolf Bleher, DK7IN # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Warnung: # Einige Texte enthalten Formatierungsbefehle wie %s oder %d, diese sollten # beibehalten werden. Falsche Formatbefehle knnen zu einem Programmabsturz # fhren. # # Hauptmenu MENUTB0001|Datei|D| MENUTB0002|Zeige|Z| MENUTB0004|Karten|K| MENUTB0005|Stationen|S| MENUTB0006|Nachrichten|N| MENUTB0010|Schnittstellen|i| MENUTB0009|Hilfe|H| # # Menu "Datei" PULDNFI001|Einstellungen|E| PULDNFI002|Protokolldatei laden|P| PULDNFI003|Test|T| PULDNFI004|Beenden|B| PULDNFI007|Debug Level ndern|D| PULDNFI010|TNC protokollieren|| PULDNFI011|Netz protokollieren|| PULDNFI012|IGate protokollieren|| PULDNFI013|Wetter protokollieren|| PULDNFI014|PNG-Schnapschsse|| PULDNFI015|Karte drucken|d| PULDNFI016|KML Snapshots|| # # Menu "Zeige" PULDNVI001|Bekanntmachungen|B| PULDNVI002|Packet Radio|P| PULDNVI003|Mobilstationen|M| PULDNVI004|Alle Stationen|A| PULDNVI009|Lokale Stationen|L| PULDNVI012|Letzte Stationen|S| PULDNVI005|Wetterstationen|W| PULDNVI008|Eigene Wetterdaten|d| PULDNVI007|Wetterwarnung|e| PULDNVI011|Nachrichten|N| PULDNVI013|Laufzeit|z| PULDNVI014|Programmlaufzeit|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistiken|| # # Menu "Einstellungen" PULDNCF004|Meine Stationsdaten|M| PULDNCF001|Grundeinstellungen|G| PULDNCF003|Zeitverhalten|Z| PULDNCF002|Koordinatensystem|K| PULDNCF006|Audio Alarm|A| PULDNCF007|Sprachausgabe|S| PULDNCF008|Einstellungen sichern|E| # (Einheiten siehe PULDNDP006) # # Menu "Karten" PULDNMP001|Kartenauswahl|K| PULDNMP012|Ausschnitte|A| PULDNMP014|Objekt in Karte suchen|O| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Alle Karten verbergen|| PULDNMP002|Automatische Karten|| PULDNMP003|Gitter|| PULDNMP004|Ebenen|| PULDNMP010|Kartenbeschriftung|| PULDNMP009|Flchen einfrben|| PULDNMP007|Wetterwarnung|| PULDNMP005|Hintergrundfarbe|H| PULDNMP006|Textdarstellung|T| PULDNMP026|Symbol Umrandung|U| PULDNMP011|Mauszeiger-Men|M| PULDNMP008|Intensitt|I| PULDNMP021|Autom. Karten - PixelKarten aus|| PULDNMP022|Neue Karten beim Start indizieren|| PULDNMP023|Index: Neue Karten hinzufgen|N| PULDNMP024|Index: ALLE Karten reindizieren|r| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Karten neu laden (nicht vom Cache)|| PULDNMP028|Lsche gesamten Karten-Cache!|| PULDNMP029|Finde Adresse|| PULDNMP030|Konfiguration USGS DRG|| PULDNMP031|Kartenrand ein|| MPUPTGR017|Internet-Karten Timeout [Sek]|| # # PopUp "Configure USGS DRG" MPUPDRG001|Whle darzustellende Objekte:|| MPUPDRG002|frbe Hintergrundkarten (XOR)|| MPUPDRG003|Schwarz|| MPUPDRG004|Wei|| MPUPDRG005|Blau|| MPUPDRG006|Rot|| MPUPDRG007|Braun|| MPUPDRG008|Grn|| MPUPDRG009|Violett|| MPUPDRG010|Gelb|| MPUPDRG011|Hellblau|| MPUPDRG012|Rosa|| MPUPDRG013|Violett (hell)|| MPUPDRG014|Hellgrau|| MPUPDRG015|Hellbraun|| # # # PopUp "Kartenauswahl" WPUPMCP001|Kartenauswahl|| PULDNMMC01|Keine|K| PULDNMMC02|Vektor|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Verz. expandieren|e| PULDNMMC07|Verz/Karten gewhlt:|| PULDNMMC08|Verz. lschen|l| PULDNMMC09|Alles whlen|A| # # Karten - Hintergrundfarbe PULDNMBC01|Grau|| PULDNMBC02|Helles Grau|| PULDNMBC03|Dunkelblau|| PULDNMBC04|Hellblau|| PULDNMBC05|Grn|| PULDNMBC06|Hellgrn|| PULDNMBC07|Gelb|| PULDNMBC08|Zartes Gelb|| PULDNMBC09|Rtliches Braun|| PULDNMBC10|Rot|| PULDNMBC11|Wei|| PULDNMBC12|Schwarz|| # # Karten - Stil der Stationstexte PULDNMSL01|Schwarze Umrandung|U| PULDNMSL02|Schatten|S| PULDNMSL03|Schwarzer Hintergrund|H| PULDNMSL04|DropShadow|| # # PullDown "Symbol Umrandung" PULDNMIO01|Keine Umrandung|K| PULDNMIO02|Schwarze Umrandung|S| PULDNMIO03|Graue Umrandung|G| PULDNMIO04|Weie Umrandung|W| # # Schalter PULDNOT001|An|| PULDNOT002|Aus|| PULDNOT003|Kurz|| # # Menu "Stationen" PULDNDP014|Station finden|f| PULDNDP001|Verfolge Station|V| PULDNDP022|Spur von findu holen|h| PULDNDP032|Daten filtern|| PULDNDP040|Nichts|| PULDNDP041|Meine Daten|| PULDNDP042|TNC|| PULDNDP027|- Direkt|| PULDNDP043|- ber Digi|| PULDNDP034|Netzwerk|| PULDNDP019|Alte Daten einbeziehen|| PULDNDP044|Stationen|| PULDNDP028|- Feste Stationen|| PULDNDP029|- Bewegte Stationen|| PULDNDP030|- Wetterstationen|| PULDNDP053| - CWOP-Stationen|| PULDNDP045|Objekte|| PULDNDP026|- Wetter Objekte|| PULDNDP039|- Regenmengen Objekte|| PULDNDP031|- Andere Objekte|| PULDNDP057|- Whlen Sie Flugzeug Objekte/Items|| PULDNDP058|- Whlen Sie Schiff Objekte/Items|| PULDNDP033|Anzeige filtern|| PULDNDP010|Rufzeichen|| PULDNDP012|Symbol|| PULDNDP011|- Symbol drehen|| PULDNDP007|Spur|| PULDNDP003|Kurs|| PULDNDP004|Geschwindigkeit|| PULDNDP017|- kurz|| PULDNDP002|Hhe|| PULDNDP009|Wetterdaten|| PULDNDP046|- Wetter Text|| PULDNDP018|-- nur Temperatur|| PULDNDP047|- Windfahne|| PULDNDP054|ALOHA Kreis anzeigen|| PULDNDP013|Positionsverschleierung|| PULDNDP008|Leistung/Gewinn|| PULDNDP021|- mit Standardwert|| PULDNDP020|- bei Mobilstationen|| PULDNDP023|DF Kreise zeigen|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Positionsvoraussage|| PULDNDP036|- Kreis zeigen|| PULDNDP037|- Kurs zeigen|| PULDNDP038|- Symbol zeigen|| PULDNDP005|Entfernung/Richtung|| PULDNDP024|Alter des letzten Empfangs|| PULDNDP015|Stationen lschen|l| PULDNDP016|Spuren lschen|S| PULDNDP025|ObjektHistorie lschen|| PULDNDP048|ObjektHistorie erneut laden|| PULDNDP049|Lschen aller taktischen Calls|| PULDNDP050|Lschen Verlauf taktische Calls|| PULDNDP051|Nur taktische Calls whlen|| PULDNDP052|- Wegpunkte bezeichnen|| PULDNDP055|Exportieren|E| PULDNDP056|Export in KML-Datei|| # # Maeinheiten PULDNUT001|Englische Mae|| PULDNUT002|Metrisch|| # # Menu "Nachrichten" PULDNMG001|Schicke Nachricht an|N| PULDNMG002|ffne Gruppen Nachricht|G| PULDNMG003|Lsche alle ausgehenden Nachrichten|L| PULDQUS001|Abfrage Stationen allgemein|S| PULDQUS002|Abfrage Internet-Gateways|I| PULDQUS003|Abfrage Wetterstationen|W| PULDNMG004|Setze automatische Antwort|t| PULDNMG005|Automatische Antwort|A| PULDNMG006|Satelliten ACK Modus|M| PULDNMG007|Unerledigte Nachrichten zeigen|U| # # Menu "Schnittstellen" PULDNTNT04|Schnittstellensteuerung|| PULDNTNT03|Nicht senden: ALLES|| PULDNTNT05|Nicht senden: Meine Position|| PULDNTNT06|Nicht senden: Objekte|| PULDNTNT11|aktiviere Server-Port|| PULDNTNT01|Sende jetzt!|S| PULDNTNT07|Lade GPS Track|T| PULDNTNT08|Lade GPS Route|R| PULDNTNT09|Lade GPS Wegpunkte|W| PULDNTNT10|Garmin RINO Wegpunkte holen|G| # # Menu "Hilfe" PULDNHEL01|Version|V| PULDNHEL02|Hilfe Index|I| PULDNHEL03|NOTFALL BAKEN MODUS EINSCHALTEN|E| PULDNHEL04|!!! NOTFALL BAKEN MODUS !!!|| PULDNHEL05|ber Xastir|| # # Mauszeiger PopUp Menu POPUPMA001|Mauszeiger-Menu|| POPUPMA00c|Zentrieren|| POPUPMA015|Stations-Info|| POPUPMA002|Zoome hinein|| POPUPMA003|Zoome heraus|| POPUPMA004|Zoomebenen|| POPUPMA005|Ebene 1|| POPUPMA006|Ebene 16|| POPUPMA007|Ebene 64|| POPUPMA008|Ebene 256|| POPUPMA009|Ebene 1024|| POPUPMA010|Ebene 8192|| POPUPMA017|Ganze Welt|| POPUPMA016|Letzte Ansicht|| POPUPMA018|Objekt Neu|| POPUPMA019|Objekt ndern|| POPUPMA025|Meine Station hierhin!|h| POPUPMA011|nach oben|| POPUPMA012|nach unten|| POPUPMA013|nach links|| POPUPMA014|nach rechts|| POPUPMA020|Messen|| POPUPMA021|Bewegen|| POPUPMA022|Verfolge mich|| POPUPMA023|Modifikationstasten aktiv!|| POPUPMA024|Bitte Umschalt/Num/Rollen/andere Modifikationstasten ausschalten|| POPUPMA026|Zentrieren & Zoom|| POPUPMA027| Breite|| POPUPMA028| Lnge|| POPUPMA029|CAD-Objekte zeichnen|| POPUPMA030|Zeichnen|| POPUPMA031|Polygon abschlieen|| POPUPMA032|CAD-Polygone lschen|| POPUPMA033|**NICHT BENUTZT**|| POPUPMA034|Selbstdefinierter Zoom|| POPUPMA035|10% verkleinern|| POPUPMA036|10% vergrern|| POPUPMA037|Bereich|| POPUPMA038|Quadrat|| POPUPMA039|Quadratfuss|| POPUPMA040|Quadratmeter|| POPUPMA041|Peilung|| POPUPMA042|Grad|| POPUPMA043|Bearbeite mehrdeutige Position|| POPUPMA044|Mehrdeutige Position, Ihre Position kann sich sprunghaft verndern.|| POPUPMA045|Vordefinierte Objekte|| POPUPMA046|CAD-Polygone|| POPUPMA047|CAD-Objekte ein|| POPUPMA048|CAD-Label ein|| POPUPMA049|CAD-Kommentare ein|| POPUPMA050|CAD-Wahrscheinlichkeit ein|| POPUPMA051|CAD-Flchenma ein|| POPUPMA052|sq|| POPUPMA053|Fu|| POPUPMA054|Meter|| POPUPMA055|Meilen| # # Texte in Statuszeile BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stationen|| BBARSTA000|%-9s Neues Objekt!|| BBARSTA001|%-9s Neue Station!|| BBARSTA002|%-9s||# neue Daten (nur Call angezeigt) BBARSTA003|Lade Karten...|| BBARSTA004|Karten geladen|| BBARSTA005|Kartengitter An|| BBARSTA006|Kartengitter Aus|| BBARSTA007|Automatische Karte ist AN|| BBARSTA008|Automatische Karte ist AUS|| BBARSTA009|Kartenebenen sind AN|| BBARSTA010|Kartenebenen sind AUS|| BBARSTA011|Automatische Antwort AUS!|| BBARSTA012|Datei beendet..|| BBARSTA013|ffne GPS Port|| BBARSTA014|Schliee GPS Port|| BBARSTA015|GPS RMC String empfangen|| BBARSTA016|GPS GGA String empfangen|| BBARSTA017|Netz vom Host getrennt|| BBARSTA018|Timeout beim Verbindungsaufbau!|| BBARSTA019|Suche Host %s|| BBARSTA020|Verbunden mit %s|| BBARSTA021|Netzverbindung fehlgeschlagen!|| BBARSTA022|Konnte keinen Socket erstellen!|| BBARSTA023|Keine IP fr Host!|| BBARSTA024|Kein Host angegeben|| BBARSTA025|Host gefunden, verbinde %d|| BBARSTA026|Warte auf GPS Daten via HSP..|| BBARSTA027|Setze HSP auf TNC Daten..|| BBARSTA028|Laden von %s|| BBARSTA029|ffne WX Port|| BBARSTA030|Schliee WX Port|| BBARSTA031|Prfe Hostname %d|| BBARSTA032|Dekodiere Wetterdaten|| BBARSTA033|Echo vom Digipeater|| BBARSTA034|Lade Wetterwarnungs-Karten|| BBARSTA035|Warte auf GPS Daten via AUX..|| BBARSTA036|Setze AUX auf TNC Daten..|| BBARSTA037|Dekodiere GPS Daten|| BBARSTA038|eigene Position gendert|| BBARSTA039|Indizieren %s|| BBARSTA040|APRS(tm) Station %s|| BBARSTA041|Warten auf GPS Daten..|| BBARSTA042|Senden von Objekten|| BBARSTA043|Protokoll|| BBARSTA044|ALOHA Entfernung betrgt %d%s|| BBARSTA045|Lade Symbole...|| BBARSTA046|Lade Symbole neu...|| BBARSTA047|Initialisiere meine Station...|| BBARSTA048|Starte Schnittstellen...|| BBARSTA049|Lesen der Kacheln...|| BBARSTA050|Laden der Kacheln...|| BBARSTA051|Laden Kachel %li von %li|| # # PopUp "Zeige - Packet Radio" WPUPDPD001|Packet Radio Daten|| WPUPDPD002|Nur TNC Daten|| WPUPDPD003|Nur Internet Daten|| WPUPDPD004|TNC und Internet Daten|| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Stations-Resourcen|| WPUPDPD008|Nur meine|| # # PopUp "Station - Station finden" WPUPLSP001|Finde Station|| WPUPLSP002|Rufzeichen|| WPUPLSP003|Gro/Klein||# ??? WPUPLSP004|Exakt||# ??? WPUPLSP005|Finde jetzt!|| WPUPLSP006|Notfall-Suche!|| WPUPLSP007|FCC/RAC Suche|| # # PopUp "Einstellungen - Grundeinstellungen" WPUPCFD001|Grundeinstellungen|| WPUPCFD002|Nach welcher Zeit gilt eine Station als alt?|| WPUPCFD003|15 Minuten|| WPUPCFD004|30 Minuten|| WPUPCFD005|45 Minuten|| WPUPCFD006|1 Stunde|| WPUPCFD007|90 Minuten|| WPUPCFD008|2 Stunden|| WPUPCFD009|Nach welcher Zeit wird eine Station nicht mehr angezeigt?|| WPUPCFD010|6 Stunden|| WPUPCFD011|12 Stunden|| WPUPCFD012|1 Tag|| WPUPCFD013|2 Tage|| WPUPCFD014|1 Woche|| WPUPCFD015|Sendeformat der Station|| WPUPCFD016|Feste Station|| WPUPCFD017|Mobile Station mit lokaler Zeit|| WPUPCFD018|Mobile Station mit UTC Tag/Zeit|| WPUPCFD019|Mobile Station mit UTC Zeit/Sekunden|| WPUPCFD021|Station mit Position und Wetter|| WPUPCFD022|Station mit UTC Zeit, Position und Wetter|| WPUPCFD023|Sende Wetter Rohdaten?|| WPUPCFD024|Komprimiertes Format beim Senden von Objekten?|| WPUPCFD025|Alternatives Netz?|| WPUPCFD026|Sende Positionsmeldung in folgenden Intervallen|| WPUPCFD027|PopUp-Fenster fr neue Bekanntmachungen|| WPUPCFD028|Warnung bei Modifikationstasten|| WPUPCFD029|Anzeige bei Entfernung Null|| WPUPCFD030|Position Dubletten-Prfung aus|| WPUPCFD031|Vordefinierte Objekte aus Datei laden|| WPUPCFD032|Meine Spuren in einer Farbe|| WPUPCFD033|ALTNET:|| # # PopUp "Zeitverhalten" WPUPCFTM01|Einstellung des Zeitverhaltens||| WPUPCFTM02|SendeIntervall Position [Min]|| WPUPCFTM03|Station schemenhaft nach [Min]|| WPUPCFTM04|Max SendeIntervall Objekt [Min]|| WPUPCFTM05|Alte Station anzeigen fr [Std]|| WPUPCFTM06|GPS Abfrage alle [Sek]|| WPUPCFTM07|Station lschen nach [Tage]|| WPUPCFTM08|Timeout Pos-Voraussage [Min]|| WPUPCFTM09|Abstand zw. seriellen Zeichen (ms)|| WPUPCFTM10|Neue Spur Zeit (Min)|| WPUPCFTM11|Neue Spur Intervall (Grad)|| WPUPCFTM12|RINO -> Objekt Intervall (min), 0 = Aus|| WPUPCFTM13|Schnapschu-Intervall (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Koordinatensystem" WPUPCFC001|Koordinatensystem|| WPUPCFC002|Koordinatensystem whlen|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM mit Spezialzonen|| # # PopUp "GPS Einstellungen" WPUPCFG001|GPS Einstellungen|| WPUPCFG003|GPS Port|| WPUPCFG002|GPS Position benutzen?|| WPUPCFG004|GPS Optionen|| WPUPCFG005|Eigenstndiger GPS|| WPUPCFG006|TNC mit GPS verbunden (HSP Kabel)|| WPUPCFG007|TNC mit GPS verbunden ber Ctrl-E|| WPUPCFG008|GPS-Abfrage alle|| WPUPCFG009|5 Sek|| WPUPCFG010|15 Sek|| WPUPCFG011|30 Sek|| WPUPCFG012|1 Minute|| WPUPCFG013|2 Minuten|| WPUPCFG014|5 Minuten|| WPUPCFG015|10 Minuten|| WPUPCFG016|GPS ber Netzwerk verbunden|| WPUPCFG017|gpsd Host|| WPUPCFG018|gpsd Port|| WPUPCFG019|GPS ber Netz via gpsd|| WPUPCFG020|Wiederverbinden nach Fehler?|| WPUPCFG021|Wetter ber Netzwerk|| WPUPCFG022|Wetterstation Host|| WPUPCFG023|Wetterstation Port|| # # TNC Einstellungen WPUPCFT001|TNC Einstellungen|| WPUPCFT002|TNC benutzen?|| WPUPCFT003|TNC Port|| WPUPCFT004|Port Geschwindigkeit|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto Pfade|| WPUPCFT012|Pfad 1: %s via || WPUPCFT013|Pfad 2: %s via || WPUPCFT014|Pfad 3: %s via || WPUPCFT015|Port Datenbits|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Einstellungen fr TNC mit GPS ber HSP-Kabel|| WPUPCFT024|Datenart|| WPUPCFT025|Automatisch|| WPUPCFT026|Binr|| WPUPCFT027|ASCII|| WPUPCFT028|Einstellungen fr TNC mit GPS ber AUX-Kabel|| WPUPCFT029|Einstellungen fr TNC mit GPS ber INVALID ENUM: %d|| WPUPCFT030|KISS TNC konfigurieren|| WPUPCFT031|TNC Konfigurationsdateien|| WPUPCFT032|Datei fr TNC-Setup|| WPUPCFT033|Datei fr TNC-Shutdown|| WPUPCFT034|KISS Parameter|| WPUPCFT035|TXDelay (in 10 ms Einheiten)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (in 10 ms Einheiten)|| WPUPCFT038|TxTail (in 10 ms Einheiten)|| WPUPCFT039|Voll-Duplex|| WPUPCFT040|Multi-Port KISS TNC konfigurieren|| WPUPCFT041|Funkgert Port|| WPUPCFT042|Unklarer UNPROTO Pfad!|| WPUPCFT043|Bitte kuerzeren Pfad eingeben, z.B. WIDE2-2 oder RELAY,WIDE2-2|| WPUPCFT044|Unklarer IGATE Pfad!|| WPUPCFT045|Senden eines unklaren/fehlerhaften UNPROTO-Pfades!|| WPUPCFT046|Senden eines unklaren/fehlerhaften IGATE-Pfades!|| WPUPCFT047|KISS-Modus beim Start aktivieren|| # # PopUp "Einstellungen Wetterstation" WPUPCFWX01|Einstellungen Wetterstation|| WPUPCFWX02|Device fr Wetterstation|| WPUPCFWX03|Regenmesser-Korrektur (globale Einstellung)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|keine Korrektur|| # # PopUp "Einstellungen - Stationsdaten" WPUPCFS001|Stationsdaten|| WPUPCFS002|Rufzeichen|| WPUPCFS003|Breite|| WPUPCFS004|Grad|| WPUPCFS005|Min|| WPUPCFS006|(N/S)|| WPUPCFS007|Lnge|| WPUPCFS008|(E/W)|| WPUPCFS009|Stations-Symbol|| WPUPCFS010|Gruppe/Overlay|| WPUPCFS011|Symbol|| WPUPCFS028|Auswahl|| WPUPCFS012|Leistung - Hhe - Gewinn - Richtung|| WPUPCFS013|Kein PHG|| WPUPCFS014|Antennen Hhe|| WPUPCFS015|Antennen Gewinn|| WPUPCFS016|Rundstrahler|| WPUPCFS017|Kommentar:|| WPUPCFS018|Positionsverschleierung|| WPUPCFS019|Keine|| WPUPCFS020|.11 Meilen Kreis|| WPUPCFS021|1.15 Meilen Kreis|| WPUPCFS022|11.51 Meilen Kreis|| WPUPCFS023|69.09 Meilen Kreis|| WPUPCFS024|.18 Kilometer Kreis|| WPUPCFS025|1.85 Kilometer Kreis|| WPUPCFS026|18.53 Kilometer Kreis|| WPUPCFS027|111.19 Kilometer Kreis|| WPUPCFS029|Position in komprimiertem Format senden|k| # # PopUp "Objekt/Item" POPUPOB001|Objekt/Item|| POPUPOB002|Name|| POPUPOB003|Objekt setzen|| POPUPOB004|Objekt lschen|| POPUPOB005|Objekt ndern|| POPUPOB006|Item setzen|| POPUPOB007|Flchenobjekt|| POPUPOB008|als Flchenobjekt|| POPUPOB009|Helle Farben|| POPUPOB010|Flchen fllen|| POPUPOB011|Kreis|| POPUPOB012|Linie-Rechts '/'|| POPUPOB013|Linie-Links '\'|| POPUPOB014|Dreieck|| POPUPOB015|Rechteck|| POPUPOB016|Schwarz|| POPUPOB017|Blau|| POPUPOB018|Grn|| POPUPOB019|Cyan|| POPUPOB020|Rot|| POPUPOB021|Violett|| POPUPOB022|Gelb|| POPUPOB023|Grau|| POPUPOB024|nach oben:|| POPUPOB025|nach links (auer '/'):|| POPUPOB026|Korridor:|| POPUPOB027|Allgemeine Optionen|| POPUPOB028|Position|| POPUPOB029|als Signpost-Objekt|| POPUPOB030|Signpost-Text|| POPUPOB031|Signpost Objekt|| POPUPOB032|Komprimierung einschalten|| POPUPOB033|Item lschen|| POPUPOB034|Item ndern|| POPUPOB035|Hhe [ft]:|| POPUPOB036|Geschwindigkeit [Knoten]:|| POPUPOB037|Kurs:|| POPUPOB038|als Peil-Objekt|| POPUPOB039|Leistung - Hhe - Gewinn - Richtung|| POPUPOB040|ffnungswinkel - Richtung|| POPUPOB041|Rundstrahlantenne|| POPUPOB042|Richtantenne|| POPUPOB043|unbekannt|| POPUPOB044|Objekt bernehmen|| POPUPOB045|Item bernehmen|| POPUPOB046|DF Peilung:|| POPUPOB047|Wahrscheinlichkeitskreise|| POPUPOB048|Map View Objekt|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Internet Einstellungen" WPUPCFI001|Internet Einstellungen|| WPUPCFI002|Host || WPUPCFI003|Port || WPUPCFI004|(Weitere Hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Port1|| WPUPCFI007|Host2|| WPUPCFI008|Port2|| WPUPCFI009|Zugangs-Code|| WPUPCFI010|(freilassen falls keiner)|| WPUPCFI011|Wiederverbinden bei NET Fehler?|| WPUPCFI012|Als I-Gate verwenden?|| WPUPCFI013|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFI014|I-Gate Transaktionen protokollieren?||| WPUPCFI015|Filter-Parameter|| # # PopUp "Datenbank Einstellungen" WPUPCFID01|Datenbank Einstellungen (TBD)|| WPUPCFID02|Host || WPUPCFID03|Port || WPUPCFID04|(Weitere Hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Port1|| WPUPCFID07|Host2|| WPUPCFID08|Port2|| WPUPCFID09|Zugangs-Code|| WPUPCFID10|(Freilassen falls keines)|| WPUPCFID11|Wiederverbinden bei NET Fehler?|| WPUPCFID12|Als I-Gate verwenden?|| WPUPCFID13|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFID14|I-Gate Transaktionen protokollieren?||| WPUPCFID15|Filter-Parameter|| # # PopUp "Configure AGWPE" WPUPCFIA01|AGWPE konfigurieren|| WPUPCFIA02|Host || WPUPCFIA03|Port || WPUPCFIA04|(Weitere Hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Port1|| WPUPCFIA07|Host2|| WPUPCFIA08|Port2|| WPUPCFIA09|Zugangs-Code|| WPUPCFIA10|Freilassen falls keines)|| WPUPCFIA11|Wiederverbinden bei NET Fehler?|| WPUPCFIA12|Als I-Gate verwenden?|| WPUPCFIA13|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFIA14|I-Gate Transaktionen protokollieren?||| WPUPCFIA15|FunkPort Senden|| # # PopUp "Einstellungen fr Audio Alarm" WPUPCFA001|Einstellungen fr Audio Alarm|| WPUPCFA002|Audio Abspielkommando|| WPUPCFA003|Alarm an|| WPUPCFA004|abzuspielende Audio Datei|| WPUPCFA005|Neue Station|| WPUPCFA006|Neue Nachricht|| WPUPCFA007|Annherung|| WPUPCFA008|Bandffnung|| WPUPCFA009|Minimum Entfernung|| WPUPCFA010|Maximum Entfernung|| WPUPCFA011|Wetter Warnung|| # # PopUp "Sprachausgabe" WPUPCFSP01|Sprachausgabe|| WPUPCFSP02|Sprachausgabe bei:|| WPUPCFSP03|Neuer Station|| WPUPCFSP04|Neuer Nachricht|| WPUPCFSP05|Neuer Text in Nachricht|| WPUPCFSP06|Annherungswarnung|| WPUPCFSP07|Bandffnung|| WPUPCFSP08|Neuer Wetterwarnung|| WPUPCFSP09|Annherung verfolgter Station|| # # PopUp "Verfolge Station" WPUPTSP001|Verfolge Station|| WPUPTSP002|Rufzeichen|| WPUPTSP003|Gro/Klein|| WPUPTSP004|Exakt|| WPUPTSP005|Verfolge jetzt!|| WPUPTSP006|Verfolgung aufheben|| WPUPTSP007|Spur aus dem Internet|| WPUPTSP008|Rufzeichen|| WPUPTSP009|Start der Spur (vor ... Std)|| WPUPTSP010|Lnge der Spur (Std)|| # # PopUp "Nachrichten..." WPUPMSB001|Nachricht Fenster %d|| WPUPMSB002|Gruppennachricht Fenster %d|| WPUPMSB003|Stationsrufzeichen:|| WPUPMSB004|Gruppenrufzeichen:|| WPUPMSB005|Neues/Refresh Rufzeichen|| WPUPMSB006|Neue Gruppe|| WPUPMSB007|Lsche alte Nachrichten|| WPUPMSB008|Nachricht:|| WPUPMSB009|Sende jetzt!|| WPUPMSB010|Pfad:|| WPUPMSB011|Wartende Nachrichten zurcknehmen|| WPUPMSB012|Kick Timer|| WPUPMSB013|Seq|| WPUPMSB014|Typ|| WPUPMSB015|Rundmeldung|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*ABBRUCH*|| WPUPMSB018|*ZURCKGEWIESEN*|| WPUPMSB019|Pfad ndern|| WPUPMSB020|Standard-Pfad(e) benutzen|| WPUPMSB021|Direkt (kein Pfad)|| WPUPMSB022|Umgekehrter Pfad (Hinweis):|| # # PopUp "Automatische Antwort" WPUPARM001|Automatische Antwort ndern|| WPUPARM002|Antwort:|| # # PopUp "Hilfe Index" WPUPHPI001|Hilfe Index|| WPUPHPI002|Anzeigen|| # # PopUp "Stations-Info" WPUPSTI000|Objekt von: %s|| WPUPSTI001|Stations-Info|| WPUPSTI002|Sende Nachricht|| WPUPSTI003|Suche in FCC Datenbank|| WPUPSTI004|Suche in RAC Datenbank|| WPUPSTI005|Pakete empfangen: %d Zuletzt gehrt: || WPUPSTI006|Gehrt ber TNC auf Device %d, || WPUPSTI007|Gehrt || WPUPSTI008|zuletzt ber Lokal|| WPUPSTI009|zuletzt ber TNC auf Device %d|| WPUPSTI010|zuletzt ber Internet auf Device %d|| WPUPSTI011|zuletzt ber Datei|| WPUPSTI012|zuletzt ber Unbekannt|| WPUPSTI013|, und hat die Position gendert|| WPUPSTI014|Momentane Leistung/Gewinn:|| WPUPSTI016|Hhe: %.0f %s || WPUPSTI017|Kurs: %s || WPUPSTI018|Geschwindigkeit: %.1fkm/h|| WPUPSTI019|Geschwindigkeit: %.1fmph|| WPUPSTI020|%0.1f Meilen|| WPUPSTI021|%0.1f km|| WPUPSTI022|Entfernung von meiner Station %s, Richtung von meiner Station %s|| WPUPSTI023|Letzte Position: || WPUPSTI024|Wetter Daten %c:%s|| WPUPSTI025|Wind Richtung: %s Geschwindigkeit: %03d km/h|| WPUPSTI026|Wind Richtung: %s Geschwindigkeit: %s mph|| WPUPSTI027| Be: %03d km/h|| WPUPSTI028| Be: %s mph|| WPUPSTI029|Temperatur: %02.1fC || WPUPSTI030|Temperatur: %sF || WPUPSTI031|Feuchte: %s%% || WPUPSTI032|rel.Feuchte: %02.1fC || WPUPSTI033|Luftdruck: %s hPa|| WPUPSTI034|Schnee: %0.1f cm/24h|| WPUPSTI035|Schnee: %0.0f Inch/24h|| WPUPSTI036|Regen: || WPUPSTI037|%0.2f mm/h || WPUPSTI038|%0.2f Inch/h || WPUPSTI039|%0.2f mm/Tag || WPUPSTI040|%0.2f Inch/Tag || WPUPSTI041|%0.2f mm/seit 0:00|| WPUPSTI042|%0.2f Inch/seit 0:00|| WPUPSTI043|Datenpfad: %s|| WPUPSTI044|Kommentar %02d/%02d %02d:%02d : %s|| WPUPSTI045|Lsche Spur|| WPUPSTI046|Regen gesamt: || WPUPSTI047|%0.2f mm|| WPUPSTI048|%0.2f Inch|| WPUPSTI049|Trace Anfrage|| WPUPSTI050|Unbest. Nachrichten|| WPUPSTI051|Stationsanfrage|| WPUPSTI052|Stationsversion|| WPUPSTI053|Objekt/Item ndern|| WPUPSTI054|Spur speichern|| WPUPSTI055|Echo gehrt von:|| WPUPSTI056|Automatische Aktualisierung|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Peil-Richtung: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Brennstofftemp.: %02.1fC || WPUPSTI061|Brennstofftemp.: %sF || WPUPSTI062|Brennstofffeuchte: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|NWS Wetterwarnung holen|| WPUPSTI065|Taktisches Rufzeichen: %s|| WPUPSTI066|Taktischen Rufzeichen zuweisen|| WPUPSTI067|Aktuelle Reichweite: %d Meilen|| WPUPSTI068|keine|| WPUPSTI069|Standard|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|Reichweite|| WPUPSTI073|PHG fehlerhaft|| WPUPSTI074|SHG fehlerhaft|| WPUPSTI075|DF Bereich|| WPUPSTI076|Kein Signal erkannt|| WPUPSTI077|mgliches Signal|| WPUPSTI078|Signal erkannt, nicht lesbar|| WPUPSTI079|Schwaches Signal, schlecht lesbar|| WPUPSTI080|Verrauschtes Signal aber lesbar|| WPUPSTI081|Signal lesbar, etwas Rauschen|| WPUPSTI082|Gutes Signal mit Restrauschen|| WPUPSTI083|Sehr gutes Signal|| WPUPSTI084|Hervorragendes Signal|| WPUPSTI085|Auerordentlich starkes Signal|| WPUPSTI086|SCHLECHTE PEILUNG|| WPUPSTI087|NRQ fehlerhaft|| WPUPSTI088|DF ffnungswinkel|| WPUPSTI089|DF Lnge|| WPUPSTI090|ungltig|| WPUPSTI091|Wegfarbe ndern|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA Radius: %d %s|| WPUPALO002|Stationen innerhalb des ALOHA Kreises: %d|| WPUPALO003| Digis : %d|| WPUPALO004| Mobilstationen (in Bew.) : %d|| WPUPALO005| Mobilstationen (sonstige): %d|| WPUPALO006| Wetterstationen : %d|| WPUPALO007| Feststationen : %d|| WPUPALO008|zuletzt berechnet vor %d %s %d %s.|| WPUPALO666|ALOHA Radius noch nicht berechnet|| # # FCC-RAC Call Look up STIFCC0001|FCC Datenbank Abfrage|| STIFCC0002|RAC Datenbank Abfrage|| STIFCC0003|Name:|| STIFCC0004|Strae:|| STIFCC0005|Stadt:|| STIFCC0006|Staat:|| STIFCC0007|PLZ:|| STIFCC0008|Grundeinstellung || STIFCC0009|Erweitert || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC Call Look up STIFCC0100|FCC-Index zu alt, erstelle neu...|| STIFCC0101|Rufzeichensuche|| STIFCC0102|Rufzeichen nicht gefunden!|| STIFCC0103|RAC-Index zu alt, erstelle neu...|| # # # Band open message UMBNDO0001|in Entfernung von|| # # # Allgemeine Optionen UNIOP00001|Ok|| UNIOP00002|Abbrechen|| UNIOP00003|Schlieen|| UNIOP00004|Meilen|| UNIOP00005|km|| UNIOP00006|Geraet|| UNIOP00007|Hinzufgen|| UNIOP00008|Lschen|| UNIOP00009|Eigenschaften|| UNIOP00010|Senden erlaubt?|| UNIOP00011|Beim Start aktivieren?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|Inch|| UNIOP00018|mm/Tag|| UNIOP00019|Inch/Tag|| UNIOP00020|mm/h|| UNIOP00021|Inch/h|| UNIOP00022|mm ab 0:00|| UNIOP00023|Inch ab 0:00|| UNIOP00024||| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|Inch Hg|| UNIOP00028|mm Hg|| UNIOP00029|Systemzeit durch GPS einstellen|| UNIOP00030|Digipeater?|| UNIOP00031|m|| UNIOP00032|Anwenden||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|Tag|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # popUp "Stationsauswahl" STCHO00001|Stationsauswahl|| # # "Zeige - Wetterwarnungen" WPUPWXA001|Wetterwarnung|| WPUPWXA002|Liste der Wetterwarnungen|| # # PopUp "Einstellungen - Schnittstellen" WPUPCIF001|Installierte Schnittstellen|| WPUPCIF002|Whle Schnittstellentyp|| # # PopUp "Einstellungen AX.25 TNC" WPUPCAX001|Einstellungen AX.25 TNC|| WPUPCAX002|AX.25 Gertename|| # # Interface device names IFDNL00000|Kein|| IFDNL00001|Serieller TNC|| IFDNL00002|Serieller TNC + GPS mit HSP-Kabel|| IFDNL00003|Serieller GPS|| IFDNL00004|Serielle Wetterstation|| IFDNL00005|Internet Server|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS ber Netzwerk (via gpsd)|| IFDNL00008|Wetter ber Netzwerk|| IFDNL00009|Serieller TNC + GPS mit AUX-Kabel|| IFDNL00010|Serieller KISS TNC|| IFDNL00011|Datenbank ber Netz (Noch nicht implementiert)|| IFDNL00012|AGWPE ber Netz|| IFDNL00013|Serieller Multi-Port KISS TNC|| IFDNL00014|SQL Datenbank (experimentell)|| # # Interface device info IFDIN00000|%s %2d %s an ser. Schnittstelle %s %s|| IFDIN00001|%s %2d %s verbunden mit %s:%d %s|| IFDIN00002|%s %2d %s ber Geraet namens %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| INAKTIV || IFDIN00007| AKTIV || IFDIN00008| FEHLER || IFDIN00009| UNBEKANNT || # # PopUp "Schnittstellen-Steuerung" IFPUPCT000|Schnittstellen-Steuerung|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Alle starten|| IFPUPCT004|Alle stoppen|| # # Internet Gateway Steuerung IGPUPCF000|Internet Gateway|| IGPUPCF001|Alle Weiterleitungen verhindern|| IGPUPCF002|Weiterleitung NUR von HF nach Internet|| IGPUPCF003|Weiterleitung HF->Internet UND Internet->HF|| IGPUPCF004|Igate -> HF Pfad || # # Wetterstation WXPUPSI000|Wetterstation|| WXPUPSI001|Wetterstation Typ|| WXPUPSI002|Aktuelle Werte|| WXPUPSI003|Windrichtung|| WXPUPSI004|Windgeschwindigkeit|| WXPUPSI005|Wind Ben|| WXPUPSI006|Temperatur|| WXPUPSI007|Regenmenge|| WXPUPSI008|Regenmenge heute|| WXPUPSI009|Druck| WXPUPSI010|Luftfeuchtigkeit|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (Data Logging Mode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (Packet Mode)|| WXPUPSI014|Regenmenge aktuelle Std.|| WXPUPSI015|Regenmenge letze 24 Std.|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Taupunkt|| WXPUPSI019|Wind Spitze|| WXPUPSI020|Windauskuehlungsfaktor (Windchill)|| WXPUPSI021|Gefhlte Temp.|| WXPUPSI022|3 Std. Druck|| WXPUPSI023|Hchsttemp.|| WXPUPSI024|Tiefsttemp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Stationslisten LHPUPNI000|Stationsliste|| LHPUPNI001|Mobile Stationen|| LHPUPNI002|Wetterstationen|| LHPUPNI003|Lokale Stationen (ber TNC)|| LHPUPNI004|Letzte Stationen|| LHPUPNI005|Objekte & Punkte|| LHPUPNI006|Eigene Objekte & Punkte|| LHPUPNI010|#|| LHPUPNI011|Rufzeichen|| LHPUPNI012|Pakete|| LHPUPNI013|Pos Zeit|| LHPUPNI014|Pfad|| LHPUPNI015|PHG|| LHPUPNI016|Kommentar|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|Hhe|| LHPUPNI103|Breite|| LHPUPNI104|Lnge|| LHPUPNI105|Pakete|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|Ben|| LHPUPNI203|Temp|| LHPUPNI204|Feucht|| LHPUPNI205|Druck|| LHPUPNI206|Rn-h|| LHPUPNI207|Rn-0|| LHPUPNI208|Rn24|| LHPUPNI209|Breite/Lnge oder UTM|| # # Stil der Wetterwarnungskarten PULDNMAT01|Zeige Warnungen ber Karten|| PULDNMAT02|Zeige Warnungen unter Karten|| # # Fehlermeldungen POPEM00001|Suchfehler!|| POPEM00002|Station %s wurde nicht gefunden!|| POPEM00003|Tracking Fehler!|| POPEM00004|Schnittstellenfehler!|| POPEM00005|Ungltiger AX.25 Port Name %s|| POPEM00006|Ungltiger AX.25 Port Name %s|| POPEM00007|Ungltiges Rufzeichen %s|| POPEM00008|AX.25 Ziel-Rufzeichen oder Digipeater ungltig|| POPEM00009|Kann AX.25-Socket nicht ffnen, %s|| POPEM00010|Kann AX.25-Socket nicht binden, %s|| POPEM00011|Kann AX.25-Rufzeichen nicht konnektieren, %s|| POPEM00012|AX.25-Fehler auf Ausgang des UI|| POPEM00013|AX.25-Problem mit axports Datei|| POPEM00014|AX.25 ungltiger Port-Name %s|| POPEM00015|Fehler beim ffnen des Interface %d Hard Fail|| POPEM00016|Fehler beim ffnen des Interface %d Time Out|| POPEM00017|Keine weiteren Schnittstellen verfgbar!|| POPEM00018|Datenanfrage - Single Message Line|| POPEM00019|Senden abgeschaltet bei Port %d|| POPEM00020|Datenbankfehler!|| POPEM00021|AX.25-Untersttzung nicht in Xastir kompiliert!|| POPEM00022|Eingabefehler!|| POPEM00023|Es wurde kein Name angegeben!|| POPEM00024|Der angegebene Name ist nicht mehr frei!|| POPEM00025|Nicht gefunden!|| POPEM00026|Verfolgung wird bei Erscheinen der Station aufgenommen|| POPEM00027|Falsche Eingabe. Einige Felder leer?|| POPEM00028|Kann Datei nicht ffnen|| POPEM00029|Gefunden!|| POPEM00030|Symbol fr Wetterstation|| POPEM00031|Gendert auf Wettersymbol '/_', auch mglich: '\_' '/W' und '\W'|| POPEM00032|Warnung: Symbol des National Weather Service wird benutzt!|| POPEM00033|Keine GPS Daten!|| POPEM00034|Position wird nicht gesendet bis gltige GPS-Daten!|| POPEM00035|Warnung|| POPEM00036|Hinweis|| POPEM00037|HSP Interface vorhanden: GPS-Abfrageintervalle grer|| POPEM00038|Der Name steht im Konflikt mit einem bereits existierenden Objekt, einer Markierung oder Station|| POPEM00039|Nicht zulssige Zeichen gefunden|| POPEM00040|Der nutzerspezifische Pfad ging verloren|| POPEM00041|Erstelle andere Datei. Bitte etwas warten und danach neu versuchen|| POPEM00042|Kein eigenes Objekt! Versuchen Sie erst das Obkekt zu bernehmen.|| POPEM00043|Kein Objekt/Item!|| POPEM00044|Findu-Wegdaten: fehlgeschlagen|| POPEM00045|Findu-Wegdaten: fertig|| POPEM00046|Berkeley DB header/shared library passen nicht! Map-Cache aus.|| POPEM00047|Senden ist global GESPERRT. Notfall-Baken werden NICHT gesendet!|| POPEM00048|Notfall-Baken-Modus!|| POPEM00049|NOTFALL-BAKEN-MODUS, senden alle 60 Sekunden!|| POPEM00050|Schnittstellen oder Positionen/Senden GESPERRT. Notfall-Baken werden NICHT gesendet!|| POPEM00051|Altnet ist aktiv (Menu Einstellungen->Grundeinstellungen)|| POPEM00052|Rufzeichen ist LEER!|| POPEM00053|Nachricht ist LEER!|| POPEM00054|Wir versuchen mit uns selbst zu reden!|| # # Karten - Ausschnitt JMLPO00001|Gespeicherte Kartenausschnitte|| JMLPO00002|Aktivieren!|A| JMLPO00003|Neuer Name:|| # # "Zeige - Bekanntmachungen" BULMW00001|Bekanntmachungen|| BULMW00002|Bereich einschrnken auf (0: unbegrenzt)|| BULMW00003|neuen Bereich setzen|| # # "Zeige - Nachrichten" AMTMW00001|Nachrichtenverkehr|| AMTMW00002|Bereich einschrnken auf (0: unbegrenzt)|| # # Texte fr Sprachsynthese SPCHSTR001|kilometer|| SPCHSTR002|meter|| SPCHSTR003|meilen|| SPCHSTR004|yards|| SPCHSTR005|%s, entfernung ist %d %s.|| SPCHSTR006|%s, entfernung ist %.1f %s.|| SPCHSTR007|%s, entfernung ist %d %s %s %s.|| SPCHSTR008|%s, entfernung ist %.1f %s %s %s.|| SPCHSTR009|neue wetterwarnung|| SPCHSTR010|neues rufzeichen|| SPCHSTR011|D X gehrt, %s, in einer entfernung von %.1f %s|| # SPCHDIRN00|nrdlich von|| SPCHDIRS00|sdlich von|| SPCHDIRE00|stlich von|| SPCHDIRW00|westlich von|| SPCHDIRNE0|nordstlich von|| SPCHDIRNW0|nordwestlich von|| SPCHDIRSE0|sdstlich von|| SPCHDIRSW0|sdwestlich von|| # # Symbolauswahl Dialog SYMSEL0001|Symbol-Auswahl|| SYMSEL0002|Primre Symbol-Tabelle|| SYMSEL0003|Sekundre Symbol-Tabelle|| # # Druckereinstellungen Dialog PRINT0001|Druck Eigenschaften|| PRINT0002|Papiergre|| PRINT0003|Automatisch drehen PRINT0004|90 im Gegenuhrzeigersinn drehen|| PRINT0005|Automatisch skalieren|| PRINT0006|Skalierung:|| PRINT0007|Standardhintergrund durch Wei ersetzen|| PRINT0008|Schwarz/Wei-Druck|| PRINT0016|Farben invertieren|| PRINT0009|Postscript Auflsung:|| PRINT0010|Vorschau|| PRINT0011|In Datei drucken|| PRINT0012|Gebe Bild auf Datei aus...|| PRINT0013|Konvertiere in Postscript...|| PRINT0014|Erstellen der Druckdatei beendet|| PRINT0015|Druckerstatus|| # # Druckereinstellungen Dialog PRINT1001|Direkt an:|| PRINT1002|ber Vorschau:|| # # Locate Feature Dialog FEATURE001|Name:|| FEATURE002|Bundesland/Provinz:|| FEATURE003|County:|| FEATURE004|Map Quad:|| FEATURE005|Typ:|| FEATURE006|GNIS-Datei:|| FEATURE007|Adresse:|| FEATURE008|Stadt:|| FEATURE009|Zielmarkierung:|| FEATURE010|PLZ:|| FEATURE011|Geocoding Datei|| # # Koordinatenrechner Dialog COORD001|Koordinatenumrechnung|| COORD002|Umrechnen|| COORD003|Umrechnen|| COORD004|Lschen|| COORD005|UTM|| COORD006|Breitengrad oder|| COORD007|Lngengrad oder|| COORD008|Zone|| COORD009|UTM stlich|| COORD010|UTM nrdlich|| COORD011| Dezimal Grad: || COORD012| Grad/Dezimal Minuten: || COORD013| Grad/Minuten/Dezimal Sekunden: || COORD014| Universal Transverse Mercator: || COORD015|Militrisches Koordinatensystem: || COORD016| Maidenhead Grid Locator: || COORD017| ** Ihre Eingabe war fehlerhaft ! **|| COORD018| ** Bitte nutzen Sie eines der folgenden Eingabeformate: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|Hohe Rate [Sek] || SMARTB003|Hohe Geschwindigkeit [mph] || SMARTB004|Hohe Geschwindigkeit [km/h] || SMARTB005|Niedrige Rate [Min] || SMARTB006|Niedrige Geschwindigkeit [mph] || SMARTB007|Niedrige Geschwindigkeit [km/h]|| SMARTB008|Kurvenschwellwert [Grad] || SMARTB009|Kurvenparameter (Turn Slope) || SMARTB010|Wartezeit [Sek] || SMARTB011|SmartBeaconing(tm) einschalten|| # # # # Gamma Adjust Dialog GAMMA001|Gammakorrektur einstellen|| GAMMA002|Gammakorrektur|| # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Winzig|| MAPFONT004|Map Font Klein|| MAPFONT005|Map Font Mittel|| MAPFONT006|Map Font Gro|| MAPFONT007|Map Font Riesig|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Entfernung/Richtung auf der Statuszeile PULDNDB001|Entf./Richtung in Status|| # # # GPS Transfer Operations GPS001|GPS-bertragung|| GPS002|Dateiname|| GPS003|Farbe whlen|| GPS004|Rot|| GPS005|Grn|| GPS006|Schwarz|| GPS007|Wei|| GPS008|Orange|| GPS009|Blau|| GPS010|Gelb|| GPS011|Violett|| # # # Karten-Eigenschaften Dialog MAPP001|Karten-Eigenschaften|| MAPP002|Max Min Karten gefllt USGS automat.|| MAPP003|Zoom Zoom Ebene zeichnen DRG Karte Pfad/Dateiname|| MAPP004|Ebene ndern->|| MAPP005|gefllt->|| MAPP006|Ja || MAPP007|Nein|| MAPP008|aut.Karte->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Zeit Texte TIME001|Tag|| TIME002|Tage|| TIME003|Stunde|| TIME004|Stunden|| TIME005|Minute|| TIME006|Minuten|| TIME007|Sekunde|| TIME008|Sekunden|| # # # Map Caching CACHE001|Karte im Cache gespeichert|| CACHE002|Lade Karte aus dem Cache|| CACHE003|Karte nicht im Cache gefunden...|| # # # Map Screen Misc RANGE001|ENTFERNUNGS-SKALIERUNG|| # # # GPS Status GPSS001|WAAS oder PPS|| GPSS002|DGPS|| GPSS003|gltig SPS|| GPSS004|ungltig|| GPSS005|Sats/Anzeige|| GPSS006|Fix|| GPSS007|!GPS-Daten sind lter als 30 Sekunden!|| GPSS008|Simulation|| GPSS009|Manuell|| GPSS010|Schtzung|| GPSS011|FRTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Flchenobjekt|| CADPUD002|Flchen-Label:|| CADPUD003|Kommentar:|| CADPUD004|Wahrscheinlichkeit (%):|| CADPUD005|OK|| CADPUD006|CAD-Dialog|| CADPUD007|Details zeigen/ndern|| CADPUD008|Abbrechen|| CADPUD009|CAD-Objekte lschen?|| CADPUD010|Alle lschen|| CADPUD011|Ausgewhlte lschen|| CADPUD012|durchgezogen|| CADPUD013|gestrichelt|| CADPUD014|doppelt gestrichelt|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Karte von %s (oben links) to %s (unten rechts). UTM %d m Gitter, %s Datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Karte von %s (oben links) to %s %s (unten rechts). Breite/Lnge Gitter, %s Datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Karte von %s (oben links) to %s (unten rechts). UTM Zonen, %s Datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/language-Italian.sys000066400000000000000000001167651501463444000215350ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Xastir Version : 1.0.0 # Creator : Alessandro Frigeri, IK0YUP # Maintained by : The Xastir Group # Last Modified : Tue 31 Aug 11:00:00 CEST 2004 by IK0YUP # # comment lines with pound signs in front are ignored # Il formato del file il seguente: # ID (10 caratteri alfanum)|(Stringa associata all'ID)|TastiDiSceltaRapida|#commento # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # # Men Principale MENUTB0001|Dati|D| MENUTB0002|Liste|L| MENUTB0004|Mappe|M| MENUTB0005|Visualizza|V| MENUTB0006|Messaggi|e| MENUTB0010|Interfacce|I| MENUTB0009|Guida|G| # # Men Dati PULDNFI001|Configura|C| PULDNFI002|Apri file di registro|A| PULDNFI003|Test|| PULDNFI004|Esci|x| PULDNFI007|Cambia il livello di Debug|D| PULDNFI010|Registro TNC|T| PULDNFI011|Registro Rete|e| PULDNFI012|Accesso al Gateway Internet|G| PULDNFI013|Registro dati meteo|G| PULDNFI014|Cattura schermo in PNG|| PULDNFI015|Stampa|P| PULDNFI016|KML Snapshots|| # # Men Visualizza PULDNVI001|Bollettini|B| PULDNVI002|Dati Packet in arrivo|P| PULDNVI003|Stazioni Mobili|M| PULDNVI004|Stazioni|S| PULDNVI009|Stazioni Locali|o| PULDNVI012|Ultime Stazioni|L| PULDNVI005|Stazioni Meteo|W| PULDNVI008|Stazioni Meteo|t| PULDNVI007|Allarmi Meteo|A| PULDNVI011|Traffico Messaggi|T| PULDNVI013|Tempo trascorso dall'avvio|d| PULDNVI014|Uptime del programma|| PULDNVI015|Stato GPS|| PULDNVI016|ALOHA Statistics|| # # Menu' di Configurazione PULDNCF004|Dati Stazione|S| PULDNCF001|Configurazioni originali|D| PULDNCF003|Temporizzazione|T| PULDNCF002|Sistema di Coordinate|C| PULDNCF006|Allarmi Audio|A| PULDNCF007|Annunci Vocali|p| PULDNCF008|Salva la Configurazione Ora!|C| # (per unit vedere PULDNDP006) # # Men Mappe PULDNMP001|Scegli mappa|C| PULDNMP012|Vai alla posizione...|J|#NUOVA funzione dalla v. 0.3.2 PULDNMP014|Localizza Elemento Mappa|E| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Disattiva tutte le mappe|D| PULDNMP002|Mappe automatiche|A| PULDNMP003|Reticolato|G| PULDNMP004|Livelli delle Mappe|L| PULDNMP010|Abilita etichette delle mappe|F| PULDNMP009|Colora le aree chiuse|F| PULDNMP007|Mappe Allarme Meteo|W| PULDNMP005|Colore dello sfondo della mappa|B| PULDNMP006|Etichette Stazione|S| PULDNMP026|Stile Bordo Icone|O| PULDNMP011|Men sul puntatore del mouse|M| PULDNMP008|Intensit Mappa|I| PULDNMP021|Mappe Automatche - Disabilita Mappe Raster|| PULDNMP022|Indicizza Mappe all' Avvio|| PULDNMP023|Indice: Aggiungi Nuove Mappe|N| PULDNMP024|Indice: Riordina Tutte le Mappe|R| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Find Address|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # # Finestra di dialogo mappe WPUPMCP001|Scegli mappa|| PULDNMMC01|Cancella|N| PULDNMMC02|Vettoriali|V| PULDNMMC03|Topografiche 250k|2| PULDNMMC04|Topografiche 100k|1| PULDNMMC05|Topografiche 24k|4| PULDNMMC06|Espandi Cartella||| PULDNMMC07|Cartella/Mappa Selezionata:|| PULDNMMC08|Clear Dirs|C| PULDNMMC09|Select All|S| # # Men Colori dello sfondo delle mappe. PULDNMBC01|Grigio|| PULDNMBC02|Rosa|| PULDNMBC03|Blu mare|| PULDNMBC04|Blu acciaio|| PULDNMBC05|Verde acqua|| PULDNMBC06|Verde chiaro|| PULDNMBC07|Oro forte|| PULDNMBC08|Oro chiaro|| PULDNMBC09|Marrone|| PULDNMBC10|Rosso fuoco|| PULDNMBC11|Bianco|| PULDNMBC12|Nero|| # # Stili delle etichette delle stazioni PULDNMSL01|Bordo nero|| PULDNMSL02|Ombra nera e sfondo uniforme|| PULDNMSL03|Testo su sfondo nero|T| PULDNMSL04|DropShadow|| # # PullDown "Stile Bordo Icone" PULDNMIO01|Nessun Bordo|N| PULDNMIO02|Bordo Nero|B| PULDNMIO03|Bordo Grigio|G| PULDNMIO04|Bordo Bianco|W| # # ATTIVO/DISATTIVO PULDNOT001|Attiva|| PULDNOT002|Disattiva|| PULDNOT003|Breve|| # # Man Stazioni PULDNDP014|Localizza Stazione|L| PULDNDP001|Segui Stazione|T| PULDNDP022|Scarica il percorso da Findu|| PULDNDP032|Filtra Dati|| PULDNDP040|Seleziona Nessuno|| PULDNDP041|Seleziona Miei|| PULDNDP042|Seleziona TNC|| PULDNDP027|- Seleziona Diretta|| PULDNDP043|- Seleziona Via Digi|| PULDNDP034|Seleziona Rete|| PULDNDP019|Visualizza dati scaduti|| PULDNDP044|Seleziona Stazioni|| PULDNDP028|- Seleziona Stazioni Fisse|| PULDNDP029|- Seleziona Stazioni Mobili|| PULDNDP030|- Seleziona Stazioni Meteo|| PULDNDP053| - Seleziona stazioni Meteo CWOP|| PULDNDP045|- Seleziona Oggetti/Dettagli|| PULDNDP026|- Seleziona Oggetti/Dettagli Meteo|| PULDNDP039|- Seleziona Oggetti/Dettagli Misura Acqua|| PULDNDP031|- Seleziona Altri Oggetti/Dettagli|| PULDNDP057|- Selezionare i Vessel Oggetti/Articol|| PULDNDP058|- Select Aircraft Oggetti/Articoli|| PULDNDP033|Visualizza Filtro|| PULDNDP010|Nominativo|l| PULDNDP012|Simboli|Y| PULDNDP011|- Ruota Simboli|R| PULDNDP007|Percorsi delle stazioni|i| PULDNDP003|Direzione|C| PULDNDP004|Velocit|S| PULDNDP017|- Visualizza basse velocit|| PULDNDP002|Altitudine||A PULDNDP009|Informazioni Meteo|W| PULDNDP046|- Visualizza Testo Meteo|| PULDNDP018|-- Visualizza solo Temperatura|| PULDNDP047|- Visualizza Vento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Ambiguit di posizione| PULDNDP008|Potenza/Guadagno|P| PULDNDP021|- Potenza/Guadagno - default|| PULDNDP020|- Potenza/Guadagno - stazioni mobili|| PULDNDP023|Visualizza i cerchi DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Abilita Conteggio|| PULDNDP036|- Visualizza Arc|| PULDNDP037|- Visualizza Rotta|| PULDNDP038|- Visualizza Simbolo|| PULDNDP005|Distanza/Direzione|D| PULDNDP024|Visualizza Et Ultimo Rapporto|| PULDNDP015|Elimina tutte le stazioni|C| PULDNDP016|Elimina tutti i percorsi|T| PULDNDP025|Cancella Storico Oggetti/Dettagli|| PULDNDP048|Ricarica Storico Oggetti/Dettagli|| PULDNDP049|Cancella tutte le chiamate tattiche|| PULDNDP050|Cancella lo storico delle chiamate tattiche|| PULDNDP051|Seleziona solo chiamate tattiche|| PULDNDP052|- Etichetta i punti percorso|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Sistema di misura PULDNUT001|Sistema inglese|| PULDNUT002|Metrico|| # # Messaggi PULDNMG001|Invia messaggio a...|S| PULDNMG002|Apri gruppo di messaggi|g| PULDNMG003|Elimina tutti i messaggi in uscita|C| PULDQUS001|Cerca tutte le stazioni|e| PULDQUS002|Cerca le stazioni Gateway|I| PULDQUS003|Cerca le stazioni meteo|W| PULDNMG004|Imposta risposta automatica ai messaggi in arrivo|S| PULDNMG005|Risposta automatica ai messaggi in arrivo|R| PULDNMG006|Modalit Satellite Ack|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface Control|| PULDNTNT03|Disabilita Trasmissioni: TUTTE|| PULDNTNT05|Disabilita Trasmissioni: Mia Posizione|| PULDNTNT06|Disabilita Trasmissioni: Oggetti/Entit|| PULDNTNT11|Abilita la porta del Server|| PULDNTNT01|Trasmetti Ora!|T| PULDNTNT07|Carica tracciato GPS|F| PULDNTNT08|Carica rotte GPS|R| PULDNTNT09|Carica punti GPS|W| PULDNTNT10|Ricevi Waypoints Garmin RINO|G| # # Men Aiuto PULDNHEL01|Versione di Xastir|A| PULDNHEL02|Indice Guida|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # #Mouse Menu Popup POPUPMA001|Opzioni|| POPUPMA00c|Centra la mappa|| POPUPMA015|Informazioni stazione|| POPUPMA002|Zoom avanti|| POPUPMA003|Zoom indietro|| POPUPMA004|Livello di Zoom|| POPUPMA005|Livello 1|| POPUPMA006|Livello 16|| POPUPMA007|Livello 64|| POPUPMA008|Livello 256|| POPUPMA009|Livello 1024|| POPUPMA010|Livello 8192|| POPUPMA017|Tutto il mondo|| POPUPMA016|Ultima posizione e zoom|| POPUPMA018|Oggetto/Entit->Crea|| POPUPMA019|Oggetto/Entit->Modifica|| POPUPMA025|Muovi La mia Stazione Qu|H| POPUPMA011|Sposta in alto|| POPUPMA012|Sposta in basso|| POPUPMA013|Sposta a sinistra|| POPUPMA014|Sposta a destra|| POPUPMA020|Misurazione distanze|D| POPUPMA021|Muovi|| POPUPMA022|RintracciaMi|| POPUPMA023|Trovato Blocco Tastiera!|| POPUPMA024|Per Favore disabilita Blocco Maiuscole/BlocNum/Scorrimento/|| POPUPMA026|Center & Zoom|| POPUPMA027| Latitudine|| POPUPMA028| Longitudine|| POPUPMA029|Disegna oggetti CAD|| POPUPMA030|Draw|| POPUPMA031|Chiudi il poligono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # #Etichette barra di stato BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stazioni|| BBARSTA000|%-9s Nuovo Oggetto!|| BBARSTA001|Nuova statione! %-9s|| BBARSTA002|Nuovi dati da %-9s|| BBARSTA003|Caricamento mappe...|| BBARSTA004|Mappe caricate|| BBARSTA005|Reticolato Lat/Long Attivo|| BBARSTA006|Reticolato Lat/Long Non Attivo|| BBARSTA007|Caricamento automatico delle mappe attivo|| BBARSTA008|Caricamento automatico delle mappe non attivo|| BBARSTA009|Livello mappe automatico attivato|| BBARSTA010|Livello automatico mappe disattivato|| BBARSTA011|Risposta automatica ai messaggi in arrivo disattivata!|| BBARSTA012|File caricato..|| BBARSTA013|Attivazione porta GPS|| BBARSTA014|Disattivazione porta GPS|| BBARSTA015|Ricezione stringa RMC dal GPS|| BBARSTA016|Ricezione stringa GGA dal GPS|| BBARSTA017|Disconnessione dall'host in rete|| BBARSTA018|Connessione con l'host perduta (Time-out)!|| BBARSTA019|Sto cercando l'host %s|| BBARSTA020|Connesso a %s|| BBARSTA021|Connessione fallita!|| BBARSTA022|Non posso utilizzare la porta di rete!|| BBARSTA023|Risoluzione IP host fallita!|| BBARSTA024|Non stato specificato nessun host|| BBARSTA025|Host trovato, connessione a %d|| BBARSTA026|Sto attendendo dati dal GPS via HSP..|| BBARSTA027|Libero HSP, ricezione dati da TNC..|| BBARSTA028|Caricamento %s|| # BBARSTA029|Apertura porta meteo||# BBARSTA030|Chiusura porta meteo||# BBARSTA031|Ricerca di %d in corso||#KEEP the %d BBARSTA032|Dati meteo rilevati||# BBARSTA033|Eco da digipeater|| BBARSTA034|Caricamento Mappe Allerta Meteo|| BBARSTA035|Sto attendendo dati del GPS via AUX..|| BBARSTA036|Libero AUX, ricezione dati da TNC..|| BBARSTA037|Dati GPS rilevati|| BBARSTA038|Posizionare il cambiamento sulla mia stazione|| BBARSTA039|Indicizzazione %s|| BBARSTA040|Stazione APRS(tm) %s|| BBARSTA041|Attendo dati GPS..|| BBARSTA042|Transmetto oggetti/dettagli|| BBARSTA043|Registro|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # #Visualizzazione dati packet WPUPDPD001|Visualizzazione dati packet|| WPUPDPD002|Solo dati da TNC|| WPUPDPD003|Solo dati dalla Rete|| WPUPDPD004|Dati da TNC e Rete|| WPUPDPD005|TNC|| WPUPDPD006|RETE|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # #Menu' localizza stazione WPUPLSP001|Localizza Stazione|| WPUPLSP002|Localizza Nominativo|| WPUPLSP003|Non rispetta Maius/Minus|| WPUPLSP004|Rispetta Maius/minus || WPUPLSP005|Localizza!|| WPUPLSP006|Localizzazione di Emergenza!|| WPUPLSP007|Ricerca su FCC/RAC|| # # Configure defaults popup WPUPCFD001|Parametri originali|| WPUPCFD002|Dopo quanto tempo una stazione da considerarsi vecchia?|| WPUPCFD003|15 Minuti|| WPUPCFD004|30 Minuti|| WPUPCFD005|45 Minuti|| WPUPCFD006|1 Ora|| WPUPCFD007|90 Minuti|| WPUPCFD008|2 Ore|| WPUPCFD009|Dopo quanto tempo una stazione verr cancellata?|| WPUPCFD010|6 Ore|| WPUPCFD011|12 Ore|| WPUPCFD012|1 Giorno|| WPUPCFD013|2 Giorni|| WPUPCFD014|1 Settimana|| WPUPCFD015|Opzione trasmissione dati stazione|| WPUPCFD016|Stazione fissa|| WPUPCFD017|Stazione mobile con ora locale|| WPUPCFD018|Stazione mobile con ora e data UTC|| WPUPCFD019|Stazione mobile con ora UTC (con secondi)|| WPUPCFD021|Posizione della Stazione con dati meteo|| WPUPCFD022|Posizione stazione, Data e ora UTC, dati meteo|| WPUPCFD023|Devo trasmettere i dati Meteo?|| WPUPCFD024|Comprimo i dati oggetti/dettagli quando trasmetto?|| WPUPCFD025|Attivare rete alternativa?|A| WPUPCFD026|Intervallo per invio rapporti posizione|| WPUPCFD027|Apparizione nuovi bollettini|| WPUPCFD028|Avvisa per utilizzo tasti inadatti|| WPUPCFD029|Vedi bollettini a distanza zero|| WPUPCFD030|Disattiva Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configura Temporizzazioni|| WPUPCFTM02|Intervallo TX posizione (min)|| WPUPCFTM03|Tempo di Ghosting della stazione (min)|| WPUPCFTM04|Max Intervallo TX Oggetto/Entit (min)|| WPUPCFTM05|Clear Time della stazione (ore)|| WPUPCFTM06|Intervallo controllo GPS (sec)|| WPUPCFTM07|Tempo eliminazione stazione (giorni)|| WPUPCFTM08|Fuori tempo Ricalcolo Assoluto (min)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|Nuovo tempo della traccia (min)|| WPUPCFTM11|Nuovo intervallo della traccia (gradi)|| WPUPCFTM12|RINO -> Intervallo oggetto (min), 0 = Non attivo|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configura Sistema Coordinate|| WPUPCFC002|Seleziona Sistema Coordinate|| WPUPCFC003|gg.ggggg|d| WPUPCFC004|gg mm.mmm|m| WPUPCFC005|gg mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM con zone speciali|| # # Configurazione GPS WPUPCFG001|Configura GPS|| WPUPCFG003|GPS collegato ad una porta autonoma|| WPUPCFG002|Usare la posizione data dal GPS?|| WPUPCFG004|Opzioni GPS|| WPUPCFG005|GPS Autonomo|| WPUPCFG006|GPS Collegato al TNC(con cavo HSP)|| WPUPCFG007|GPS Collegato al TNC usando CTL-E|| WPUPCFG008|Ora dal GPS (Rileva ogni)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 Minuti|| WPUPCFG014|5 Minuti|| WPUPCFG015|10 Minuti|| WPUPCFG016|GPS collegato ad una rete (gpsd)|| WPUPCFG017|Host GPSD|| WPUPCFG018|Porta GPSD|| WPUPCFG019|GPS in rete con GPSD|| WPUPCFG020|Riconnetti in caso di errore?|| WPUPCFG021|Dati Meteo rilevati dalla rete|| WPUPCFG022|Host Meteo|| WPUPCFG023|Porta Meteo|| # #Configure TNC (baud/style are also for Meteo) WPUPCFT001|Configura TNC|| WPUPCFT002|Usare TNC?|| WPUPCFT003|porta TNC|| WPUPCFT004|Impostazioni porta|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Percorsi UnProto|| WPUPCFT012|Percorso 1: %s via || WPUPCFT013|Percorso 2: %s via || WPUPCFT014|Percorso 3: %s via || WPUPCFT015|Stile porta|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configura TNC con cavo HSP per GPS|| WPUPCFT024|Tipi di dati|| WPUPCFT025|Riconoscimento automatico|| WPUPCFT026|Dati binari|| WPUPCFT027|Dati ASCII|| WPUPCFT028|Configura TNC con cavo AUX per GPS|| WPUPCFT029|Configura TNC con INVALID ENUM: %d|| WPUPCFT030|Configura TNC KISS|| WPUPCFT031|File di configurazione del TNC|| WPUPCFT032|Nome File configurazione TNC|| WPUPCFT033|Nome File dello Shutdown TNC|| WPUPCFT034|Parametri KISS|| WPUPCFT035|Ritardo TX (unit di 10 ms)|| WPUPCFT036|Persistenza (0 to 255)|| WPUPCFT037|SlotTime (unit di 10 ms)|| WPUPCFT038|Coda Tx (unit di 10 ms)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configura TNC Multi-Port KISS|| WPUPCFT041|Porta Radio|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-Mode|| # #Configura Porta Meteo WPUPCFWX01|Configura Porta Meteo|| WPUPCFWX02|Periferica della stazione|| WPUPCFWX03|Correzione Portata pioggia (Settaggio Globale)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Nessuna Correzione|| # #Configure Stazione WPUPCFS001|Configura Dati Stazione|| WPUPCFS002|Nominativo|| WPUPCFS003|LAT|| WPUPCFS004|grad|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/W)|| WPUPCFS009|Simbolo della Stazione|| WPUPCFS010|Raggruppa/Sovrapponi|| WPUPCFS011|Simbolo|| WPUPCFS028|Seleziona|| WPUPCFS012|Potenza-guadagno|| WPUPCFS013|Disattiva PHG|| WPUPCFS014|Altezza antenna|| WPUPCFS015|Guadagno antenna|| WPUPCFS016|Omni|| WPUPCFS017|Commenti:|| WPUPCFS018|Ambiguit posizione|| WPUPCFS019|Nessuna|| WPUPCFS020|cerchio di.11 miglia|| WPUPCFS021|cerchio di1.15 miglia|| WPUPCFS022|cerchio di11.51 miglia|| WPUPCFS023|cerchio di69.09 miglia|| WPUPCFS024|cerchio di.18 chilometri|| WPUPCFS025|cerchio di1.85 chilometri|| WPUPCFS026|cerchio di18.53 chilometri|| WPUPCFS027|cerchio di 111.19 chilometri|| WPUPCFS029|Invia posizioni compresse|C| # # PopUp "Oggetto/Entit" POPUPOB001|Oggetto/Entit|| POPUPOB002|Nome|| POPUPOB003|Imposta Oggetto|| POPUPOB004|Elimina Oggetto|| POPUPOB005|Modifica Oggetto|| POPUPOB006|Crea Nuova Entit|| POPUPOB007|Oggetto Area|| POPUPOB008|Abilita Oggetto Area|| POPUPOB009|Colore Brillante|| POPUPOB010|Riempimento|| POPUPOB011|Cerchio|| POPUPOB012|Linea a destra '/'|| POPUPOB013|Linea a sinistra '\'|| POPUPOB014|Triangolo|| POPUPOB015|Rettangolo|| POPUPOB016|Nero|| POPUPOB017|Blu|| POPUPOB018|Verde|| POPUPOB019|Azzurro|| POPUPOB020|Rosso|| POPUPOB021|Viola|| POPUPOB022|Giallo|| POPUPOB023|Grigio|| POPUPOB024|Spostamento lungo lat.:|| POPUPOB025|Spostamento lungo long.:|| POPUPOB026|Corridoio:|| POPUPOB027|Opzioni Generiche|| POPUPOB028|Posizione|| POPUPOB029|Abilita simbolo postazione|| POPUPOB030|Dati:|| POPUPOB031|Simbolo postazione|| POPUPOB032|Abilita compressione|| POPUPOB033|Elimina Entit|| POPUPOB034|Modifica Entit|| POPUPOB035|Altitudine (piedi):|| POPUPOB036|Velocit (nodi):|| POPUPOB037|Direzione:|| POPUPOB038|Oggetto DF|| POPUPOB039|Segnale - Altezza(HAAT) - Guadagno - Direttivit|| POPUPOB040|Larghezza fascio - Puntamento|| POPUPOB041|Antenna Omni|| POPUPOB042|Antenna Direzionale|| POPUPOB043|Sconosciuta|| POPUPOB044|Adotta l'Oggetto|| POPUPOB045|Adotte l'Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # #Configure Internet WPUPCFI001|Configura Rete|| WPUPCFI002|Host || WPUPCFI003|Porta || WPUPCFI004|(host secondari)|| WPUPCFI005|Host1|| WPUPCFI006|Porta 1|| WPUPCFI007|Host2|| WPUPCFI008|Porta 2|| WPUPCFI009|codice|| WPUPCFI010|(Lascia vuoto se non necessario)|| WPUPCFI011|Riconnettersi in caso di sconnessione?|| WPUPCFI012|Funzionare da Gateway?|| WPUPCFI013|Trasmetto i dati al TNC quando sono collegato ad Internet?|| WPUPCFI014|Scrivo nel log le trasmissioni dalla Rete al TNC?||| WPUPCFI015|Parametri Filtro|| # #Configure Database WPUPCFID01|Configura Database (TBD)|| WPUPCFID02|Host || WPUPCFID03|Porta || WPUPCFID04|(host secondari)|| WPUPCFID05|Host1|| WPUPCFID06|Porta 1|| WPUPCFID07|Host2|| WPUPCFID08|Porta 2|| WPUPCFID09|codice|| WPUPCFID10|(Lascia vuoto se non necessario)|| WPUPCFID11|Riconnettersi in caso di sconnessione?|| WPUPCFID12|Funzionare da Gateway?|| WPUPCFID13|Trasmetto i dati al TNC quando sono collegato ad Internet?|| WPUPCFID14|Scrivo nel log le trasmissioni dalla Rete al TNC?||| WPUPCFID15|Parametri Filtro|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configura AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Porta || WPUPCFIA04|(Host secondari)|| WPUPCFIA05|Host1|| WPUPCFIA06|Porta1|| WPUPCFIA07|Host2|| WPUPCFIA08|Porta2|| WPUPCFIA09|Codice segreto|| WPUPCFIA10|((Lascia in Bianco se Nessuno)|| WPUPCFIA11|Riconnetti su errore NET?|| WPUPCFIA12|Opera come I-Gate?|| WPUPCFIA13|Manda messaggi Broadcast via TNC durante operazione I-Gate?|| WPUPCFIA14|Registra su Log I-Gate Transactions?|| WPUPCFIA15|Porta radio di trasmissione|| # #Configure Audio Alarms WPUPCFA001|Configura Suoni|| WPUPCFA002|Comando esecuzione audio|| WPUPCFA003|Allarme attivo|| WPUPCFA004|File audio da eseguire|| WPUPCFA005|Nuova stazione|| WPUPCFA006|Nuovo messaggio|| WPUPCFA007|Vicinanza|| WPUPCFA008|Apertura banda|| WPUPCFA009|Distanza minima|| WPUPCFA010|Distanza massima|| WPUPCFA011|Allarme meteo|| # # PopUp "Configure Speech" WPUPCFSP01|Configura Annuncio|| WPUPCFSP02|Annuncio su:|| WPUPCFSP03|Nuova stazione|| WPUPCFSP04|Nuovo Messaggio|| WPUPCFSP05|Nuovo corpo del messaggio|| WPUPCFSP06|Allarme di vicinanza|| WPUPCFSP07|Apertura di banda|| WPUPCFSP08|Allarme Meteo|| WPUPCFSP09|Avviso Prossimit Stazione Tracciata|| # # Track Stazione WPUPTSP001|Segui Stazione|| WPUPTSP002|Segui Nominativo|| WPUPTSP003|Corrispondenza a caso|| WPUPTSP004|Corrispondenza Esatta|| WPUPTSP005|Segui ora!|| WPUPTSP006|Annulla operazione|| WPUPTSP007|Scarica tracciato|| WPUPTSP008|Nominativo|| WPUPTSP009|Percorso iniziato (ore fa)|| WPUPTSP010|Durata percorso (ore)|| # #Messages WPUPMSB001|Casella messaggi %d|| WPUPMSB002|Casella messaggi a gruppo %d|| WPUPMSB003|Nominativi stazioni:|| WPUPMSB004|Nominativo gruppo:|| WPUPMSB005|Nuovo/Refresh nominativo|| WPUPMSB006|Nuovo gruppo|| WPUPMSB007|Cancella storico Msg|| WPUPMSB008|Messaggio:|| WPUPMSB009|Invia ora!|| WPUPMSB010|Percorso:|| WPUPMSB011|Cancella Msg in attesa|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # #Auto Reply WPUPARM001|Cambia risposta automatica|| WPUPARM002|Risposta:|| # #Help Index WPUPHPI001|Indice guida|| WPUPHPI002|Visualizza|| # #Stazione Info popup WPUPSTI000|Oggetto Inserito da: %s|| WPUPSTI001|Informazioni stazione|| WPUPSTI002|Invia messaggio|| WPUPSTI003|Cerca nel Database FCC|| WPUPSTI004|Cerca nel Database RFC|| WPUPSTI005|Pacchetti recevuti: %d Ultima stazione ascoltata: || WPUPSTI006|Ascoltata dal TNC sulla periferica %d, || WPUPSTI007|Ascoltata || WPUPSTI008|Ascoltata l'ultima volta in locale|| WPUPSTI009|Ascoltata l'ultima volta dal TNC, periferica %d|| WPUPSTI010|Ascoltata l'ultima volta da Internet sulla periferica %d|| WPUPSTI011|ultima via File|| WPUPSTI012|Ascoltata l'ultima volta via Unknown|| WPUPSTI013|, e ha cambiato posizione|| WPUPSTI014|Potenza attuale:|| WPUPSTI016|Altitudine: %.0f%s|| WPUPSTI017| Direzione: %s || WPUPSTI018| Velocit: %.1f km/ora|| WPUPSTI019| Velocit: %.1f miglia/ora|| WPUPSTI020|%0.1f Miglia|| WPUPSTI021|%0.1f chilometri|| WPUPSTI022|Distanza dalla mia Stazione: %s, direzione rispetto alla mia stazione: %s|| WPUPSTI023|Ultima posizione: || WPUPSTI024|Dati meteorologici %c:%s|| WPUPSTI025|Direzione del vento: %s, Velocit: %03d km/ora|| WPUPSTI026|Direzione del vento: %s, Velocit: %s miglia/ora|| WPUPSTI027| Picco: %03d km/ora|| WPUPSTI028| Picco: %s MPH|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031|Umidit: %s%% || WPUPSTI032|Humidex: %02.1fC || WPUPSTI033|Pressione: %s mb || WPUPSTI034|Neve: %0.1f (cm/24ora) || WPUPSTI035|Neve: %0.0f (inch/24ora) || WPUPSTI036|Pioggia: || WPUPSTI037|%0.2f (mm/ora) || WPUPSTI038|%0.2f (pollici/ora) || WPUPSTI039|%0.2f (mm/Giorno) || WPUPSTI040|%0.2f (pollici/Giorno) || WPUPSTI041|%0.2f (mm/da mezzanotte)|| WPUPSTI042|%0.2f (pollici/da mezzanotte)|| WPUPSTI043|Percorso dei dati: %s|| WPUPSTI044|Commenti %02d/%02d %02d:%02d : %s|| WPUPSTI045|Elimina traccia|| WPUPSTI046|Pioggia totale: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (pollici)|| WPUPSTI049|Richiesta traccia|| WPUPSTI050|Richiesta Messaggi non Riconosciuti|| WPUPSTI051|Richiesta Stazioni Dirette|| WPUPSTI052|Richiesta Versione Stazione|| WPUPSTI053|Modifica Oggetto/Entit|| WPUPSTI054|Registra Tracciato|| WPUPSTI055|Ripetuto da:|| WPUPSTI056|Abilita Aggiornamento Automatico|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Puntamento DF: %s|| WPUPSTI059|Stato %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp Carburante: %02.1fC || WPUPSTI061|Temp Carburante: %sF || WPUPSTI062|Umidit Carburante: %s%% || WPUPSTI063|Pressione: %0.2f in Hg|| WPUPSTI064|Ricevi avvisi NWS|| WPUPSTI065|Chiamata tattica: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC Call Look up STIFCC0001|Ricerca nel database FCC|| STIFCC0002|Ricerca nel database RAC|| STIFCC0003|Nome:|| STIFCC0004|Indirizzo:|| STIFCC0005|Citt:|| STIFCC0006|Stato:|| STIFCC0007|Codice Postale:|| STIFCC0008|Informazioni base|| STIFCC0009|Informazioni avanzate || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC Call Look up STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # #Band open message UMBNDO0001|ad una distanza di|| # #Universal Options UNIOP00001|OK|| UNIOP00002|Annulla|| UNIOP00003|Chiudi|| UNIOP00004|Miglia|| UNIOP00005|Chilometri|| UNIOP00006|Periferica|| UNIOP00007|Aggiungi|| UNIOP00008|Cancella|| UNIOP00009|Propriet|| UNIOP00010|Consenti la trasmissione?|| UNIOP00011|Attiva all'avvio?|| UNIOP00012|km/ora|| UNIOP00013|miglia/ora|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pollici|| UNIOP00018|mm/Giorno|| UNIOP00019|pollici/Giorno|| UNIOP00020|mm/ora|| UNIOP00021|pollici/ora|| UNIOP00022|mm da mezzanotte|| UNIOP00023|pollici da mezzanotte|| UNIOP00024|gradi|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Regolare il tempo del sistema dal GPS|| UNIOP00030|Ripeti?|| UNIOP00031|m|| UNIOP00032|Apply||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Scelta Stazione|| # #DISPLAY Meteo ALERT WPUPWXA001|Allarmi Meteo|| WPUPWXA002|Lista allarmi meteo|| # # Configure Interfaces WPUPCIF001|Interfacce installate|| WPUPCIF002|Scelta tipo di interfaccia|| # #Configure AX.25 WPUPCAX001|Configura TNC AX.25|| WPUPCAX002|Periferica TNC AX.25|| # #Interface device names IFDNL00000|Nessuna|| IFDNL00001|TNC Seriale|| IFDNL00002|TNC Seriale con GPS connesso con cavo HSP|| IFDNL00003|GPS Seriale|| IFDNL00004|Meteo Seriale|| IFDNL00005|Server Internet|| IFDNL00006|TNC AX.25|| IFDNL00007|GPS in rete (via gpsd)|| IFDNL00008|Meteo in rete|| IFDNL00009|TNC Seriale con GPS connesso con cavo AUX|| IFDNL00010|TNC Seriale in KISS|| IFDNL00011|Database su Rete (Non ancora Implementato)|| IFDNL00012|AGWPE Via Rete|| IFDNL00013|TNC Seriale in Multi-Port KISS|| IFDNL00014|SQL Database (Experimental)|| # #Interface device info IFDIN00000|%s %2d %s sulla seriale %s %s|| IFDIN00001|%s %2d %s connettendo %s:%d %s|| IFDIN00002|%s %2d %s usa la porta %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| Disattiva || IFDIN00007| Attiva || IFDIN00008| ERRORE || IFDIN00009|SCONOSCIUTO|| # #Interface control IFPUPCT000|Controllo interfaccia|| IFPUPCT001|Avvia|| IFPUPCT002|Ferma|| IFPUPCT003|Avvia Tutte|| IFPUPCT004|Ferma Tutte|| # #IGate control IGPUPCF000|Opzioni Gateway|| IGPUPCF001|Disabilita tutto il traffico per il gateway|| IGPUPCF002|Permetti solo il traffico verso il Gateway|| IGPUPCF003|Permetti il traffico Radio->Rete e Rete->Radio|| IGPUPCF004|Igate -> RF Path || # #Stazione Meteo WXPUPSI000|Stazione Meteo|| WXPUPSI001|Tipo di Stazione meteo|| WXPUPSI002|Dati correnti|| WXPUPSI003|Direzione del vento|| WXPUPSI004|Velocit del vento|| WXPUPSI005|Raffiche|| WXPUPSI006|Temperatura|| WXPUPSI007|Pioggia totale|| WXPUPSI008|Pioggia totale odierna|| WXPUPSI009|Pressione|| WXPUPSI010|Umidit|| WXPUPSI011|Peet Bros ULTIMETER 2000 (Modalit Data Logging)|| WXPUPSI012|Peet Bros ULTIMETER II || WXPUPSI013|Peet Bros ULTIMETER 2000 (Modalit Packet)|| WXPUPSI014|Pioggia (ultima ora)|| WXPUPSI015|Pioggia (24 ore)|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Temp.rugiada|| WXPUPSI019|Velocit massima vento|| WXPUPSI020|Vento Freddo|| WXPUPSI021|Indice Termico|| WXPUPSI022|Pressione ultime 3 Ore|| WXPUPSI023|Temp. Massima|| WXPUPSI024|Temp. Minima|| WXPUPSI025|Radio Shack Meteo-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Stn Lists LHPUPNI000|Lista stazioni|| LHPUPNI001|Lista stazioni mobili|| LHPUPNI002|Lista stazioni meteo|| LHPUPNI003|Lista stazioni locali|| LHPUPNI004|Lista ultime stazioni|| LHPUPNI005|Oggetti e Dettagli|| LHPUPNI006|Oggetti e Dettagli personali|| LHPUPNI010|#|| LHPUPNI011|Sigla|| LHPUPNI012|#Pack|| LHPUPNI013|Data e Ora|| LHPUPNI014|Percorso|| LHPUPNI015|PHG|| LHPUPNI016|Commenti|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Latitudine|| LHPUPNI104|Longitudine|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temperatura|| LHPUPNI204|Umidit|| LHPUPNI205|Pressione|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon or UTM|| # # Maps Meteo Alert styles PULDNMAT01|Mostra allarmi sopra altre mappe|| PULDNMAT02|Mostra allarmi sotto altre mappe|| # # Error/popup messages POPEM00001|Localizza errore!|| POPEM00002|Stazione %s non trovata!|| POPEM00003|Errore nell'inseguimento!|| POPEM00004|Errore dell'interfaccia!|| POPEM00005|Nome della porta %s non valido|| POPEM00006|Nome della porta AX.25 %s non valido|| POPEM00007|Nominativo %s non valido|| POPEM00008|Destinazione AX.25, Nominativo o digipeater errati|| POPEM00009|Impossibile aprire la porta AX.25, %s|| POPEM00010|Non posso collegare la porta AX.25, %s|| POPEM00011|Connessione al nominativo AX.25 non riuscita, %s|| POPEM00012|AX.25 errore sull'uscita di UI|| POPEM00013|AX.25: problema nel file axports|| POPEM00014|AX.25: %s|| POPEM00015|Errore nell'apertura dell'interfaccia %d (Fallito)|| POPEM00016|Errore nell'apertura dell'interfaccia %d (Tempo scaduto)|| POPEM00017|Non sono disponibili altre interfacce!|| POPEM00018|Richiesta dati - Messaggio su linea singola| POPEM00019|La trasmissione dalla porta %d disattivata| POPEM00020|Errore del Database!| POPEM00021|Supporto AX.25 non compilato in Xastir!|| POPEM00022|Errore di input!| POPEM00023|Non e' stato specificato alcun nome per questo punto!| POPEM00024|Il nome assegnato al punto gi in uso!| POPEM00025|Non trovato!|| POPEM00026|Il tracciamento verr visualizzato quando appare|| POPEM00027|Informazione non completa. Campi vuoti?|| POPEM00028|Non possibile aprire il file|| POPEM00029|Trovato!|| POPEM00030|Simbolo Stazione Meteo|| POPEM00031|Cambiato al simbolo Meteo '/_', altre opzioni: '\_' '/W' e '\W'|| POPEM00032|Attenzione: Stai usando il simbolo Meteo del Servizio Nazionale!|| POPEM00033|Nessun dato GPS!|| POPEM00034|Disabilito TX Mia Posizione fino all'arrivo dei dati GPS!|| POPEM00035|Attenzione|| POPEM00036|Nota|| POPEM00037|presente interfaccia HSP: l'intervallo di lettura del GPS viene aumentato|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Posizione Mappa|| JMLPO00002|Vai!|| JMLPO00003|Nome del nuovo punto:|| # # Bollettini BULMW00001|Bollettini|| BULMW00002|Raggio (0, senza limite)|| BULMW00003|Cambia raggio|| # # All Message Traffic AMTMW00001|Traffico di tutti i messaggi|| AMTMW00002|Raggio (0, senza limite)|| # # Speech Strings SPCHSTR001|chilometri|| SPCHSTR002|metri|| SPCHSTR003|miglia|| SPCHSTR004|yards|| SPCHSTR005|%s, distanza %d %s.|| SPCHSTR006|%s, distanza %.1f %s.|| SPCHSTR007|%s, distanza %d %s %s %s.|| SPCHSTR008|%s, distanza %.1f %s %s %s.|| SPCHSTR009|Nuovo Allarme Meteo|| SPCHSTR010|Nuovo Nominativo|| SPCHSTR011|Ascoltato, D X, %s, alla distanza di %.1f %s|| # SPCHDIRN00|nord di|| SPCHDIRS00|sud di|| SPCHDIRE00|est di|| SPCHDIRW00|ovest di|| SPCHDIRNE0|nordest di|| SPCHDIRNW0|nordovest di|| SPCHDIRSE0|sudest di|| SPCHDIRSW0|sudovest di|| # # Symbol Selection Dialog SYMSEL0001|Selezione simbolo|| SYMSEL0002|Tabella Primaria|| SYMSEL0003|Tabella Secondaria|| # # Finestra di dialogo proprieta di stampa PRINT0001|Propriet di Stampa|| PRINT0002|Formato Carta|| PRINT0003|Ruota Immagine automaticamente PRINT0004|Ruota Immagine di 90 in senso antiorario|| PRINT0005|Ridimensiona immagine|| PRINT0006|Scala:|| PRINT0007|Sfondo bianco|| PRINT0008|Stampa in bianco e nero|| PRINT0016|Inverti i colori|| PRINT0009|Risoluzione del file Postscript:|| PRINT0010|Anteprima|| PRINT0011|Stampa su file|| PRINT0012|Elaborazione immagine su file...|| PRINT0013|Conversione in Postscript...|| PRINT0014|Fine elaborazione file.|| PRINT0015|Stato del processo di stampa|| # # Finestra di dialogo proprieta di stampa PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Finestra di dialogo localizza elemento mappa FEATURE001|Nome:|| FEATURE002|Stato/Provincia:|| FEATURE003|Contea:|| FEATURE004|Quadrante:|| FEATURE005|Tipo:|| FEATURE006|File GNIS:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Coordinate Calculator Dialog COORD001|Calcolo Coordinate|| COORD002|Calc|| COORD003|Calcola|| COORD004|Cancella|| COORD005|UTM|| COORD006|Latitudine o|| COORD007|Longitudine o|| COORD008|Zona|| COORD009|UTM Est|| COORD010|UTM Nord|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Smart Beaconing Dialog SMARTB001|SmartBeaconing|| SMARTB002|Tasso Alto (secs):|| SMARTB003|Alta Velocit (mph):|| SMARTB004|Alta Velocit (kmh):|| SMARTB005|Tasso Basso (mins):|| SMARTB006|Bassa Velocit (mph):|| SMARTB007|Bassa Velocit (kmh):|| SMARTB008|Giro Minimo (gradi):|| SMARTB009|Inclinazione Giro:|| SMARTB010|Tempo di Attesa (secondi):|| SMARTB011|Abilita SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Impostazione Correzione Gamma|| GAMMA002|Correzione Gamma|| # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Minuscolo|| MAPFONT004|Map Font Piccolo|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distance/Bearing on status line PULDNDB001|Stato Distanza/Puntamento|| # # # GPS Transfer Operations GPS001|Trasferimento GPS|| GPS002|Nome File|| GPS003|Seleziona Colore|| GPS004|Rosso|| GPS005|Verde|| GPS006|Nero|| GPS007|Bianco|| GPS008|Arancione|| GPS009|Blu|| GPS010|Giallo|| GPS011|Viola|| # # # Map Properties Dialog MAPP001|Propriet Mappa|| MAPP002|Max Min Disegna Mappa USGS Auto|| MAPP003|Zoom Zoom Livello Riempi DRG Map Percorso/Nome File|| MAPP004|Cambia Livello->|| MAPP005|Riempito->|| MAPP006|Si|| MAPP007|No|| MAPP008|Automappe->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Giorno|| TIME002|Giorni|| TIME003|Ora|| TIME004|Ore|| TIME005|Minuto|| TIME006|Minuti|| TIME007|Secondo|| TIME008|Secondi|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/language-Portuguese.sys000066400000000000000000001175171501463444000223120ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # Este e o ficheiro da lingua Portuguesa, sem pontuacao, usado para todas as consultas # no Xastir. # # Criador : por CT1DRB, David Quental # # Linhas de comentarios com o simbolo de cardinal a frente sao ignorados # O formato do ficheiro e como segue: # Id (10 caracteres alfa numerico)|(Cadeia associada com id)|TeclaRapida|#comentario # # AVISO: # Algumas cadeias de letras conteem comandos de formato como %s e %d, voce nao # deve mudar isso. Cadeias de formatos errados poderao produzir um segfault! # # Menu principal MENUTB0001|Ficheiro|F| MENUTB0002|Visualizar|V| MENUTB0004|Mapas|M| MENUTB0005|Estacoes|s| MENUTB0006|Mensagens|g| MENUTB0010|Interfaces|I| MENUTB0009|Ajuda|j| # # Menu de ficheiro PULDNFI001|Configurar|C| PULDNFI002|Abrir o log|B| PULDNFI003|Testar|P| PULDNFI004|Sair|S| PULDNFI007|Muda nivel de debug|D| PULDNFI010|Abre o log do TNC|T| PULDNFI011|Abre o log da internet|I| PULDNFI012|Abre o log da I-Gate|G| PULDNFI013|Abre o log do tempo|W| PULDNFI014|Activa PNG instantanea|| PULDNFI015|Imprimir mapa|P| PULDNFI016|KML Snapshots|| # # Menu visor PULDNVI001|Boletins|B| PULDNVI002|Trafego recebido|D| PULDNVI003|Estacoes moveis|m| PULDNVI004|Todas as estacoes|e| PULDNVI009|Estacoes locais|t| PULDNVI012|Ultimas estacoes|U| PULDNVI005|Estacoes meteorologicas|t| PULDNVI008|A sua estacao meteorologica|s| PULDNVI007|Alerta de tempo|A| PULDNVI011|Trafego de mensagens|f| PULDNVI013|Aviso|v| PULDNVI014|Programar aviso|r| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Menu de configuracao PULDNCF004|Estao|E| PULDNCF001|Pre-definidos|P| PULDNCF003|Momento certo|T| PULDNCF002|Sistema de coordenadas|S| PULDNCF006|Audio dos alarmes|A| PULDNCF007|Sintetizador de voz|S| PULDNCF008|Guardar configuracao!|G| # (Unidades ver PULDNDP006) # # Menu de mapas PULDNMP001|Seleccionar mapas|M| PULDNMP012|Saltar para um local do mapa|S| PULDNMP014|Localizar faixa no mapa|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Desactivar todos os mapas|| PULDNMP002|Activar auto mapas|| PULDNMP003|Activar as coordenadas do mapa|| PULDNMP004|Niveis dos mapas|| PULDNMP010|Etiquetas dos mapas|| PULDNMP009|Activar areas coloridas|| PULDNMP007|Activar os alertas de WX|| PULDNMP005|Cor de fundo|C| PULDNMP006|Estilo de texto da estacao|E| PULDNMP026|Estilo da linha de fora do icon|O| PULDNMP011|Menu indicador do rato|r| PULDNMP008|Intensidade do mapa|I| PULDNMP021|Auto Map - desactivar raster mapas|| PULDNMP022|Indexar mapas no comeco|| PULDNMP023|Index: Acrescentar mapas novos|A| PULDNMP024|Index: Reindexar os mapas TODOS|R| PULDNMP025|Fonts|| PULDNMP015|Seleccionar a fonte do X|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Find Address|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # # Selecao de mapas WPUPMCP001|Escolher mapa|| PULDNMMC01|Limpar|N| PULDNMMC02|Vectores|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Direccoes expandidas||| PULDNMMC07|Selecionados dirs/mapas:|| PULDNMMC08|Limpar dirs|C| PULDNMMC09|Seleccionar tudo|S| # # Cores de fundo do mapa PULDNMBC01|Cinzento|| PULDNMBC02|Rosado mistico|| PULDNMBC03|Azul marinho|| PULDNMBC04|Azul escuro|| PULDNMBC05|Med. verde mar|| PULDNMBC06|Verde palido|| PULDNMBC07|Dourado palido|| PULDNMBC08|Dourado amarelado|| PULDNMBC09|Castanho rosado|| PULDNMBC10|Vermelho escuro|| PULDNMBC11|Branco|| PULDNMBC12|Preto|| # # Mapas de estacoes e estilos das etiquetas PULDNMSL01|Fundo negro|| PULDNMSL02|Fundo cinzento|| PULDNMSL03|Texto em negro|T| PULDNMSL04|DropShadow|| # # PullDown "Estilo da linha de fora do icon" PULDNMIO01|Nao ha limite|N| PULDNMIO02|Limite preto|B| PULDNMIO03|Limite cinzento|G| PULDNMIO04|Limite brando|W| # # Switches ON/OFF/Curto PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Curto|| # # Menu de mostragem de estacoes PULDNDP014|Localizar estacao|L| PULDNDP001|Rastrear estacao|R| PULDNDP022|Tirar o rasto de Findu|F| PULDNDP032|Filtrar dados|| PULDNDP040|Escolher nada|| PULDNDP041|Escolher meu|| PULDNDP042|Escolher TNC|| PULDNDP027|- Mostrar estacoes direct|| PULDNDP043|- Escolher via digi|| PULDNDP034|Mostrar estacoes net|| PULDNDP019|Mostrar infos expiradas|| PULDNDP044|Mostrar estacoes|| PULDNDP028|- Mostrar estacoes fixas|| PULDNDP029|- Mostrar estacoes moveis|| PULDNDP030|- Mostrar estacoes de tempo|| PULDNDP053| - Seleccionar estacoes CWOP WX|| PULDNDP045|Mostrar objectos/items|| PULDNDP026|- Mostrar objectos/items metereologicos|| PULDNDP039|- Mostrar objectos de medida de agua/Items|| PULDNDP031|- Mostrar outros objectos/Items|| PULDNDP057|- Selecionar objetos avio / Itens|| PULDNDP058|- Seleccione navio Objetos / Itens|| PULDNDP033|Filtrar monitor|| PULDNDP010|Mostrar indicativo|i| PULDNDP012|Mostrar simbolos|D| PULDNDP011|- Simbolos rodados|S| PULDNDP007|Rastos de estacoes|R| PULDNDP003|Mostrar curso|c| PULDNDP004|Mostrar velocidade|v| PULDNDP017|- Mostrar velocidade baixa|| PULDNDP002|Mostrar altura|a| PULDNDP009|Mostrar info do tempo|t| PULDNDP046|- Mostrar texto do tempo|| PULDNDP018|-- Mostrar so a temperatura|| PULDNDP047|- Mostrar intensidade do vento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Ambiguidade de posicao|| PULDNDP008|Estacao potencia/ganho|p| PULDNDP021|- Activar por defeito pot/ganho|| PULDNDP020|- Activar movel pot/ganho|| PULDNDP023|Mostrar circulos DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activar Dead-Reckoning|| PULDNDP036|- Activar arco Dead-Reckoning|| PULDNDP037|- Activar curso Dead-Reckoning|| PULDNDP038|- Activar simbolo Dead-Reckoning|| PULDNDP005|Mostrar dist/curso|d| PULDNDP024|Mostrar o ultimo reporte horario|| PULDNDP015|Anular todas as estacoes|A| PULDNDP016|Limpar rastos|L| PULDNDP025|Limpar historia de objecto/item|| PULDNDP048|Recarregar objecto/historia de item|| PULDNDP049|Limpar todos os indicativos tacticos|| PULDNDP050|Limpar a historia dos indicativos tacticos|| PULDNDP051|Seleccionar unicamente indicativos tacticos|| PULDNDP052|- Etiquetas de pontos de pista|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Inglesa/metrica PULDNUT001|Activar unidades Inglesas|| PULDNUT002|Metrica|| # # Menu de mensagens PULDNMG001|Enviar mensagem a|E| PULDNMG002|Abrir mensagens de grupos|g| PULDNMG003|Anular todas as mensagens a enviar|A| PULDQUS001|Pergunta geral a estacoes|r| PULDQUS002|Pergunta a estacoes I-Gate|I| PULDQUS003|Pergunta a estacoes WX|W| PULDNMG004|Modificar mensagem de resposta automatica|f| PULDNMG005|Activar mensagem de resposta automatica|A| PULDNMG006|Modo de reconhecimento por satelite|M| PULDNMG007|Show Pending Messages|P| # # Menu de interfaces PULDNTNT04|Interface Control|| PULDNTNT03|Desactivar transmitir: TODOS|| PULDNTNT05|Desactivar transmitir: A minha posicao|| PULDNTNT06|Desactivar transmitir: Objectos/Artigos|| PULDNTNT11|Activar porta de server|| PULDNTNT01|Transmitir agora..!|T| PULDNTNT07|Buscar rastro de GPS|F| PULDNTNT08|Buscar rotas de GPS|R| PULDNTNT09|Buscar waypoints de GPS|W| PULDNTNT10|Buscar pontos da Garmin RINO|G| # # Menu de ajuda PULDNHEL01|Acerca de|A| PULDNHEL02|Index de ajuda|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # Menu do rato POPUPMA001|Opcoes|| POPUPMA00c|Centro|| POPUPMA015|Info da estacao|| POPUPMA002|Aproximar|A| POPUPMA003|Afastar|f| POPUPMA004|Nivel de focagem|N| POPUPMA005|Nivel 1|1| POPUPMA006|Nivel 16|6| POPUPMA007|Nivel 64|4| POPUPMA008|Nivel 256|2| POPUPMA009|Nivel 1024|0| POPUPMA010|Nivel 8192|8| POPUPMA017|O mundo inteiro|E| POPUPMA016|Ultima pos/focagem do mapa|P| POPUPMA018|Criar objecto/artigo|C| POPUPMA019|Modificar objecto/artigo|M| POPUPMA025|Mover aqui a minha estacao|H| POPUPMA011|Ir para cima|u| POPUPMA012|Ir para baixo|d| POPUPMA013|Ir para a esquerda|l| POPUPMA014|Ir para a direita|r| POPUPMA020|Medida|| POPUPMA021|Movimento|| POPUPMA022|Siga-me|| POPUPMA023|Modificadores encontrados!|| POPUPMA024|Por favor desligue as teclas CapsLock/NumLock/ScrollLock/outros|| POPUPMA026|Centro e Zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Desenhar objectos CAD|| POPUPMA030|Draw|| POPUPMA031|Fechar poligono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Menu dos estados das linhas de etiquetas BBARZM0001|Foco %s|| BBARZM0002|Foco %s Tr|| BBARSTH001|%d/%d estacoes|| BBARSTA000|%-9s novo objecto!|| BBARSTA001|%-9s nova estacao!|| BBARSTA002|%s|| BBARSTA003|Carregando mapas...|| BBARSTA004|Mapas carregados...|| BBARSTA005|Graduacao lat/long esta ON|| BBARSTA006|Graduacao lat/long esta OFF|| BBARSTA007|O uso dos auto mapas, esta ON|| BBARSTA008|O uso dos auto mapas, esta OFF|| BBARSTA009|Os niveis do mapa estao ON|| BBARSTA010|Os niveis do mapa estao OFF|| BBARSTA011|A mensagem de resposta automatica esta OFF!|| BBARSTA012|Ficheiro criado..|| BBARSTA013|Abrindo porta GPS|| BBARSTA014|Fechando porta GPS|| BBARSTA015|Obtendo a string do GPS RMC|| BBARSTA016|Obtendo a string do GPS GGA|| BBARSTA017|Rede desligada do servidor|| BBARSTA018|Ligacao fechada por excesso de tempo!|| BBARSTA019|A procurar servidor %s|| BBARSTA020|Ligado a %s|| BBARSTA021|Falha na ligacao rede!|| BBARSTA022|Pode nao ligar ao socket!|| BBARSTA023|Nao ha IP para o servidor!|| BBARSTA024|Nao ha servidor especificado|| BBARSTA025|Servidor encontrado, a ligar %d|| BBARSTA026|Esperando por infos do GPS via HSP..|| BBARSTA027|Limpando as infos de HSP obtidos do TNC..|| BBARSTA028|Carregando %s|| BBARSTA029|Abrindo porta WX|| BBARSTA030|A fechar porta WX|| BBARSTA031|A procura o servidor %d|| BBARSTA032|Infos de WX descodificados|| BBARSTA033|Eco desde o digipeater|| BBARSTA034|Carregando mapas de alerta WX|| BBARSTA035|Esperando por dados do GPS via AUX..|| BBARSTA036|Limpando AUX para obter dados do TNC..|| BBARSTA037|Dados do GPS completos|| BBARSTA038|Posicao alterada na minha estacao|| BBARSTA039|Indexando %s|| BBARSTA040|Estacao de radioamador de APRS(tm) %s|| BBARSTA041|Esperando pela data do GPS..|| BBARSTA042|Transmitindo objectos/items|| BBARSTA043|Registando|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # Visualizao do trafego de packet WPUPDPD001|Visualizacao do trafego|| WPUPDPD002|So dados do TNC|| WPUPDPD003|So dados da rede|| WPUPDPD004|Dados do TNC e da rede|| WPUPDPD005|TNC|| WPUPDPD006|REDE|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # Localizar estacao WPUPLSP001|Localizar estacao|| WPUPLSP002|Localizar indicativo|| WPUPLSP003|Maiscula/minuscula|M| WPUPLSP004|Exacta|E| WPUPLSP005|Localizar agora!|A| WPUPLSP006|Localizar emergencia!|| WPUPLSP007|FCC/RAC Lookup|| # # Configurar predefinidos WPUPCFD001|Configurar valores pre-definidos|| WPUPCFD002|desde que intervalo de tempo sera considerada uma estacao antiga?|| WPUPCFD003|15 minutos|1| WPUPCFD004|30 minutos|3| WPUPCFD005|45 minutos|4| WPUPCFD006|1 hora|H| WPUPCFD007|90 minutos|9| WPUPCFD008|2 horas|2| WPUPCFD009|desde que intervalo de tempo a estacao nao sera mostrada?|| WPUPCFD010|6 horas|6| WPUPCFD011|12 horas|o| WPUPCFD012|1 Dia|D| WPUPCFD013|2 Dias|s| WPUPCFD014|1 semana|n| WPUPCFD015|Opcao modo de transmissao da estacao|| WPUPCFD016|Estacao fixa|F| WPUPCFD017|Estacao movel c/hora local|l| WPUPCFD018|Estacao movel c/data-hora zulu|z| WPUPCFD019|Estacao movel c/horas-segundos zulu|u| WPUPCFD021|Posicao da estacao c/tempo|t| WPUPCFD022|Posicao da estacao, data-hora zulu e tempo|d| WPUPCFD023|Transmitir infos WX em Raw?|| WPUPCFD024|Comprimir objecto/item durante a transmissao?|| WPUPCFD025|Activar rede alternativa?|A| WPUPCFD026|Enviar reportes de posicao em que intervalos?|| WPUPCFD027|Pop up de novos boletins|| WPUPCFD028|Avisar se teclas foram modificadas|| WPUPCFD029|Ver boletins de distancia zero|| WPUPCFD030|Desactivar dupe-checks de posit|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configurar - momento certo" WPUPCFTM01|Configurar momento certo||| WPUPCFTM02|Intervalo Posit TX (min)|| WPUPCFTM03|Tempo de estacao fantasma (min)|| WPUPCFTM04|Max Intervalo TX objecto/item (min)|| WPUPCFTM05|Tempo para limpar estacao (horas)|| WPUPCFTM06|Intervalo para verificar GPS (seg)|| WPUPCFTM07|Tempo para apagar estacao (dias)|| WPUPCFTM08|Tempo limite para dead-reckoning (min)|| WPUPCFTM09|Serie de atraso de inter-char (ms)|| WPUPCFTM10|Novo tempo de pista (min)|| WPUPCFTM11|Novo intervado de pista (degrees)|| WPUPCFTM12|RINO -> Intervalo de objectos (min), 0 = Desactivado|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Sistema de configuracao de coordenadas" WPUPCFC001|Sistema de configuracao de coordenadas|| WPUPCFC002|Sistema de selecao de coordenadas|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM com zonas especiais|| # # Configurar GPS WPUPCFG001|Configurar GPS|| WPUPCFG003|Porta exclusiva de GPS|| WPUPCFG002|Usar posicao GPS?|| WPUPCFG004|opcoes do GPS|| WPUPCFG005|GPS exclusivo|| WPUPCFG006|TNC ligado a GPS (cabo HSP)|| WPUPCFG007|TNC ligado a GPS usando CTL-E|| WPUPCFG008|GPS tempo (a mostrar cada)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 minutos|| WPUPCFG014|5 minutos|| WPUPCFG015|10 minutos|| WPUPCFG016|Rede ligada ao GPS|| WPUPCFG017|Servidor GPSD|| WPUPCFG018|Porta GPSD|| WPUPCFG019|Rede GPS via GPSD|| WPUPCFG020|Voltar a ligar quando falhar?|| WPUPCFG021|Rede ligada a WX|| WPUPCFG022|Servidor WX|| WPUPCFG023|Porta WX|| # # Configurar TNC (bauds tambem sao para WX) WPUPCFT001|Configurar TNC|| WPUPCFT002|Usar TNC?|| WPUPCFT003|Porta TNC|| WPUPCFT004|Velocidade da porta|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Rota do UnProto|| WPUPCFT012|Rota 1: %s via || WPUPCFT013|Rota 2: %s via || WPUPCFT014|Rota 3: %s via || WPUPCFT015|Modo da porta|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurar o TNC c/HSP GPS|| WPUPCFT024|Tipo de data|| WPUPCFT025|Auto deteccao|| WPUPCFT026|Tipo Binario|| WPUPCFT027|Tipo ASCII|| WPUPCFT028|Configurar TNC com GPS AUX|| WPUPCFT029|Configurar TNC com ENUM INVALIDO: %d|| WPUPCFT030|Configurar o TNC em KISS|| WPUPCFT031|Ficheiros de configuracao do TNC|| WPUPCFT032|Nome do ficheiro de definicoes do TNC|| WPUPCFT033|Nome do ficheiro de fecho do TNC|| WPUPCFT034|Parametros do KISS|| WPUPCFT035|TXDelay (10 unidades de ms)|| WPUPCFT036|Persistencia (0 a 255)|| WPUPCFT037|SlotTime (10 unidades de ms)|| WPUPCFT038|TxTail (10 unidades de ms)|| WPUPCFT039|Duplex completo (Full Duplex)|| WPUPCFT040|Configurar o TNC em Multi-Port KISS|| WPUPCFT041|Porta radio|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # Configurar a porta da estacao meteorologica WPUPCFWX01|Configurar a porta da estacao meteorologica|| WPUPCFWX02|Dispositivo da estacao meteorologica|| WPUPCFWX03|Correccao da medida de chuva (Definicoes globais)|| WPUPCFWX04|.1 polegadas/2.5mm|| WPUPCFWX05|.01 polegadas/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Nao corrigido|| # # Configurar a estacao WPUPCFS001|Configurar a estacao|| WPUPCFS002|Indicativo|| WPUPCFS003|Latitude|| WPUPCFS004|grd|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Longitude|| WPUPCFS008|(E/W)|| WPUPCFS009|Simbolo da estacao|| WPUPCFS010|Grupo/sobreposto|| WPUPCFS011|Simbolo|| WPUPCFS028|Seleccione|| WPUPCFS012|Potencia - Altura (HAAT) - Ganho e direccao|| WPUPCFS013|Desactive PHG|| WPUPCFS014|Altura da antena|| WPUPCFS015|Ganho da antena|| WPUPCFS016|Omni|| WPUPCFS017|Comentarios:|| WPUPCFS018|Posicao ambigua|| WPUPCFS019|Nenhuma|| WPUPCFS020|.11 milha|| WPUPCFS021|1.15 milhas|| WPUPCFS022|11.51 milhas|| WPUPCFS023|69.09 milhas|| WPUPCFS024|.18 quilometro|| WPUPCFS025|1.85 quilometros|| WPUPCFS026|18.53 quilometros|| WPUPCFS027|111.19 quilometros|| WPUPCFS029|Enviar posits comprimidas|C| # # Dialogo de Objeto/Artigo POPUPOB001|Objecto/artigo|| POPUPOB002|Nome:|| POPUPOB003|Criar novo objecto|| POPUPOB004|Apagar objeto|| POPUPOB005|Modificar objecto|| POPUPOB006|Criar novo artigo|| POPUPOB007|Area do objeto|| POPUPOB008|Activar area do objecto|| POPUPOB009|Cor luminosa|| POPUPOB010|Area colorida|| POPUPOB011|Circulo|| POPUPOB012|Linha-direita '/'|| POPUPOB013|Linha-esquerda '\'|| POPUPOB014|Triangulo|| POPUPOB015|Rectangulo|| POPUPOB016|Negro|| POPUPOB017|Azul|| POPUPOB018|Verde|| POPUPOB019|Cinzento|| POPUPOB020|Vermelho|| POPUPOB021|Violeta|| POPUPOB022|Amarelo|| POPUPOB023|Cinzento|| POPUPOB024|Compensar em cima:|| POPUPOB025|Compensar a esq.(Excepto '/'):|| POPUPOB026|Corredor:|| POPUPOB027|Opcoes gerais|| POPUPOB028|Situacao|| POPUPOB029|Activar letreiro|| POPUPOB030|Data:|| POPUPOB031|Letreiro objecto|| POPUPOB032|Activar compressao|| POPUPOB033|Apagar artigo|| POPUPOB034|Modificar artigo|| POPUPOB035|Altitude (Pes):|| POPUPOB036|Velocidade (nos):|| POPUPOB037|Curso:|| POPUPOB038|DF objecto|| POPUPOB039|Sinal - Altura(HAAT) - Ganho - Direccao|| POPUPOB040|Dirigindo - Amplitude da direccao|| POPUPOB041|Antena omni-direcional|| POPUPOB042|Antena direcional|| POPUPOB043|Inutil|| POPUPOB044|Adoptar objecto|| POPUPOB045|Adoptar item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # Configurar Internet WPUPCFI001|Configurar internet|| WPUPCFI002|Servidor|| WPUPCFI003|Porta|| WPUPCFI004|(Servidores secundarios)|| WPUPCFI005|Servidor1|| WPUPCFI006|Porta1|| WPUPCFI007|Servidor2|| WPUPCFI008|Porta2|| WPUPCFI009|Senha|| WPUPCFI010|(Deixar em branco se nao houver nada)|| WPUPCFI011|Voltar a ligar em caso de falha de rede?|| WPUPCFI012|Correr como num I-Gate?|| WPUPCFI013|Difundir mensagens via TNC quando houver um I-Gate?|| WPUPCFI014|Registo de transacoes do I-Gate?||| WPUPCFI015|Parametros filtrados|| # # Configurar Database WPUPCFID01|Configurar Database (TBD)|| WPUPCFID02|Servidor|| WPUPCFID03|Porta|| WPUPCFID04|(Servidores secundarios)|| WPUPCFID05|Servidor1|| WPUPCFID06|Porta1|| WPUPCFID07|Servidor2|| WPUPCFID08|Porta2|| WPUPCFID09|Senha|| WPUPCFID10|(Deixar em branco se nao houver nada)|| WPUPCFID11|Voltar a ligar em caso de falha de rede?|| WPUPCFID12|Correr como num I-Gate?|| WPUPCFID13|Difundir mensagens via TNC quando houver um I-Gate?|| WPUPCFID14|Log de transacoes do I-Gate?||| WPUPCFID15|Parametros filtrados|| # # PopUp "Configurar AGWPE" WPUPCFIA01|Configurar AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Porta || WPUPCFIA04|(Hosts secundarios)|| WPUPCFIA05|Host1|| WPUPCFIA06|Porta1|| WPUPCFIA07|Host2|| WPUPCFIA08|Porta2|| WPUPCFIA09|Codigo de passagem|| WPUPCFIA10|(Deixar em branco se nao ha nada)|| WPUPCFIA11|Voltar a ligar se houver uma falha da NET?|| WPUPCFIA12|Funcionar como uma I-Gate?|| WPUPCFIA13|Divulgar mensagens via TNC quando estiver na I-Gate?|| WPUPCFIA14|Registo das transacoes I-Gate?|| WPUPCFIA15|Transmitir RadioPort|| # # Configurar Alarmas de Audio WPUPCFA001|Configurar alarme de audio|| WPUPCFA002|Aplicacao audio|| WPUPCFA003|Alarme ON|| WPUPCFA004|Ficheiros de audio|| WPUPCFA005|Nova estacao|| WPUPCFA006|Nova mensagem|| WPUPCFA007|Proximidade|| WPUPCFA008|Banda aberta|| WPUPCFA009|Minima distancia|| WPUPCFA010|Maxima distancia|| WPUPCFA011|Alerta de tempo|| # # Configurar o festival, o sintetizador de voz WPUPCFSP01|Configurar o festival como sintetizador de voz|| WPUPCFSP02|Fixar em 'ON' as opcoes do sintetizador de voz|| WPUPCFSP03|<- Anuncia nova estacao|| WPUPCFSP04|<- Anuncia alerta de nova mensagem|| WPUPCFSP05|<- Anuncia corpo de nova mensagem|| WPUPCFSP06|<- Anuncia a proximidade de estacoes|| WPUPCFSP07|<- Anuncia DX condio de banda aberta|| WPUPCFSP08|<- Anuncia alerta sobre condicoes do tempo|| WPUPCFSP09|Alerta de proximidade da estacao rastreada|| # # Rastreo da estacao WPUPTSP001|Rastrear estacao|| WPUPTSP002|Rastrear indicativo|| WPUPTSP003|Maiscula/minuscula|| WPUPTSP004|Exacto|| WPUPTSP005|Rastrear agora!|| WPUPTSP006|Limpar rastro|| WPUPTSP007|Receber caminho|| WPUPTSP008|Indicativo|| WPUPTSP009|Comecar rasto (horas atras)|| WPUPTSP010|Tamanho do rasto (horas)|| # # Menu de mensagens WPUPMSB001|Enviar mensagem %d|| WPUPMSB002|Enviar mensagem ao grupo %d|| WPUPMSB003|Indicativo de estacao:|| WPUPMSB004|Indicativos de grupos:|| WPUPMSB005|Novo/Refresh indicativo|| WPUPMSB006|Novo grupo|| WPUPMSB007|Limpar histria da mensagem|| WPUPMSB008|Mensagem:|| WPUPMSB009|Enviar agora!|| WPUPMSB010|Encaminhamento:|| WPUPMSB011|Cancelar mensagens pendentes|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # Auto resposta WPUPARM001|Mudar resposta automatica|| WPUPARM002|Reenviar:|| # # Auuda / Indice WPUPHPI001|Indice de ajuda|I| WPUPHPI002|Visualizar|V| # # Informacao da estacao WPUPSTI000|Objecto criado desde: %s|| WPUPSTI001|Info estacao|| WPUPSTI002|Enviar mensagem|| WPUPSTI003|Procurar infos FCC|| WPUPSTI004|Procurar infos RAC|| WPUPSTI005|%d: pacotes recebidos, ultimo recebido na data: || WPUPSTI006|Ouvido via TNC no dispositivo: %d, || WPUPSTI007|Ouvido || WPUPSTI008|Ultima vez via local|| WPUPSTI009|Ultima vez via TNC no dispositivo: %d|| WPUPSTI010|Ultima vez via internet no dispositivo: %d|| WPUPSTI011|Ultima vez via ficheiro|| WPUPSTI012|Ultima vez via desconhecida|| WPUPSTI013|, e mudou de posicao|| WPUPSTI014|Actual potencia/ganho:|| WPUPSTI016|Altitude: %.1f%s || WPUPSTI017|Curso: %s || WPUPSTI018|Velocidade: %.1f km/h|| WPUPSTI019|Velocidade: %.1f mph|| WPUPSTI020|%0.1f milhas|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distancia desde a minha estacao %s, curso desde a minha estacao %s|| WPUPSTI023|Ultima posicao: || WPUPSTI024|Dados da estacao meteorologica %c:%s|| WPUPSTI025|Curso do vento: %s Velocidade: %03d km/h|| WPUPSTI026|Curso do vento: %s Velocidade: %s mph|| WPUPSTI027| Rajada: %03d Km/h|| WPUPSTI028| Rajada: %s mph|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031|Humidade: %s%% || WPUPSTI032|Indice da humidade: %02.1fC || WPUPSTI033|Pressao barometrica: %s mb|| WPUPSTI034|Neve: %0.1f (cm/24h)|| WPUPSTI035|Neve: %0.0f (plg/24h)|| WPUPSTI036|Chuva: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (plg/h) || WPUPSTI039|%0.2f (mm/dia) || WPUPSTI040|%0.2f (plg/dia) || WPUPSTI041|%0.2f (mm/desde a meia noite)|| WPUPSTI042|%0.2f (mm/desde a meia noite)|| WPUPSTI043|Rota de dados: %s|| WPUPSTI044|Comentarios %02d/%02d %02d:%02d : %s|| WPUPSTI045|Limpar rastro|| WPUPSTI046|Total de chuva: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (plg)|| WPUPSTI049|Perguntar rastro|| WPUPSTI050|Perguntar por mensagens nao-confirmadas|| WPUPSTI051|Pergunta directa a estacao|| WPUPSTI052|Pergunta versao a estacao|| WPUPSTI053|Modificar objeto/artigo|| WPUPSTI054|Armazenar rastro|| WPUPSTI055|Repetido desde:|| WPUPSTI056|Activar actualizacao automatica|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF dirigido: %s|| WPUPSTI059|Estados %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp do combustivel: %02.1fC || WPUPSTI061|Temp do combustivel: %sF || WPUPSTI062|Mistura do combustevel: %s%% || WPUPSTI063|Baro: %0.2f em Hg|| WPUPSTI064|Procurar alerta de NWS|| WPUPSTI065|Indicativo tactico: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC procurar indicativo STIFCC0001|Procurar FCC banco de datos|| STIFCC0002|Procurar RAC banco de datos|| STIFCC0003|Nome:|| STIFCC0004|Rua/Av:|| STIFCC0005|Cidade:|| STIFCC0006|Estado:|| STIFCC0007|Codigo postal:|| STIFCC0008|Basica || STIFCC0009|Avancada || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC procurar indicativo STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Mensagem de banda aberta UMBNDO0001|a cerca de|| # # Opcoes universais UNIOP00001|Aceitar|| UNIOP00002|Cancelar|| UNIOP00003|Fechar|| UNIOP00004|milhas|| UNIOP00005|km|| UNIOP00006|Dispositivo|| UNIOP00007|Acrescentar|| UNIOP00008|Anular|| UNIOP00009|Propriedades|| UNIOP00010|Permitir transmissao?|| UNIOP00011|Activar no inicio?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|plg|| UNIOP00018|mm/dia|| UNIOP00019|plg/dia|| UNIOP00020|mm/hora|| UNIOP00021|plg/hora|| UNIOP00022|mm/med|| UNIOP00023|plg/med|| UNIOP00024|grd|| UNIOP00025|mb|| UNIOP00026|%|| UNIOP00027|inHg|| UNIOP00028|mm Hg|| UNIOP00029|Definir o relogio do sistema desde o GPS?|| UNIOP00030|Digipeater?|| UNIOP00031|m|| UNIOP00032|Aplicar||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # Seleccionar estacao STCHO00001|Seleccionar estacao|| # # Desligar alarme de WX WPUPWXA001|Alerta do tempo|| WPUPWXA002|Lista de alerta do tempo|| # # Configurar interfaces WPUPCIF001|Interfaces instalados|| WPUPCIF002|Escolher tipo de interface|| # # Configurar AX.25 TNC WPUPCAX001|Configurar AX.25 TNC|| WPUPCAX002|AX.25 nome da porta|| # # Nomes dos dispositivos do interface IFDNL00000|Nada|| IFDNL00001|TNC via a porta serie|| IFDNL00002|Serial TNC c/GPS mais (cabo HSP)|| IFDNL00003|GPS via porta serie|| IFDNL00004|Est. meteorologica via porta serie|| IFDNL00005|Ligacao a um servidor na internet|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS ligado via o servidor gpsd|| IFDNL00008|Est. meteorologica ligada a uma REDE|| IFDNL00009|TNC com GPS na porta AUX|| IFDNL00010|KISS TNC da porta serie|| IFDNL00011|Base de dados de rede (Nao implementado ainda)|| IFDNL00012|AGWPE em rede|| IFDNL00013|Multi-Port KISS TNC da porta serie|| IFDNL00014|SQL Database (Experimental)|| # # Info dispositivo interface IFDIN00000|%s %2d %s sobre serie %s %s|| IFDIN00001|%s %2d %s ligado a %s:%d %s|| IFDIN00002|%s %2d %s usando dispositivo nomeado %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| desligado || IFDIN00007| ligado || IFDIN00008| ERRO || IFDIN00009|DESCONHECIDO|| # # Controle da interface IFPUPCT000|Controle do interface|| IFPUPCT001|Iniciar|| IFPUPCT002|Parar|| IFPUPCT003|Iniciar todos|| IFPUPCT004|Parar todos|| # # Control de I-Gate IGPUPCF000|Opcoes I-Gate|| IGPUPCF001|Desactiva todo o trafego da IGate|| IGPUPCF002|So permite trafego de RF para Inet|| IGPUPCF003|Permite trafego de RF->Inet e Inet->RF|| IGPUPCF004|Caminho Igate -> RF || # # Estao meteorologica WXPUPSI000|Estacao meteorologica|| WXPUPSI001|Tipo de estacao meteorologica|| WXPUPSI002|Datos actuais|| WXPUPSI003|Curso do vento|| WXPUPSI004|Velocidade do vento|| WXPUPSI005|Rajada do vento|| WXPUPSI006|Temperatura|| WXPUPSI007|Total de chuva|| WXPUPSI008|Total de chuva hoje|| WXPUPSI009|Pressao barometrica|| WXPUPSI010|Humidade relativa|| WXPUPSI011|Peet Bros ULTIMETER 2000 Tipo (Modo dados log)|| WXPUPSI012|Peet Bros ULTIMETER II Tipo|| WXPUPSI013|Peet Bros ULTIMETER 2000 Tipo (Modo paquete)|| WXPUPSI014|Horas totais de chuva|| WXPUPSI015|Ultimas 24 tot. de chuvas|| WXPUPSI016|Qualimetricos Q-Net|| WXPUPSI017|Tipo Peet Bros ULTIMETER 2000 (Modo Completo)|| WXPUPSI018|Ponto de Rocio|| WXPUPSI019|Vento alto|| WXPUPSI020|Vento frio|| WXPUPSI021|Indice calorifico|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|Alta temperat.|| WXPUPSI024|Baixa temperat.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Listas das estacoes LHPUPNI000|Todas as estacoes|| LHPUPNI001|Estacoes moveis|| LHPUPNI002|Estacaos meteorologicas|| LHPUPNI003|Estacoes locais (via TNC)|| LHPUPNI004|Ultimas estacoes|| LHPUPNI005|Objectos e items|| LHPUPNI006|Objectos e items proprios|| LHPUPNI010| #|| LHPUPNI011|Indicativo|| LHPUPNI012|#Pack|| LHPUPNI013|Ult. posicao|| LHPUPNI014|Rota|| LHPUPNI015|PHG|| LHPUPNI016|Comentarios|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon ou UTM|| # # Tracar alertas WX sobre mapas PULDNMAT01|Mostra mapa de alarmes sobre outros mapas|| PULDNMAT02|Mostra mapa de alarmes debaixo de outros mapas|| # # Error/popup mensagens POPEM00001|Localiza erro!|| POPEM00002|A estacao %s nao foi encontrada!|| POPEM00003|Rastrear erro!|| POPEM00004|Erro do interface!|| POPEM00005|Nome invalido da porta AX.25 %s|| POPEM00006|Nome invalido da porta AX.25 %s|| POPEM00007|Indicativo invalido %s|| POPEM00008|Indicativo invalido AX.25 destinado ao digipeater|| POPEM00009|Nao posso abrir o interface AX.25, %s|| POPEM00010|Nao posso ligar o interface AX.25, %s|| POPEM00011|Nao posso ligar ao indicativo AX.25, %s|| POPEM00012|AX.25 erro na saida de UI|| POPEM00013|AX.25 problema com o ficheiro /etc/ax25/axports|| POPEM00014|AX.25 nome invalido da porta %s|| POPEM00015|Erro abrindo o interface %d, falha grave|| POPEM00016|Erro abrindo o interface %d tempo esgotado|| POPEM00017|Nao ha mais interfaces disponiveis!|| POPEM00018|Dado requerido - Simples linha de mensagem| POPEM00019|A porta de transmissao esta "off" para a porta %d| POPEM00020|Erro no banco de dados!| POPEM00021|AX.25 nao foi compilado no Xastir!|| POPEM00022|Erro de entrada!| POPEM00023|Nome de localizacao nao especificada!| POPEM00024|Nome de localizacao especificada em uso!| POPEM00025|Nao encontrado!|| POPEM00026|O rastreamento comeara quando ele aparecer|| POPEM00027|Info impropia. Alguns campos vazios?|| POPEM00028|Nao se pode abrir o ficheiro|| POPEM00029|Encontrado!|| POPEM00030|Simbolo da estacao meteorologica|| POPEM00031|Alterado para simbolo de WX '/_', outras opcoes: '\_' '/W' e '\W'|| POPEM00032|Atencao: usando simbolos do servico nacional meteorologico!|| POPEM00033|Nao ha dados GPS!|| POPEM00034|Desactivando a TX da minha posicao ate ter dados validos do GPS!|| POPEM00035|Atencao|| POPEM00036|Aviso|| POPEM00037|Interface HSP presente: tempo de GPS foi aumentado|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Salto de localizacao JMLPO00001|Localizacao de mapa|| JMLPO00002|IR!|| JMLPO00003|Nome da nova localizacao:|| # # Boletins BULMW00001|Boletins|| BULMW00002|Limite de alcance a (0, nao ha limite)|| BULMW00003|Mudanca de alcance|| # # Trafego de todas as mensagens AMTMW00001|Trafego de todas as mensagens|| AMTMW00002|Limite de alcance a (0, nao ha limite)|| # # Cadeias do sintetizador SPCHSTR001|Quilometros|| SPCHSTR002|metros|| SPCHSTR003|milhas|| SPCHSTR004|jardas|| SPCHSTR005|%s, distancia e %d %s.|| SPCHSTR006|%s, distancia e %.1f %s.|| SPCHSTR007|%s, distancia e %d %s %s %s.|| SPCHSTR008|%s, distancia e %.1f %s %s %s.|| SPCHSTR009|Novo alerta de tempo|| SPCHSTR010|Indicativo novo|| SPCHSTR011|Ouvido, D X, %s, na distancia de %.1f %s|| # SPCHDIRN00|norte of|| SPCHDIRS00|sul of|| SPCHDIRE00|este of|| SPCHDIRW00|oeste of|| SPCHDIRNE0|nordeste of|| SPCHDIRNW0|nordoeste of|| SPCHDIRSE0|sudeste of|| SPCHDIRSW0|sudoeste of|| # # Dialogo da seleo do simbolo SYMSEL0001|Selecionar simbolo|| SYMSEL0002|Tabela de simbolo primario|| SYMSEL0003|Tabela de simbolo secundario|| # # Dialogo das propriedades da impressora PRINT0001|Propriedades da impressora|| PRINT0002|Largura do papel|| PRINT0003|Auto-rodar imagem PRINT0004|Rodar imagem 90 CCW|| PRINT0005|Auto-balancear imagem|| PRINT0006|Balanca:|| PRINT0007|Forcar a pre-definida cor de fundo a branco|| PRINT0008|Imprimir em branco e preto|| PRINT0016|Cores invertidas|| PRINT0009|Resolucao do postscript:|| PRINT0010|Prevista|| PRINT0011|Imprimir o ficheiro|| PRINT0012|Guardar imagem num ficheiro...|| PRINT0013|Convertendo para postscript...|| PRINT0014|Criando arquivo de impressao finalizado|| PRINT0015|Estado da impressora|| # # Dialogo das propriedades da impressora PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Dialogo de localizar forma FEATURE001|Nome:|| FEATURE002|Estado/provincia:|| FEATURE003|Pas:|| FEATURE004|Mapa quad:|| FEATURE005|Tipo:|| FEATURE006|GNIS arquivo:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Dialogo do calculo de coordenadas COORD001|Calcular coordenadas|| COORD002|Calc|| COORD003|Calcular|| COORD004|Limpar|| COORD005|UTM|| COORD006|Latitude ou|| COORD007|Longitude ou|| COORD008|Zona|| COORD009|UTM indo para este|| COORD010|UTM indo para norte|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Dialogo do smart beaconing SMARTB001|Beaconing esperto|| SMARTB002|Racio alto (secs):|| SMARTB003|Velocidade alta (mph):|| SMARTB004|Velocidade alta (kph):|| SMARTB005|Racio baixo (mins):|| SMARTB006|Velocidade baixa (mph):|| SMARTB007|Velocidade baixa (kph):|| SMARTB008|Voltar ao minimo (deg):|| SMARTB009|Virar encosta:|| SMARTB010|Tempo de espera (secs):|| SMARTB011|Activar SmartBeaconing(tm)|| # # # # Dialogo do gamma adjust GAMMA001|Correccao do ajuste gamma|| GAMMA002|Correccao gamma|| # # # Dialogo das fontes de etiquetas dos mapas MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Muito pequeno Font|| MAPFONT004|Map Font Pequeno|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distancia/rumo na linha de estados PULDNDB001|Estado dist/rumo|| # # # Operacoes transferencias de GPS GPS001|Transferir GPS|| GPS002|Ficheiro|| GPS003|Escolher cor|| GPS004|Vermelho|| GPS005|Verde|| GPS006|Preto|| GPS007|Branco|| GPS008|Laranja|| GPS009|Azul|| GPS010|Amarelo|| GPS011|Violeta|| # # # Dialogo de propriedades dos mapas MAPP001|Propriedades dos mapas|| MAPP002| Max Min Desenhar mapas USGS|| MAPP003| Zoom Zoom Camada Preenchido DRG AutoMapa Caminho/Ficheiro|| MAPP004|Mudar camada->|| MAPP005|Preenchido->|| MAPP006|Sim|| MAPP007|Nao|| MAPP008|Automapas->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Marcas do tempo TIME001|Dia|| TIME002|Dias|| TIME003|Hora|| TIME004|Horas|| TIME005|Minuto|| TIME006|Minutos|| TIME007|Segundo|| TIME008|Segundos|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/language-Spanish.sys000066400000000000000000001173161501463444000215520ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Este es el archivo del Lenguaje Espaol usado para todas, consultas en Xastir. # # Creador : por Jose R. Marte A. # Mantenido por : El Xastir Grupo # Ult. Revisin : 05/20/2003, Por Jose R. Marte A. # # Lneas de comentarios con un signo de libra en frente son ignorado # El formato del archivo es como sigue: # Id (10 caractres alfa numrico)|(Cadena asociada con id)|TeclaRpida|#comentario # # AVISO: # Algunas cadenas de letras contienen comando de formato como %s y %d, usted no # debera cambiar eso. Cadena de formatos errados podran producir un segfault! # # Men Principal MENUTB0001|Archivo|A| MENUTB0002|Visualizar|V| MENUTB0004|Mapas|M| MENUTB0005|Estaciones|S| MENUTB0006|Mensajes|e| MENUTB0010|Interfaces|I| MENUTB0009|Ayuda|y| # # Men archivo PULDNFI001|Configurar|C| PULDNFI002|Abrir Bitcora|B| PULDNFI003|Prueba|P| PULDNFI004|Salir|S| PULDNFI007|Cambia nivel Depuracin|D| PULDNFI010|Bitcora del TNC|T| PULDNFI011|Bitcora de Internet|I| PULDNFI012|Bitcora del I-Gate|G| PULDNFI013|Bitcora del WX|W| PULDNFI014|Activa PNG Instantnea|| PULDNFI015|Imprimir Mapa|P| PULDNFI016|KML Snapshots|| # # Men visor PULDNVI001|Boletines|B| PULDNVI002|Datos entrantes|D| PULDNVI003|Estaciones Mviles|M| PULDNVI004|Todas las Estaciones|T| PULDNVI009|Estaciones Locales|L| PULDNVI012|ltimas Estaciones|U| PULDNVI005|Estaciones Meteorolgicas|E| PULDNVI008|Su Estacin Meteorolgica|S| PULDNVI007|Alerta del tiempo|A| PULDNVI011|Trficos de Mensajes|f| PULDNVI013|Tiempo de Inicio|I| PULDNVI014|Tiempo Transcurrido|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Men de Configuracin PULDNCF004|Estacin|E| PULDNCF001|Predefinidos|P| PULDNCF003|Cronmetro|t| PULDNCF002|Sistema de Coordenada|C| PULDNCF006|Alarmas de Audio|A| PULDNCF007|Sintetizador de Voz|S| PULDNCF008|Guardar Configuracin!|G| # # Men de Mapas PULDNMP001|Seleccionar Mapas|M| PULDNMP012|Saltar a una Locacin|S| PULDNMP014|Localice rasgo del Mapa|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Desactive todos los Mapas|| PULDNMP002|Activar Auto Mapas|| PULDNMP003|Rejillas sobre Mapa|| PULDNMP004|Niveles de Mapas|| PULDNMP010|Etiquetas de Mapas|| PULDNMP009|Activar Areas Coloridas|| PULDNMP007|Alerta Mapa WX|| PULDNMP005|Color de fondo|C| PULDNMP006|Etiquetas de estiones|E| PULDNMP026|Icon Outline Style|O| PULDNMP011|Men Indicador del Ratn|R| PULDNMP008|Intensidad del Mapa|I| PULDNMP021|Auto Mapa - Desactivar Mapas de Trama|| PULDNMP022|Indezar Mapas en Inicio|| PULDNMP023|Indice: Agregar Nuevos Mapas|A| PULDNMP024|Indice: Reindezar TODOS los Mapas|T| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Find Address|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| MPUPTGR017|Internet Map Timeout (segundo)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # Seleccion de Mapas WPUPMCP001|Seleccin de Mapa|| PULDNMMC01|Limpiar|N| PULDNMMC02|Vectores|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Expandir Dirs||| PULDNMMC07|Dirs/Mapas Seleccionado:|| PULDNMMC08|Clear Dirs|C| PULDNMMC09|Select All|S| # # Colores de fondo del mapa PULDNMBC01|Gris|| PULDNMBC02|Rosado Mstico|| PULDNMBC03|Azul Marino|| PULDNMBC04|Azul acerado|| PULDNMBC05|Med. Verde mar|| PULDNMBC06|Verde Plido|| PULDNMBC07|Dorado Plido|| PULDNMBC08|Dorado Amarillo|| PULDNMBC09|Marrn Rosado|| PULDNMBC10|Rojo ladrillo|| PULDNMBC11|Blanco|| PULDNMBC12|Negro|| # # Mapas Estaciones estilos de etiquetas PULDNMSL01|Fondo Negro|| PULDNMSL02|Fondo Gris|| PULDNMSL03|Texto en Negro|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|No Outline|N| PULDNMIO02|Black Outline|B| PULDNMIO03|Grey Outline|G| PULDNMIO04|White Outline|W| # # Switches ON/OFF/Corto PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Corto|| # # Men de Despliegue de Estaciones PULDNDP014|Localizar Estacin|L| PULDNDP001|Rastreo de Estacin|E| PULDNDP022|Sacar Rastro de Findu|F| PULDNDP032|Filtrar Datos|| PULDNDP040|- Seleccionar Nada|| PULDNDP041|- Seleccionar Mo|| PULDNDP042|- Seleccionar TNC|| PULDNDP027|- Seleccionar Directo|| PULDNDP043|- Seleccionar Va Digi|| PULDNDP034|- Seleccionar Red|| PULDNDP019|Incluir Datos Expirados|| PULDNDP044|- Seleccionar Estaciones|| PULDNDP028|- Seleccionar Estaciones Fijas|| PULDNDP029|- Seleccionar Estaciones Mviles|| PULDNDP030|- Seleccionar Estaciones de WX|| PULDNDP053| - Select CWOP WX Stations|| PULDNDP045|- Seleccionar Objetos/Artculos|| PULDNDP026|- Seleccionar Objetos/Artculos de WX|| PULDNDP039|- Seleccionar Objetos/Artculos Medidores de Agua|| PULDNDP031|- Seleccionar Otros Objetos/Artculos|| PULDNDP057|- Seleccione los objetos aeronuticos/Artculos|| PULDNDP058|- Seleccionar objetos del buque / Artculos|| PULDNDP033|Filtrar Visualizacin|| PULDNDP010|Mostrar Indicativo|I| PULDNDP012|Mostrar Smbolo|D| PULDNDP011|- Smbolo Rotado|S| PULDNDP007|Mostrar Rastros|R| PULDNDP003|Mostrar Curso|C| PULDNDP004|Mostrar Velocidad|V| PULDNDP017|- Mostrar Velocidad Corta|| PULDNDP002|Mostrar Altura|A| PULDNDP009|Mostrar Informe del Tiempo|T| PULDNDP046|- Mostrar Texto|| PULDNDP018|- Slo la Temperatura|| PULDNDP047|- Mostrar Indicacin de Viento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Mostrar Ambigedad de Posicin|| PULDNDP008|Mostrar Potencia/Ganancia|P| PULDNDP021|- Usar Pot/Ganancia por Defecto|| PULDNDP020|- Mostrar Pot/Ganancia Mviles|| PULDNDP023|Mostrar atributos DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activar Conteo-Muerto|| PULDNDP036|- Mostrar Arco|| PULDNDP037|- Mostrar Curso|| PULDNDP038|- Mostrar Smbolo|| PULDNDP005|Mostrar Orientacin/Distancia|D| PULDNDP024|Mostrar Tiempo del Ultimo Informe|| PULDNDP015|Anular Todas las Estaciones|A| PULDNDP016|Limpiar Rastros|n| PULDNDP025|Limpiar Historia de Objeto/Artculo|| PULDNDP048|Recargar Historia de Objeto/Artculo|| PULDNDP049|Clear All Tactical Calls|| PULDNDP050|Clear Tactical Call History|| PULDNDP051|Select Tactical Calls Only|| PULDNDP052|- Label Trailpoints|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Inglesa/Mtrica PULDNUT001|Activar Unidades Inglesa|| PULDNUT002|Mtrica|| # # Men de Mensajes PULDNMG001|Enviar Mensaje A|E| PULDNMG002|Abrir Mensajes Grupos|G| PULDNMG003|Anular todos mensajes saliente|B| PULDQUS001|Pregunta General a Estaciones|P| PULDQUS002|Pregunta a Estaciones I-Gate|I| PULDQUS003|Pregunta a Estaciones WX|W| PULDNMG004|Fijar Mensaje en Contestacin Automtica|F| PULDNMG005|Activar Auto contestacin de Mensaje|A| PULDNMG006|Satlite Modo de Reconocimiento|M| PULDNMG007|Show Pending Messages|P| # # Men de Interfaces PULDNTNT04|Interface Control|| PULDNTNT03|Desactivar Transmitir: TODOS|| PULDNTNT05|Desactivar Transmitir: Mi Posicin|| PULDNTNT06|Desactivar Transmitir: Objetos/Artculos|| PULDNTNT11|Enable Server Port|| PULDNTNT01|Transmitir Ahora..!|T| PULDNTNT07|Coger Huella de GPS|F| PULDNTNT08|Coger Rutas de GPS|R| PULDNTNT09|Coger VaPuntos de GPS|W| PULDNTNT10|Fetch Garmin RINO Waypoints|G| # # Men de Ayuda PULDNHEL01|Acerca de|A| PULDNHEL02|Indice de Ayuda|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # Men de Ratn POPUPMA001|Opciones|| POPUPMA00c|Centro|| POPUPMA015|Info de estacin|| POPUPMA002|Acercar|A| POPUPMA003|Alejar|l| POPUPMA004|Nivel de Enfoque|N| POPUPMA005|Nivel 1|1| POPUPMA006|Nivel 16|6| POPUPMA007|Nivel 64|4| POPUPMA008|Nivel 256|2| POPUPMA009|Nivel 1024|0| POPUPMA010|Nivel 8192|8| POPUPMA017|El Mundo Entero|E| POPUPMA016|Ultima Pos/Enfoque del Mapa|P| POPUPMA018|Crear Objeto/Artculo|C| POPUPMA019|Modificar Objeto/Artculo|M| POPUPMA025||Mover Mi Estacin Aqu|A| POPUPMA011|Paneo arriba|u| POPUPMA012|Paneo abajo|d| POPUPMA013|Paneo izquierda|l| POPUPMA014|Paneo derecha|r| POPUPMA020|Medida|| POPUPMA021|Movimiento|| POPUPMA022|RastreMe|| POPUPMA023|Modificadores Encontrado!|| POPUPMA024|Por favor apague OFF CapsLock/NumLock/ScrollLock/otro modificadores|| POPUPMA026|Centre & Enfoque|| POPUPMA027| Latitud|| POPUPMA028| Longitud|| POPUPMA029|Dibuje Objetos CAD|| POPUPMA030|Draw|| POPUPMA031|Cierre el Polgono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Men de Estados de la lneas de Etiquetas BBARZM0001|Foco %s|| BBARZM0002|Foco %s Tr|| BBARSTH001|%d/%d Estaciones|| BBARSTA000|%-9s Nuevo objeto!|| BBARSTA001|%-9s Nueva estacin!|| BBARSTA002|%s|| BBARSTA003|Cargando mapas...|| BBARSTA004|Mapas cargados...|| BBARSTA005|Mapa Lat/Long Rejilla es ON|| BBARSTA006|Mapa Lat/Long Rejilla es OFF|| BBARSTA007|El uso de Auto Mapas, es ON|| BBARSTA008|El uso de Auto Mapas, es OFF|| BBARSTA009|Los Niveles del Mapa estn ON|| BBARSTA010|Los Niveles del Mapa estn OFF|| BBARSTA011|Auto contestacin de Mensaje es OFF!|| BBARSTA012|Achivo creado..|| BBARSTA013|Abriendo Puerto GPS|| BBARSTA014|Cerrando Puerto GPS|| BBARSTA015|Obtenido GPS RMC Cordn|| BBARSTA016|Obtenido GPS GGA Cordn|| BBARSTA017|Red desconectada del Servidor|| BBARSTA018|Conexin a Red tiempo vencido!|| BBARSTA019|Buscando Servidor %s|| BBARSTA020|Conectado al %s|| BBARSTA021|Fracaso en conexin de la Red!|| BBARSTA022|Podra no atar el scalo!|| BBARSTA023|No IP para el Servidor!|| BBARSTA024|No Servidor Especificado|| BBARSTA025|Servidor encontrado, Conectando %d|| BBARSTA026|Esperando por datos del GPS va HSP..|| BBARSTA027|Limpiando el HSP datos obtenido del TNC..|| BBARSTA028|Cargando %s|| BBARSTA029|Abriendo Puerto WX|| BBARSTA030|Cerrando Puerto WX|| BBARSTA031|Buscando el Servidor %d|| BBARSTA032|Datos de WX Decodificado|| BBARSTA033|Eco desde digipeater|| BBARSTA034|Cargando Mapas de alerta WX|| BBARSTA035|Esperando por datos del GPS va AUX..|| BBARSTA036|Limpiando el AUX datos obtenido del TNC..|| BBARSTA037|Datos de GPS Decondificado|| BBARSTA038|Coloque el cambio en mi estacin|| BBARSTA039|Indezando %s|| BBARSTA040|Estacin de Aficionado APRS(tm) %s|| BBARSTA041|Esperando por GPS data..|| BBARSTA042|Transmitiendo objetos/articulos|| BBARSTA043|Anotando|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # Despliegue Paquete de Datos WPUPDPD001|Despligue de Datos|| WPUPDPD002|slo datos del TNC|| WPUPDPD003|slo datos de la Red|| WPUPDPD004|Datos del TNC y la Red|| WPUPDPD005|TNC|| WPUPDPD006|RED|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # Localizar Estacin WPUPLSP001|Localizar estacin|| WPUPLSP002|Localizar Indicativo|| WPUPLSP003|Macheo Sensible|S| WPUPLSP004|Macheo Exacto|E| WPUPLSP005|Localizar ahora!|A| WPUPLSP006|Localizar Emergencia!|| WPUPLSP007|FCC/RAC Lookup|| # # Configurar predefinidos WPUPCFD001|Configurar valores predefinidos|| WPUPCFD002|desde qu intrvalo de tiempo ser considerada una estacin vieja?|| WPUPCFD003|15 minutos|1| WPUPCFD004|30 minutos|3| WPUPCFD005|45 minutos|4| WPUPCFD006|1 hora|H| WPUPCFD007|90 minutos|9| WPUPCFD008|2 horas|2| WPUPCFD009|desde qu intrvalo de tiempo la estacin no ser desplegada?|| WPUPCFD010|6 horas|6| WPUPCFD011|12 horas|o| WPUPCFD012|1 Da|D| WPUPCFD013|2 Das|s| WPUPCFD014|1 semana|n| WPUPCFD015|Opcin modo de Transmisin de la estacin|| WPUPCFD016|Estacin Fija|F| WPUPCFD017|Estacin Mvil c/Hora local|l| WPUPCFD018|Estacin Mvil c/Fecha-hora Zlu|Z| WPUPCFD019|Estacin Mvil c/Horas-segundos Zlu|u| WPUPCFD021|Posicin de la estacin c/Tiempo|T| WPUPCFD022|Posicin de la estacin, fecha-hora Zulu, y Tiempo|f| WPUPCFD023|Transmitir datos WX en Raw?|| WPUPCFD024|Comprimir datos objeto/artculo cuando transmita?|| WPUPCFD025|Activar Red Alternada?|A| WPUPCFD026|Enviar reportes de posicin en qu intrvalos?|| WPUPCFD027|Mostrar bulletines Nuevo|| WPUPCFD028|Avisar si hay teclas Modificadora|| WPUPCFD029|Ver boletines de zero-distancia|| WPUPCFD030|Disable Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # Menu "Configurar - Cronmetro" WPUPCFTM01|Configurar Cronmetro|| WPUPCFTM02|TX Posicin Intrvalo (minutos)|| WPUPCFTM03|Desvanecimiento de la Estacin (minutos)|| WPUPCFTM04|Objeto/Artculo TX Max Intrvalo (minutos)|| WPUPCFTM05|Limpiar Tiempo de la Estacin (horas)|| WPUPCFTM06|Chequeo Intrvalo del GPS (segundos)|| WPUPCFTM07|Borrar Tiempo de la Estacin (das)|| WPUPCFTM08|Descanso Conteo-Muerto (minutos)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|Nuevo Tiempo Rastro (min)|| WPUPCFTM11|Nuevo Interval Rastro (grados)|| WPUPCFTM12|RINO -> Objects Interval (min), 0 = Disabled|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # Configurar Sistema de Coordenada" WPUPCFC001|Configurar Sistema de Coordenada|| WPUPCFC002|Seleccione Sistema de Coordenada|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM con zonas especiales|| # # Configurar GPS WPUPCFG001|Configurar GPS|| WPUPCFG003|Puerto exclusivo de GPS|| WPUPCFG002|Usar Posicin GPS?|| WPUPCFG004|opciones del GPS|| WPUPCFG005|GPS Exclusivo|| WPUPCFG006|TNC conectado a GPS (Cable HSP)|| WPUPCFG007|TNC conectado a GPS usando CTL-E|| WPUPCFG008|GPS tiempo (Muestreo cada)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 minutos|| WPUPCFG014|5 minutos|| WPUPCFG015|10 minutos|| WPUPCFG016|Red conectada al GPS|| WPUPCFG017|Servidor GPSD|| WPUPCFG018|Puerto GPSD|| WPUPCFG019|Red GPS va GPSD|| WPUPCFG020|Reconectar en fallo?|| WPUPCFG021|Red Conectada a WX|| WPUPCFG022|Servidor WX|| WPUPCFG023|Puerto WX|| # # Configurar TNC (baudio tambin son para WX) WPUPCFT001|Configurar TNC|| WPUPCFT002|Usar TNC?|| WPUPCFT003|Puerto TNC|| WPUPCFT004|Velocidad del Puerto|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Rutas del UnProto|| WPUPCFT012|Ruta 1: %s va || WPUPCFT013|Ruta 2: %s va || WPUPCFT014|Ruta 3: %s va || WPUPCFT015|Modo del Puerto|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurar el TNC c/HSP GPS|| WPUPCFT024|Tipo de Data|| WPUPCFT025|Auto deteccin|| WPUPCFT026|Tipo Binario|| WPUPCFT027|Tipo ASCII|| WPUPCFT028|Configurar el TNC c/AUX GPS|| WPUPCFT029|Configurar el TNC c/MAL ENUM: %d|| WPUPCFT030|Configurar un KISS TNC|| WPUPCFT031|Archivos de Configuracin del TNC|| WPUPCFT032|Arreglar Archivo del TNC|| WPUPCFT033|Archivo de apagar TNC|| WPUPCFT034|Parmetros TNC KISS modo|| WPUPCFT035|TXDelay (10 ms unidades)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (10 ms unidades)|| WPUPCFT038|TxTail (10 ms unidades)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configurar un Multi-Port KISS TNC|| WPUPCFT041|Radio Port|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # Configurar el Puerto de la Estacin Meteorolgica WPUPCFWX01|Configurar el Puerto de la Estacin Meteorolgica|| WPUPCFWX02|Dispositivo de la Estacin Meteorolgica|| WPUPCFWX03|Tipo Medida de lluvia (Configuracin Global)|| WPUPCFWX04|0.1 pg / 2.5 mm|| WPUPCFWX05|0.01 pg / 0.25 mm|| WPUPCFWX06|0.1 mm|| WPUPCFWX07|No Correccin|| # # Configurar la Estacin WPUPCFS001|Configurar la estacin|| WPUPCFS002|Indicativo|| WPUPCFS003|Latitud|| WPUPCFS004|grd|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Longitud|| WPUPCFS008|(E/W)|| WPUPCFS009|Smbolo de la estacin|| WPUPCFS010|Grupo/sobrepuesto|| WPUPCFS011|Smbolo|| WPUPCFS028|Seleccione|| WPUPCFS012|Potencia - Altura (HAAT) - Ganancia y Direccin|| WPUPCFS013|Desactive PHG|| WPUPCFS014|Altura de la Antena|| WPUPCFS015|Ganancia de la Antena|| WPUPCFS016|Omni|| WPUPCFS017|Comentarios:|| WPUPCFS018|Posicin ambiga|| WPUPCFS019|Ninguna|| WPUPCFS020|.11 milla|| WPUPCFS021|1.15 millas|| WPUPCFS022|11.51 millas|| WPUPCFS023|69.09 millas|| WPUPCFS024|.18 kilmetro|| WPUPCFS025|1.85 kilmetros|| WPUPCFS026|18.53 kilmetros|| WPUPCFS027|111.19 kilmetros|| WPUPCFS029|Envo de posicin comprimida|C| # # Dilogo de Objeto/Artculo POPUPOB001|Objeto/Arculo|| POPUPOB002|Nombre:|| POPUPOB003|Crear Nuevo Objeto|| POPUPOB004|Borrar Objeto|| POPUPOB005|Modificar Objeto|| POPUPOB006|Crear Nuevo Artculo|| POPUPOB007|Area de Objeto|| POPUPOB008|Activar Area de Objeto|| POPUPOB009|Color Luminoso|| POPUPOB010|Area Colorida|| POPUPOB011|Crculo|| POPUPOB012|Lnea-Derecha '/'|| POPUPOB013|Lnea-Izquierda '\'|| POPUPOB014|Tringulo|| POPUPOB015|Rectngulo|| POPUPOB016|Negro|| POPUPOB017|Azul|| POPUPOB018|Verde|| POPUPOB019|Cian|| POPUPOB020|Rojo|| POPUPOB021|Violeta|| POPUPOB022|Amarillo|| POPUPOB023|Gris|| POPUPOB024|Compense Arriba:|| POPUPOB025|Compense Izq.(Excepto '/'):|| POPUPOB026|Corridor:|| POPUPOB027|Opciones Genricas|| POPUPOB028|Situacin|| POPUPOB029|Activar Letrero|| POPUPOB030|Data:|| POPUPOB031|Letrero Objeto|| POPUPOB032|Activar Compresin|| POPUPOB033|Borrar Artculo|| POPUPOB034|Modificar Artculo|| POPUPOB035|Altitud (Pies):|| POPUPOB036|Velocidad (Nudos):|| POPUPOB037|Curso:|| POPUPOB038|DF Objeto|| POPUPOB039|Seal - Altura(HAAT) - Ganancia - Direccin|| POPUPOB040|Dirigiendo - Ancho de la orientacin|| POPUPOB041|Antena Omni-direccional|| POPUPOB042|Antena Direccional|| POPUPOB043|Intil|| POPUPOB044|Adopt Object|| POPUPOB045|Adopt Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # Configurar Internet WPUPCFI001|Configurar Internet|| WPUPCFI002|Servidor|| WPUPCFI003|Puerto|| WPUPCFI004|(Servidores Secundarios)|| WPUPCFI005|Servidor1|| WPUPCFI006|Puerto1|| WPUPCFI007|Servidor2|| WPUPCFI008|Puerto2|| WPUPCFI009|Palabra de Paso|| WPUPCFI010|Dejar en blanco si nada|| WPUPCFI011|Reconectar en fallo de la RED?|| WPUPCFI012|Correr como un I-Gate?|| WPUPCFI013|Difundir mensajes va TNC cuando un I-Gate?|| WPUPCFI014|Bitcora de Transacciones del I-Gate?||| WPUPCFI015|Parametros de Filtrado|| # # Configurar Base de datos WPUPCFID01|Configurar Base de datos(TBD)|| WPUPCFID02|Servidor|| WPUPCFID03|Puerto|| WPUPCFID04|(Servidores Secundarios)|| WPUPCFID05|Servidor1|| WPUPCFID06|Puerto1|| WPUPCFID07|Servidor2|| WPUPCFID08|Puerto2|| WPUPCFID09|Palabra de Paso|| WPUPCFID10|Dejar en blanco si nada|| WPUPCFID11|Reconectar en fallo de la RED?|| WPUPCFID12|Correr como un I-Gate?|| WPUPCFID13|Difundir mensajes va TNC cuando un I-Gate?|| WPUPCFID14|Bitcora de Transacciones del I-Gate?||| WPUPCFID15|Parametros de Filtrado|| # # Menu "Configurar AGWPE" WPUPCFIA01|Configurar AGWPE|| WPUPCFIA02|Servidor || WPUPCFIA03|Puerto || WPUPCFIA04|(Servidores Secundario)|| WPUPCFIA05|Servidor1|| WPUPCFIA06|Puerto1|| WPUPCFIA07|Servidor2|| WPUPCFIA08|Puerto2|| WPUPCFIA09|Codigo de Paso|| WPUPCFIA10|(dejar en blanco si Nada)|| WPUPCFIA11|Reconectar en fallo de RED?|| WPUPCFIA12|Correr como un I-Gate?|| WPUPCFIA13|Difundir mensajes via TNC cuando un I-Gate?|| WPUPCFIA14|Bitcora de Transacciones I-Gate?|| WPUPCFIA15|Transmitir RadioPuerto|| # # Configurar Alarmas de Audio WPUPCFA001|Configurar Alarma de Audio|| WPUPCFA002|Aplicacin Audio|| WPUPCFA003|Alarma ON|| WPUPCFA004|Archivos de Audio|| WPUPCFA005|Nueva estacin|| WPUPCFA006|Nuevo mensaje|| WPUPCFA007|Proximidad|| WPUPCFA008|Banda abierta|| WPUPCFA009|Mnima distancia|| WPUPCFA010|Mxima distancia|| WPUPCFA011|Alerta del Tiempo|| # # Configurar a Festival el sintetizador de Voz WPUPCFSP01|Configurar a Festival el Sintetizador de Voz|| WPUPCFSP02|Fijar en 'ON' la opciones del Sintetizador de Voz|| WPUPCFSP03|<- Anunciar Nueva Estacin|| WPUPCFSP04|<- Anunciar Alerta de Nuevo Mensaje|| WPUPCFSP05|<- Anunciar Cuerpo de Nuevo Mensaje|| WPUPCFSP06|<- Anunciar la Proximidad de estaciones|| WPUPCFSP07|<- Anunciar DX condicin de Banda Abierta|| WPUPCFSP08|<- Anunciar Alerta sobre condiciones del Tiempo|| WPUPCFSP09|<- Estacin Rastreada Alerta de Proximidad|| # # Rastreo de Estacin WPUPTSP001|Rastreo estacin|| WPUPTSP002|Rastreo Indicativo|| WPUPTSP003|Macheo Sensible|| WPUPTSP004|Macheo Exacto|| WPUPTSP005|Rastrear Ahora!|| WPUPTSP006|Limpiar Rastro|| WPUPTSP007|Abajar Rastro|| WPUPTSP008|Indicativo|| WPUPTSP009|Inicio Del Rastro (hace horas)|| WPUPTSP010|Longitud del Rastro (horas)|| # # Men de Mensajes WPUPMSB001|Enviar mensaje %d|| WPUPMSB002|Enviar Mensaje a grupo %d|| WPUPMSB003|Indicativo de Estacin:|| WPUPMSB004|Indicativos de Grupos:|| WPUPMSB005|Nuevo/Refresh Indicativo|| WPUPMSB006|Nuevo grupo|| WPUPMSB007|Clear Msg History|| WPUPMSB008|Mensaje:|| WPUPMSB009|Enviar ahora!|| WPUPMSB010|Ruta:|| WPUPMSB011|Cancel Pending Msgs|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # Auto Contestacin WPUPARM001|Cambiar auto Contestacin|| WPUPARM002|Reenviar:|| # # Ayuda / Indice WPUPHPI001|Indice de Ayuda|I| WPUPHPI002|Visualizar|V| # # Informacin de la Estacin WPUPSTI000|Objeto creado desde: %s|| WPUPSTI001|Info Estacin|| WPUPSTI002|Enviar mensaje|| WPUPSTI003|Buscar datos FCC|| WPUPSTI004|Buscar datos RAC|| WPUPSTI005|%d: Paquetes recibidos, ltimo recibido en fecha: || WPUPSTI006|Odo va TNC en dispositivo: %d, || WPUPSTI007|Odo || WPUPSTI008|Ultima vez va Local|| WPUPSTI009|Ultima vez va TNC en dispositivo: %d|| WPUPSTI010|Ultima vez va Internet en dispositivo: %d|| WPUPSTI011|Ultima vez va Archivo|| WPUPSTI012|Ultima vez va Desconocida|| WPUPSTI013|, y ha cambiado posicin|| WPUPSTI014|Actual Potencia/Ganancia:|| WPUPSTI016|Altitud: %.1f%s || WPUPSTI017|Curso: %s || WPUPSTI018|Velocidad: %.1f km/h|| WPUPSTI019|Velocidad: %.1f mph|| WPUPSTI020|%0.1f millas|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distancia desde mi estacin %s, Curso desde mi estacin %s|| WPUPSTI023|Ultima posicin: || WPUPSTI024|Datos de la estacin Meteorolgica %c:%s|| WPUPSTI025|Curso del viento: %s Velocidad: %03d km/h|| WPUPSTI026|Curso del viento: %s Velocidad: %s mph|| WPUPSTI027| Rfaga: %03d Km/h|| WPUPSTI028| Rfaga: %s mph|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031| Humedad: %s%% || WPUPSTI032|Indice de Humedad: %02.1fC || WPUPSTI033| Presin Baromtrica: %s mb|| WPUPSTI034|Nieve: %0.1f (cm/24h)|| WPUPSTI035|Nieve: %0.0f (plg/24h)|| WPUPSTI036|Lluvia: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (plg/h) || WPUPSTI039|%0.2f (mm/da) || WPUPSTI040|%0.2f (plg/da) || WPUPSTI041|%0.2f (mm/desde medianoche)|| WPUPSTI042|%0.2f (mm/desde medianoche)|| WPUPSTI043|Ruta de Datos: %s|| WPUPSTI044|Comentarios %02d/%02d %02d:%02d : %s|| WPUPSTI045|Limpiar Rastro|| WPUPSTI046|Total lluvia: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (plg)|| WPUPSTI049|Preguntar rastro|| WPUPSTI050|Pregunta no-conocido Mensaje|| WPUPSTI051|Pregunta directa a estacin|| WPUPSTI052|Pregunta versin a estacin|| WPUPSTI053|Modificar Objeto/Artculo|| WPUPSTI054|Almacenar Rastro|| WPUPSTI055|Repetido desde:|| WPUPSTI056|Activar Actualizaciones Automtica|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Orientando DF: %s|| WPUPSTI059|Estados %02d/%02d %02d:%02d : %s|| WPUPSTI060|Incendio Temp: %02.1fC || WPUPSTI061|Incendio Temp: %sF || WPUPSTI062|Humedad de Incendio: %s%% || WPUPSTI063|Baro: %0.2f en Hg|| WPUPSTI064|Fetch NWS Alert|| WPUPSTI065|Tactical Call: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC buscar Indicativo STIFCC0001|Buscar en Base de datos FCC|| STIFCC0002|Buscar en Base de datos RAC|| STIFCC0003|Nombre:|| STIFCC0004|Calle:|| STIFCC0005|Ciudad:|| STIFCC0006|Estado:|| STIFCC0007|Zona Postal:|| STIFCC0008|Bsica || STIFCC0009|Advanzada || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC buscar Indicativo STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Mensaje de Banda abierta UMBNDO0001|en distancia de|| # # Opciones Universales UNIOP00001|Aceptar|| UNIOP00002|Cancelar|| UNIOP00003|Cerrar|| UNIOP00004|millas|| UNIOP00005|km|| UNIOP00006|Dispositivo|| UNIOP00007|Agregar|| UNIOP00008|Anular|| UNIOP00009|Propiedades|| UNIOP00010|Permitir Transmisin?|| UNIOP00011|Activar en Inicio?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pg|| UNIOP00018|mm/da|| UNIOP00019|pg/da|| UNIOP00020|mm/hora|| UNIOP00021|pg/hora|| UNIOP00022|mm/med|| UNIOP00023|pg/med|| UNIOP00024|grd|| UNIOP00025|mb|| UNIOP00026|%|| UNIOP00027|pg Hg|| UNIOP00028|mm Hg|| UNIOP00029|Fije el tiempo del sistema del GPS|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Apply||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # Seleccionar Estacin STCHO00001|Seleccionar Estacin|| # # DESPLIEGUE ALARMA WX WPUPWXA001|Alerta del Tiempo|| WPUPWXA002|Lista de alerta del Tiempo|| # # Configurar Interfaces WPUPCIF001|Interfaces Instalados|| WPUPCIF002|Elegir Tipo de interfz|| # # Configurar AX.25 TNC WPUPCAX001|Configurar AX.25 TNC|| WPUPCAX002|AX.25 nombre de puerto|| # # Nombres de dispositivos de la Interfz IFDNL00000|Nada|| IFDNL00001|TNC va el Puerto Serial|| IFDNL00002|Serial TNC c/GPS ms (cable HSP)|| IFDNL00003|GPS va Puerto Serial|| IFDNL00004|Est. Meteorolgica va Puerto Serial|| IFDNL00005|Conexin a un Servidor en Internet|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS Enlazado va el Servidor gpsd|| IFDNL00008|Est. Meteorolgica Enlazada a una RED|| IFDNL00009|Serial TNC c/GPS ms (cable AUX)|| IFDNL00010|Serial KISS TNC|| IFDNL00011|Red Base de Datos (Aun No Implementada)|| IFDNL00012|Red AGWPE|| IFDNL00013|Serial Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Info dispositivo Interfz IFDIN00000|%s %2d %s sobre serial %s %s|| IFDIN00001|%s %2d %s conectado a %s:%d %s|| IFDIN00002|%s %2d %s usando dispositivo nombrado %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| ABAJO || IFDIN00007| ARRIBA || IFDIN00008| ERROR || IFDIN00009|DESCONOCIDO|| # # Control de la interfz IFPUPCT000|Control de Interfz|| IFPUPCT001|Iniciar|| IFPUPCT002|Detener|| IFPUPCT003|Iniciar todos|| IFPUPCT004|Detener todos|| # # Control de I-Gate IGPUPCF000|I-Gate Opciones|| IGPUPCF001|Desactiva todo el IGate trfico|| IGPUPCF002|Slo Permite trfico de RF->Inet|| IGPUPCF003|Permite ambos trficos RF<->Inet|| IGPUPCF004|Igate -> RF Ruta || # # Estacin Meteorolgica WXPUPSI000|Estacin meteorolgica|| WXPUPSI001|Tipo de estacin Meteorolgica|| WXPUPSI002|Datos Actuales|| WXPUPSI003|Curso del viento|| WXPUPSI004|Velocidad del viento|| WXPUPSI005|Rfaga del viento|| WXPUPSI006|Temperatura|| WXPUPSI007|Total lluvia|| WXPUPSI008|Hoy Total lluvia|| WXPUPSI009|Presin Baromtrica|| WXPUPSI010|Humedad Relativa|| WXPUPSI011|Peet Bros ULTIMETER 2000 Tipo (Modo Datos Log)|| WXPUPSI012|Peet Bros ULTIMETER II Tipo|| WXPUPSI013|Peet Bros ULTIMETER 2000 Tipo (Modo Paquete)|| WXPUPSI014|Actual Tot. hora lluvia|| WXPUPSI015|Ultimas 24 Tot. lluvias|| WXPUPSI016|Cualimtricos Q-Net|| WXPUPSI017|Tipo Peet Bros ULTIMETER 2000 (Modo Completo)|| WXPUPSI018|Punto de Roco|| WXPUPSI019|Viento Alto|| WXPUPSI020|Viento Fro|| WXPUPSI021|Indice Caluroso|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|Alta Temperat.|| WXPUPSI024|Baja Temperat.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Listas de Estaciones LHPUPNI000|Todas las estaciones|| LHPUPNI001|Estaciones mviles|| LHPUPNI002|Estaciones Meteorolgicas|| LHPUPNI003|Estaciones locales (va TNC)|| LHPUPNI004|Ultimas Estaciones|| LHPUPNI005|Objetos y Artculos|| LHPUPNI006|Objetos y Artculos Propio|| LHPUPNI010| #|| LHPUPNI011|Indicativo|| LHPUPNI012|#Pack|| LHPUPNI013|Ult.Posicin|| LHPUPNI014|Ruta|| LHPUPNI015|PHG|| LHPUPNI016|Comentarios|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon o UTM|| # # Traza Alertas WX sobre mapas PULDNMAT01|Muestra mapa de alarma sobre otros mapas|| PULDNMAT02|Muestra mapa de alarma bajo otros mapas|| # # Error/popup mensajes POPEM00001|Localiza Error!|| POPEM00002|La estacin %s no fue encontrada!|| POPEM00003|Rastreo Error!|| POPEM00004|Interfz Error!|| POPEM00005|Invlido nombre de puerto AX.25 %s|| POPEM00006|Invlido nombre de puerto AX.25 %s|| POPEM00007|Invlido Indicativo %s|| POPEM00008|Invlido Indicativo AX.25 destinacin o digipeater|| POPEM00009|No puedo abrir el scalo AX.25, %s|| POPEM00010|No puedo atar el scalo AX.25, %s|| POPEM00011|No puedo conectar al Indicativo AX.25, %s|| POPEM00012|AX.25 error en la salida de UI|| POPEM00013|AX.25 problema con el archivo axports|| POPEM00014|AX.25 invlido nombre de puerto %s|| POPEM00015|Error abriendo la interfz %d, duro fallo|| POPEM00016|Error abriendo la interfz %d Tiempo agotado|| POPEM00017|No hay mas interfz disponible!|| POPEM00018|Dato requerido - Simple Lnea de Mensaje| POPEM00019|El Puerto de transmisin est "off" para puerto %d| POPEM00020|Error banco de Datos!| POPEM00021|El soporte de AX.25 no est compilado en Xastir!|| POPEM00022|Error de entrada!| POPEM00023|Nombre de locacin no especificada!| POPEM00024|Nombre de Locacin especificada en uso!| POPEM00025|No Encontrado!|| POPEM00026|El Rastreo empezar cuando el aparezca|| POPEM00027|Info Impropia. Algunos campos vaco?|| POPEM00028|No se puede abrir el archivo|| POPEM00029|Encontrado!|| POPEM00030|Smbolo de Estacin Meteorolgica|| POPEM00031|Cambiado a smbolo WX '/_', otras opciones: '\_' '/W' y '\W'|| POPEM00032|Aviso: Usando Smbolo del National Weather Service!|| POPEM00033|No GPS Data!|| POPEM00034|Disactivando TX de Mi Posicin Hasta ver Data de GPS Vlido!|| POPEM00035|Warning|| POPEM00036|Notice|| POPEM00037|HSP interface present: GPS timing has been increased|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Salto de Locacin JMLPO00001|Localizacin de Mapa|| JMLPO00002|IR!|| JMLPO00003|Nombre de Nueva Localizacin:|| # # Boletines BULMW00001|Boletines|| BULMW00002|Lmite de Rango a (0, no hay lmite)|| BULMW00003|Cambio de Rango|| # # Trfico de todo los mensajes AMTMW00001|Trfico de todos los mensajes|| AMTMW00002|Lmite de Rango a (0, no hay lmite)|| # # Cadenas del Sintetizador SPCHSTR001|kilmetros|| SPCHSTR002|metros|| SPCHSTR003|millas|| SPCHSTR004|yardas|| SPCHSTR005|%s, distancia es %d %s.|| SPCHSTR006|%s, distancia es %.1f %s.|| SPCHSTR007|%s, distancia es %d %s %s %s.|| SPCHSTR008|%s, distancia es %.1f %s %s %s.|| SPCHSTR009|Nueva Alerta de WX|| SPCHSTR010|Nueva LLamada|| SPCHSTR011|Odo, D X, %s, en distancia de %.1f %s|| # SPCHDIRN00|norte de|| SPCHDIRS00|sur de|| SPCHDIRE00|este de|| SPCHDIRW00|oeste de|| SPCHDIRNE0|noreste de|| SPCHDIRNW0|noroeste de|| SPCHDIRSE0|sureste de|| SPCHDIRSW0|suroeste de|| # # Dilogo de selecin de Smbolo SYMSEL0001|Seleccione Smbolo|| SYMSEL0002|Tabla de Smbolo primario|| SYMSEL0003|Tabla de Smbolo Secundario|| # # Dilogo de la Propiedades de Impresora PRINT0001|Propiedades de Impresora|| PRINT0002|Ancho del Paper|| PRINT0003|Auto-Rotar Imagen PRINT0004|Rotar Imagen 90 CCW|| PRINT0005|Auto-Balancear Imagen|| PRINT0006|Balanza:|| PRINT0007|Forza el predefinido color de fondo a blanco|| PRINT0008|Imprime en Blanco y Negro|| PRINT0016|Colores Revertidos|| PRINT0009|Resolucin de Postscript:|| PRINT0010|Prevista|| PRINT0011|Imprimir al archivo|| PRINT0012|Guardar imagen a un archivo...|| PRINT0013|Convirtiendo a Postscript...|| PRINT0014|Creando archivo de impresin Finalizado|| PRINT0015|Estado de Impresora|| # # Dilogo de la Propiedades de Impresora PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Dilogo de localizar forma FEATURE001|Nombre:|| FEATURE002|Estado/Provincia:|| FEATURE003|Pais:|| FEATURE004|Cuadratura del Mapa:|| FEATURE005|Tipo:|| FEATURE006|GNIS Archivo:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Dilogo de Calcular Coordenada COORD001|Calcula Coordenada|| COORD002|Calc|| COORD003|Calcular|| COORD004|Limpiar|| COORD005|UTM|| COORD006|Latitud o|| COORD007|Longitud o|| COORD008|Zona|| COORD009|UTM Hacia Este|| COORD010|UTM Hacia Norte|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # Dilogo Baliza Inteligente SMARTB001|Baliza Inteligente|| SMARTB002|Alta Proporcin (secs):|| SMARTB003|Alta Velocidad (mph):|| SMARTB004|Alta Velocidad (kph):|| SMARTB005|Baja Proporcin (mins):|| SMARTB006|Baja Velocidad (mph):|| SMARTB007|Baja Velocidad (kph):|| SMARTB008|Mnima Vuelta (grados):|| SMARTB009|Vuelta de declive:|| SMARTB010|Tiempo de Espera (secs):|| SMARTB011|Activar Baliza Inteligente(tm)|| # # Dilogo Ajuste de Gamma GAMMA001|Ajuste Correccin de Gamma|| GAMMA002|Correccin Gamma|| # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Minsculo|| MAPFONT004|Map Font Pequeo|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distancia/Orientacin en lnea de estado PULDNDB001|Estado de Distancia/Orientacin|| # # Transferir Operaciones de GPS GPS001|Transferir GPS|| GPS002|Nombre de Archivo|| GPS003|Seleccionar Color|| GPS004|Rojo|| GPS005|Verde|| GPS006|Negro|| GPS007|Blanco|| GPS008|Naranja|| GPS009|Azul|| GPS010|Amarillo|| GPS011|Violeta|| # # Dilogo de Propiedades de Mapa MAPP001|Propiedades de Mapa|| MAPP002|Max Min Dibuja Mapa USGS Auto|| MAPP003|Zoom Zoom Capa Llenado DRG Mapa Sendero/NombreArchivo|| MAPP004|Cambie Capa->|| MAPP005|Llenado->|| MAPP006|S|| MAPP007|No|| MAPP008|Automapas->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # Cadenas del Tiempo TIME001|Da|| TIME002|Das|| TIME003|Hora|| TIME004|Horas|| TIME005|Minuto|| TIME006|Minutos|| TIME007|Segundo|| TIME008|Segundos|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.2/config/nwsc_ddmmyy.dbfawk000066400000000000000000000047431501463444000213400ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTYNAME:STATE:FIPS"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. /^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. /^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} /^STATE=(..)$/ {name="$name County"; key="$1"; next} /^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_09.dbfawk000066400000000000000000000053231501463444000216430ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2009, and differs from the earlier format. Shapefiles from 2008 # are matched by the file "nwsc_ddmmyy.dbfawk" instead. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:SHAPE_LENG:SHAPE_AREA:STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTYNAME:STATE:FIPS"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. /^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. /^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} /^STATE=(..)$/ {name="$name County"; key="$1"; next} /^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_09b.dbfawk000066400000000000000000000053121501463444000220030ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2009, and differs from the earlier format. Shapefiles from 2008 # are matched by the file "nwsc_ddmmyy.dbfawk" instead. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID_1:OBJECTID:STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTYNAME:STATE:FIPS"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. /^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. /^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} /^STATE=(..)$/ {name="$name County"; key="$1"; next} /^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_10.dbfawk000066400000000000000000000053701501463444000216350ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2009, and differs from the earlier format. Shapefiles from 2008 # are matched by the file "nwsc_ddmmyy.dbfawk" instead. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID_1:OBJECTID_2:OBJECTID:STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:LON:LAT:SHAPE_LENG:SHAPE_LE_1:Shape_Le_2:Shape_Area"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. #/^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. #/^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} #/^STATE=(..)$/ {name="$name County"; key="$1"; next} #/^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_10a.dbfawk000066400000000000000000000053501501463444000217740ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2009, and differs from the earlier format. Shapefiles from 2008 # are matched by the file "nwsc_ddmmyy.dbfawk" instead. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:ID:WFO:GL_WFO:SHAPE_LENG:SHAPE_AREA:MZ:AJOIN0:AJOIN1:STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. #/^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. #/^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} #/^STATE=(..)$/ {name="$name County"; key="$1"; next} #/^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_13.dbfawk000066400000000000000000000053111501463444000216330ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2009, and differs from the earlier format. Shapefiles from 2008 # are matched by the file "nwsc_ddmmyy.dbfawk" instead. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID_1:STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT:Shape_Leng:Shape_Area"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. #/^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. #/^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} #/^STATE=(..)$/ {name="$name County"; key="$1"; next} #/^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsc_ddmmyy_15.dbfawk000066400000000000000000000051701501463444000216400ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # This DBFAWK file matches the set of county shapefiles that was published # by NOAA in 2015, which differs from earlier formats of these county # shapefiles. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="LON:LAT:STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. #/^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. #/^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} #/^STATE=(..)$/ {name="$name County"; key="$1"; next} #/^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/nwsfz_ddmmyy_19.dbfawk000066400000000000000000000037361501463444000220470ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:LON:LAT:InPoly_FID:SimPgnFlag:MaxSimpTol:MinSimpTol"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwshzddmmyy.dbfawk000066400000000000000000000035731501463444000214000ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:NAME:LAT:LON:id"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} #/^ID=(..)(.*)$/ {key="$1_$2"; next} #/^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwshzddmmyy_old14.dbfawk000066400000000000000000000035701501463444000224000ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:NAME:LAT:LON"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} #/^ID=(..)(.*)$/ {key="$1_$2"; next} #/^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzddmmyy.dbfawk000066400000000000000000000035101501463444000213740ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:NAME:GL_WFO:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzddmmyy_09.dbfawk000066400000000000000000000035451501463444000217140ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:ID:WFO:NAME:GL_WFO:LON:LAT:Shape_Leng:Shape_Area"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzddmmyy_11.dbfawk000066400000000000000000000035261501463444000217040ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:GL_WFO:NAME:AJOIN0:AJOIN1:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzddmmyy_16.dbfawk000066400000000000000000000035641501463444000217130ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:ID:WFO:GL_WFO:NAME:AJOIN0:AJOIN1:LON:LAT:Shape_Leng:Shape_Area"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzddmmyy_17.dbfawk000066400000000000000000000035071501463444000217110ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:GL_WFO:NAME:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsmzoddmmyy.dbfawk000066400000000000000000000035031501463444000215550ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:NAME:WFO_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(.*)$/ {key="$1"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsozddap12.dbfawk000066400000000000000000000036051501463444000211530ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:LON:LAT:Location:Name"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsozddmmyy.dbfawk000066400000000000000000000035761501463444000214120ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:NAME:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsozddmmyy_09.dbfawk000066400000000000000000000035741501463444000217200ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:LON:LAT:NAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsozddmmyy_14.dbfawk000066400000000000000000000036071501463444000217110ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:LON:LAT:LOCATION:NAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsozddmmyy_14b.dbfawk000066400000000000000000000035761501463444000220600ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:NAME:LAT:LON:id"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsw_ddjn12.dbfawk000066400000000000000000000035411501463444000211360ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="CWA:WFO:Lon:Lat"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy.dbfawk000066400000000000000000000035431501463444000213610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:CWA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_09.dbfawk000066400000000000000000000035461501463444000216740ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:CWA:AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_10.dbfawk000066400000000000000000000035611501463444000216610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="AJOIN0:AJOIN1:WFO:CWA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_13.dbfawk000066400000000000000000000036231501463444000216630ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="AJOIN0:AJOIN1:WFO:CWA:LON:LAT"; dbfinfo="OBJECTID:WFO:CWA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_14.dbfawk000066400000000000000000000036041501463444000216630ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID_1:CWA:Shape_Leng:Shape_Area:WFO:lon:lat"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_14a.dbfawk000066400000000000000000000035411501463444000220240ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="CWA:WFO:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_17.dbfawk000066400000000000000000000036121501463444000216650ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="CWA:WFO:LON:LAT:Region:FullStaId:CityState:City:State:ST"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_20.dbfawk000066400000000000000000000036241501463444000216620ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:CWA:WFO:LON:LAT:Region:FullStaId:CityState:City:State:ST"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsw_ddmmyy_22.dbfawk000066400000000000000000000036241501463444000216640ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:CWA:WFO:LON:LAT:REGION:FULLSTAID:CITYSTATE:CITY:STATE:ST"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.2/config/nwsz1ddmmyy.dbfawk000066400000000000000000000036621501463444000213100ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy.dbfawk000066400000000000000000000037121501463444000213620ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:CEN_LAT:CEN_LON:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_09.dbfawk000066400000000000000000000037531501463444000216770ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:CEN_LAT:CEN_LON:SHAPE_LENG:SHAPE_AREA:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_10.dbfawk000066400000000000000000000037341501463444000216660ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:SHAPE_LENG:SHAPE_AREA:FI:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_10b.dbfawk000066400000000000000000000037231501463444000220260ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:AJOIN0:AJOIN1:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_10c.dbfawk000066400000000000000000000036721501463444000220320ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_11.dbfawk000066400000000000000000000040631501463444000216630ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. #dbfinfo="OBJECTID:STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME:Shape_Leng:Shape_Area"; dbfinfo="OBJECTID:STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_13.dbfawk000066400000000000000000000041351501463444000216650ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. #dbfinfo="OBJECTID:STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME:Shape_Leng:Shape_Area"; dbfinfo="OBJECTID:STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME:Shape_Leng:Shape_Le_1:Shape_Le_2:Shape_Area"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwsz_ddmmyy_19.dbfawk000066400000000000000000000037461501463444000217020ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME:InPoly_FID:SimPgnFlag:MaxSimpTol:MinSimpTol"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/nwszoddmmyy.dbfawk000066400000000000000000000036741501463444000214110ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/pointlm.dbfawk000066400000000000000000000052011501463444000204530ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for POINTLM # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUNTYNS:POINTID:FULLNAME:MTFCC"; dbfinfo="STATEFP:COUNTYFP:ANSICODE:POINTID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=C3/ {display_level=512;color=50; next} # Hospitals /^MTFCC=K12/ {filled=1; fill_color=12; label_color=12; display_level=256; label_level=128; font_size=12; next} # Schools /^MTFCC=K25/ {filled=1; fill_color=5; label_color=5; display_level=256; label_level=64; font_size=10; next} # Airports /^MTFCC=K24/ {filled=1; fill_color=13; label_color=13; display_level=256; label_level=128; font_size=12; next} # buildings /^MTFCC=K/ {filled=1; fill_color=2; label_color=2; display_level=256; next} # PLCC /^MTFCC=L/ {display_level=0; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/predefined_EVENT.sys000066400000000000000000000062051501463444000214240ustar00rootroot00000000000000# # # Copyright (C) 2000-2023 The Xastir Group # # This file contains definitions for the Create SAR objects menu # # The objects defined here are typical Public Service Event objects. # # The objects defined here are ones that might be used in a public # service event such as a 5k race. Customize this file to fit your # needs. # # Typical modifications include internationalizing the names and menu text # and adding your own custom objects. # # To select this file as the source of custom objects in the Create SAR # objects menu, use the Load SAR objects menu options in the Configure # defaults dialog (File/Configure/Defaults). # # Lines beginning with # are comments and will be ignored. # # Each line contains a tab separated variable and value pair. # Each set of lines defines an object as specified on the prepared # objects menu. Each set of lines must have variables defined in the # following order: # # NAME The name of the object. # Maximum length = MAX_CALLSIGN - 1 or - 2, to allow for Name1, Name2 # incrementing numbers with multiple objects. # If name ends with a - then the first object will be called Name-1, # the second Name-2, and so on. If name does not end with a - then # The first object will be called Name, the second Name2. # PAGE The APRS symbol code page, / or \ # Maximum length = 1 character. # SYMBOL The APRS symbol specifier. Maximum length = 1 character. # DATA Additional data (such as probability circles) to follow the symbol in # the APRS string for the object # Use DATA NULL if there is no additional data, or omit the DATA line. # Maximum length = PREDEFINED_OBJECT_DATA_LENGTH = 44 # MENU The text to appear on the prepared objects menu for this object. # Maximum length = 25 characters. # HIDDENCHILD NO for entries that appear on the menu. YES for a second # object to be created at the same time as the one above it. # This is a workaround to create an IPP and an IPP_ with different # probability circles in the same place at the same time. # YES is case sensitive. # HIDDENCHILD must be the last line in each object. # # NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required for each object. # # Each set of lines specifying an object should be separated by a blank line # for clarity. Blank lines are ignored. # # The maximum number of objects that can be shown on the predefined object # menu is defined by the constant MAX_NUMBER_OF_PREDEFINED_OBJECTS. NAME ICP PAGE / SYMBOL c DATA NULL MENU ICP: Command Post HIDDENCHILD NO NAME Water PAGE / SYMBOL w DATA NULL MENU Water HIDDENCHILD NO # FirstAid post # "FirstAid" as name will only allow FirstAid1 to FirstAid9 # due to the default length constraint on object names. NAME Aid #NAME FirstAid #NAME Aid- PAGE / # A is blue field with white cross, + is red cross SYMBOL A #SYMBOL + DATA NULL MENU Aid: First Aid #MENU First Aid #MENU Aid-n: First Aid HIDDENCHILD NO NAME Staging PAGE S SYMBOL 0 DATA NULL MENU Staging HIDDENCHILD NO NAME Waypt- PAGE \ SYMBOL m DATA NULL MENU Waypt-n: Waypoint HIDDENCHILD NO NAME Toilets PAGE \ SYMBOL r DATA NULL MENU Toilets HIDDENCHILD NO Xastir-Release-2.2.2/config/predefined_SAR.sys000066400000000000000000000067641501463444000212020ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This file contains definitions for the Create SAR objects menu # # The objects defined here are typical Search and Rescue and ICS objects. # # You may modify this file to produce a custom set of prepared objects. # Typical modification would be changing probability circles from # miles to kilometers, placing probability circles around the PLS # instead of the IPP, internationalizing the names and menu text, # and adding your own standard objects. # # To select this file as the source of custom objects in the Create SAR # objects menu, use the Load SAR objects menu options in the Configure # defaults dialog (File/Configure/Defaults). # # Lines beginning with # are comments and will be ignored. # # Each line contains a tab separated variable and value pair. # Each set of lines defines an object as specified on the prepared # objects menu. Each set of lines must have variables defined in the # following order: # # NAME The name of the object. # Maximum length = MAX_CALLSIGN - 1 or - 2, to allow for Name1, Name2 # incrementing numbers with multiple objects. # If name ends with a - then the first object will be called Name-1, # the second Name-2, and so on. If name does not end with a - then # The first object will be called Name, the second Name2. # PAGE The APRS symbol code page, / or \ # Maximum length = 1 character. # SYMBOL The APRS symbol specifier. Maximum length = 1 character. # DATA Additional data (such as probability circles) to follow the symbol in # the APRS string for the object # Use DATA NULL if there is no additional data, or omit the DATA line. # Maximum length = PREDEFINED_OBJECT_DATA_LENGTH = 44 # MENU The text to appear on the prepared objects menu for this object. # Maximum length = 25 characters. # HIDDENCHILD NO for entries that appear on the menu. YES for a second # object to be created at the same time as the one above it. # This is a workaround to create an IPP and an IPP_ with different # probability circles in the same place at the same time. # YES is case sensitive. # HIDDENCHILD must be the last line in each object. # # NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required for each object. # # Each set of lines specifying an object should be separated by a blank line # for clarity. Blank lines are ignored. # # The maximum number of objects that can be shown on the predefined object # menu is defined by the constant MAX_NUMBER_OF_PREDEFINED_OBJECTS. NAME ICP PAGE / SYMBOL c DATA NULL MENU ICP: Command Post HIDDENCHILD NO NAME Staging PAGE S SYMBOL 0 DATA NULL MENU Staging HIDDENCHILD NO NAME IPP PAGE / SYMBOL / #circles at .75 and 1 miles DATA Pmin0.75,Pmax1.0 #circles at 2 and 3 kilometers #DATA Pmin1.24,Pmax1.86 MENU IPP: InitialPlanningPoint HIDDENCHILD NO NAME IPP_ PAGE / SYMBOL / # circles at .25 and .5 miles DATA Pmin0.25,Pmax0.5 # circles at .5 and 1 kilometers #DATA Pmin0.31,Pmax0.62 MENU [not shown] HIDDENCHILD YES NAME PLS PAGE / SYMBOL / DATA NULL MENU PLS: Point Last Seen HIDDENCHILD NO NAME LKP PAGE / SYMBOL . DATA NULL MENU LKP: Last Known Point HIDDENCHILD NO NAME Base PAGE B SYMBOL 0 DATA NULL MENU Base HIDDENCHILD NO NAME Helibase PAGE H SYMBOL 0 DATA NULL MENU Helibase HIDDENCHILD NO # Using Heli- will produce an object named Heli-1 # with subsequent objects Heli-2, Heli-3, etc. NAME Heli- PAGE / SYMBOL / DATA NULL MENU Heli-n Helispot HIDDENCHILD NO NAME Camp PAGE C SYMBOL 0 DATA NULL MENU Camp HIDDENCHILD NO Xastir-Release-2.2.2/config/stored_track.dbfawk000066400000000000000000000005051501463444000214570ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # BEGIN { dbfinfo="Credits:DateTime:Label; dbffields="Label:DateTime"; } BEGIN_RECORD {key=""; lanes=3; color=12; name=""; filled=0; pattern=0; display_level=65536; label_level=256; label_color=12; symbol=""} /^Label=(.*)$/ {name="$1";} /^DateTime=(.*)$/ {name="$name ($1)";} Xastir-Release-2.2.2/config/tabblock.dbfawk000066400000000000000000000044751501463444000205660ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2008 TigerMaps for TABBLOCK # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUNTYNS:STATEFP00:COUNTYFP00:TRACTCE00:BLOCKCE00:SUFFIX1CE:BLKIDFP:NAME:MTFCC:UR00:UACE00:FUNCSTAT"; dbfinfo="STATEFP:COUNTYFP:COUNTYNS:STATEFP00:COUNTYFP00:TRACTCE00:BLOCKCE00:SUFFIX1CE:BLKIDFP:NAME:MTFCC:UR:UACE:FUNCSTAT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="UR:NAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=11; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } #/^NAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=G5/ {next} /^UR=U/ {display_level=2048;filled=1;color=99;fill_color=99; skip} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tgr2shp.dbfawk000066400000000000000000000251451501463444000203730ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the command: # ogr2ogr -f "ESRI Shapefile" -t_srs "EPSG:4326" out_directory in_directory # # THis file is identical to the file "tgrlk" except for the "dbfinfo" variable # that is used to recognize the signature of the shapefiles. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="MODULE:TLID:SIDE1:SOURCE:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC:FRADDL:TOADDL:FRADDR:TOADDR:FRIADDL:TOIADDL:FRIADDR:TOIADDR:ZIPL:ZIPR:AIANHHFPL:AIANHHFPR:AIHHTLIL:AIHHTLIR:CENSUS1:CENSUS2:STATEL:STATER:COUNTYL:COUNTYR:COUSUBL:COUSUBR:SUBMCDL:SUBMCDR:PLACEL:PLACER:TRACTL:TRACTR:BLOCKL:BLOCKR"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="TLID:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^TLID=(.*)$/ {key=$1; next} # name: concatenate FEDIRP (direction prefix), FENAME (name), # FETYPE (type: Rd, Ln, Pky, etc.) and FEDIRS (direction suffix). # also abbreviate United States Highway to US, etc. /^FEDIRP=(.+)$/ {name="$1 ";next} /^FENAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^FENAME=State Highway (.*)$/ {name="$(name)State $1";next} /^FENAME=State Route (.*)$/ {name="$(name)SR $1";next} /^FENAME=(.*)$/ {name="$(name)$1"; next} /^FETYPE=(.+)$/ {name="$(name) $1"; next} /^FEDIRS=(.+)$/ {name="$(name) $1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway # "P" types denote "Provisional" streets that had not been field checked # or verified through aerial photography as of the date of preparation of # the TIGER/Line data. They are otherwise equivalent to "A" types, and # we'll just display them the same way. /^CFCC=[AP]1/ {lanes=4; color=4; label_level=512; font_size=3; next} /^CFCC=[AP]2/ {lanes=3; color=8; label_level=256; font_size=2; next} /^CFCC=[AP]3/ {lanes=2; color=8; label_level=128; font_size=1; next} /^CFCC=[AP]3[1-6]/ {display_level=256; next} /^CFCC=[AP]3[7-8]/ {display_level=128; next} /^CFCC=[AP]4/ {display_level=96; label_level=16; color=40; lanes=1; next} /^CFCC=[AP]5/ {lanes=2; color=40; display_level=64; font_size=1; next} /^CFCC=[AP]65/ {lanes=2; color=8; pattern=2; font_size=1; next} /^CFCC=[AP]6[^5]/ {color=40; display_level=64; next} /^CFCC=[AP]7[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} /^CFCC=[AP]7[03-9]/ {lanes=1; color=40; pattern=2; display_level=64; next} # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F10$/{color=255; fill_color=255; label_level=32; display_level=512; pattern=0; next} /^CFCC=F/{display_level=0; next} # (G not used by census; tig2aprs uses for special maps) # H: hydrography # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean # H60 - gravel pit or quarry filled with water # H70 - nonvisibile.... # H80 - special water features # H81 - glacier # Don't display hydrology unless zoomed all the way in --- adjust to taste, # in NM anything more than this looks absurd coz every intermittent wash # would show up as a blue line, which is just wrong. /^CFCC=H/ {lanes=0; color=26; fill_color=26; label_color=26; display_level=1;} /^CFCC=H01/ {pattern=0; display_level=512; lanes=1; next} /^CFCC=H02/ {pattern=2; display_level=1; next} /^CFCC=H[124]2/ {lanes=1; pattern=2; display_level=128; next} # These filled patterns don't actually work: the tiger shapefiles produced # by ogr2ogr do not have the polygon features readily accessible! /^CFCC=H[34][01]/ {lanes=1; pattern=0; filled=1; fill_style=0; display_level=512; next} /^CFCC=H32/ {lanes=1; pattern=1; filled=1; fill_style=1; display_level=512; next} /^CFCC=H[1-6][013-9]/ {lanes=1; display_level=512; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1; display_level=1} /^CFCC=H81/ {color=15; fill_color=15; display_level=256; next} # X00 - feature not yet classified # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tgr2shppoly.dbfawk000066400000000000000000000254471501463444000213040ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the Xastir_tigerpoly.py utility # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="MODULE:FILE:CENID:POLYID:STATECU:COUNTYCU:TRACT:BLOCK:BLOCKSUFCU:RS_A1:AIANHHFPCU:AIANHHCU:AIHHTLICU:ANRCCU:AITSCECU:AITSCU:CONCITCU:COUSUBCU:SUBMCDCU:PLACECU:SDELMCU:SDSECCU:SDUNICU:RS_A20:RS_A21:RS_A22:CDCU:ZCTA5CU:ZCTA3CU:RS_A4:RS_A5:RS_A6:RS_A7:RS_A8:RS_A9:CBSACU:CSACU:NECTACU:CNECTACU:METDIVCU:NECTADIVCU:RS_A14:RS_A15:RS_A16:RS_A17:RS_A18:RS_A19:STATE:COUNTY:BLKGRP:AIANHHFP:AIANHH:AIHHTLI:ANRC:AITSCE:AITS:CONCIT:COUSUB:SUBMCD:PLACE:SDELM:SDSEC:SDUNI:MSACMSA:PMSA:NECMA:CD106:CD108:PUMA5:PUMA1:ZCTA5:ZCTA3:TAZ:TAZCOMB:UA:UR:VTD:SLDU:SLDL:UGA:POLYLONG:POLYLAT:WATER:LAND:SOURCE:CFCC:LANAME:LALONG:LALAT:FILLER"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="WATER:CFCC:LANAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=0; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0; fill_stipple=0 } # Name -- only features that have landmark records get names /^LANAME=None$/ {next} /^LANAME=(.*)$/ {name="$1"; next} #We need this just in case there is no CFCC code to tell us we're a water # feature #Perennial water /^WATER=1$/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;} #intermittent water /^WATER=2$/ {filled=1; fill_style=2; fill_stipple=0; color=117; fill_color=117; label_color=26; display_level=512;pattern=1;} # These are *all* the allowed feature classes, even those that aren't # polygon types. We won't actually bother testing for anything other # than the ones we expect to find, lest we spend too much time filtering. # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway #Roads are not going to be polygons, don't even check # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram # /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway # /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # color is RosyBrown2 /^CFCC=D1/ { filled=1; color=112; fill_color=112; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission /^CFCC=D2/ {filled=1; color=14; fill_color=14; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm /^CFCC=D3/ {filled=1; color=13; fill_color=13; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution /^CFCC=D4/ { filled=1; color=20; fill_color=20; fill_style=2; fill_stipple=0; display_level=64; font_size=1; next} # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D57 - Airport # color is "gray81" /^CFCC=D5/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=1; display_level=512; font_size=1; next} # D60 - Employment center # D61 - Shopping center # D62 - Industrial Building or Ind. park # D63 - Office Building or office park # D64 - Amusement Center # D65 - Government Center # D66 - Other emplyoment center /^CFCC=D6/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # D70 - tower # D71 - lookout tower /^CFCC=D7/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D80 - open space # D81 - golf course # D82 - cemetery # Color is "tgr_park_1" /^CFCC=D8[01]/ {filled=1; color=114; fill_color=114; fill_style=2; fill_stipple=0; display_level=512; font_size=1; next} # D83 - national park # D84 - national forest # D85 - state or local park or forest # color is "tgr_forest_1" /^CFCC=D8[3-5]/ {filled=1; color=116; fill_color=116; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D9/ {filled=1; color=101; fill_color=101; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # Don't display the E's # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F/{filled=1; color=115; fill_color=115; fill_style=0; label_level=32; display_level=512; pattern=0; next} #/^CFCC=F/{display_level=0; next} # Don't bother with the F's either for now # (G not used by census; tig2aprs uses for special maps) # H: hydrography # Color is "tgr_water_1" /^CFCC=H/ {filled=1; color=117; fill_color=3; label_color=26; display_level=512;} # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " /^CFCC=H0/ {filled=1; fill_style=2; fill_stipple=2; display_level=4096; label_level=16; lanes=1} /^CFCC=H02/ {filled=1; fill_stipple=0; pattern=1; next} # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean /^CFCC=H[1-5]/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} /^CFCC=H[1-4]2/ {filled=1; fill_stipple=0; pattern=1; next} # H60 - gravel pit or quarry filled with water /^CFCC=H6/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H81/ {filled=1; color=15; fill_color=15; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} Xastir-Release-2.2.2/config/tgr2shppoly_2006.dbfawk000066400000000000000000000256611501463444000217510ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the Xastir_tigerpoly.py utility # # It differs from the "tgr2shppoly.dbfawk" file only in the DBF signature, # which changed between the 2004 and 2006 TIGER/Line releases. # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="MODULE:FILE:CENID:POLYID:STATECU:COUNTYCU:TRACT:BLOCK:BLOCKSUFCU:RS_A1:AIANHHFPCU:AIANHHCU:AIHHTLICU:ANRCCU:AITSCECU:AITSCU:CONCITCU:COUSUBCU:SUBMCDCU:PLACECU:SDELMCU:SDSECCU:SDUNICU:RS_A20:RS_A21:RS_A22:CDCU:ZCTA5CU:ZCTA3CU:RS_A4:RS_A5:RS_A6:RS_A7:RS_A8:RS_A9:CBSACU:CSACU:NECTACU:CNECTACU:METDIVCU:NECTADIVCU:RS_A14:UACU:URCU:RS_A17:RS_A18:RS_A19:STATE:COUNTY:BLKGRP:AIANHHFP:AIANHH:AIHHTLI:ANRC:AITSCE:AITS:CONCIT:COUSUB:SUBMCD:PLACE:SDELM:SDSEC:SDUNI:MSACMSA:PMSA:NECMA:CD106:CD108:PUMA5:PUMA1:ZCTA5:ZCTA3:TAZ:TAZCOMB:UA:UR:VTD:SLDU:SLDL:UGA:POLYLONG:POLYLAT:WATER:LAND:SOURCE:CFCC:LANAME:LALONG:LALAT:FILLER"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="WATER:CFCC:LANAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=0; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0; fill_stipple=0 } # Name -- only features that have landmark records get names /^LANAME=None$/ {next} /^LANAME=(.*)$/ {name="$1"; next} #We need this just in case there is no CFCC code to tell us we're a water # feature #Perennial water /^WATER=1$/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;} #intermittent water /^WATER=2$/ {filled=1; fill_style=2; fill_stipple=0; color=117; fill_color=117; label_color=26; display_level=512;pattern=1;} # These are *all* the allowed feature classes, even those that aren't # polygon types. We won't actually bother testing for anything other # than the ones we expect to find, lest we spend too much time filtering. # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway #Roads are not going to be polygons, don't even check # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram # /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway # /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # color is RosyBrown2 /^CFCC=D1/ { filled=1; color=112; fill_color=112; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission /^CFCC=D2/ {filled=1; color=14; fill_color=14; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm /^CFCC=D3/ {filled=1; color=13; fill_color=13; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution /^CFCC=D4/ { filled=1; color=20; fill_color=20; fill_style=2; fill_stipple=0; display_level=64; font_size=1; next} # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D57 - Airport # color is "gray81" /^CFCC=D5/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=1; display_level=512; font_size=1; next} # D60 - Employment center # D61 - Shopping center # D62 - Industrial Building or Ind. park # D63 - Office Building or office park # D64 - Amusement Center # D65 - Government Center # D66 - Other emplyoment center /^CFCC=D6/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # D70 - tower # D71 - lookout tower /^CFCC=D7/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D80 - open space # D81 - golf course # D82 - cemetery # Color is "tgr_park_1" /^CFCC=D8[01]/ {filled=1; color=114; fill_color=114; fill_style=2; fill_stipple=0; display_level=512; font_size=1; next} # D83 - national park # D84 - national forest # D85 - state or local park or forest # color is "tgr_forest_1" /^CFCC=D8[3-5]/ {filled=1; color=116; fill_color=116; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D9/ {filled=1; color=101; fill_color=101; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # Don't display the E's # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F/{filled=1; color=115; fill_color=115; fill_style=0; label_level=32; display_level=512; pattern=0; next} #/^CFCC=F/{display_level=0; next} # Don't bother with the F's either for now # (G not used by census; tig2aprs uses for special maps) # H: hydrography # Color is "tgr_water_1" /^CFCC=H/ {filled=1; color=117; fill_color=3; label_color=26; display_level=512;} # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " /^CFCC=H0/ {filled=1; fill_style=2; fill_stipple=2; display_level=4096; label_level=16; lanes=1} /^CFCC=H02/ {filled=1; fill_stipple=0; pattern=1; next} # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean /^CFCC=H[1-5]/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} /^CFCC=H[1-4]2/ {filled=1; fill_stipple=0; pattern=1; next} # H60 - gravel pit or quarry filled with water /^CFCC=H6/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H81/ {filled=1; color=15; fill_color=15; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} Xastir-Release-2.2.2/config/tgrcty.dbfawk000066400000000000000000000041421501463444000203100ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "cty" polygon shapefiles # which are named tgrSSCCCcty00.dbf, where SSCCC are the FIPS state and # county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:FIPSSTCO:STATE:COUNTY"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTY:FIPSSTCO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; fill_color=11; color=8; name=""; filled=0; pattern=0; display_level=8192; label_level=512; label_color=20; font_size=4; symbol=""} # name: name is just the county name. /^COUNTY=(.*)$/ {name="$1"; next} # key: set the search key to be the FIPS code. Not currently used. # also append County to the name except for Louisiana, use Parish: /^FIPSSTCO=(22.*)$/ {name="$name Parish"; key=$1; next} /^FIPSSTCO=(.*)$/ {name="$name County"; key=$1; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tgrkgl.dbfawk000066400000000000000000000051051501463444000202660ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "kgl" (Key Geographic # Location) shapefiles which are named tgrSSCCCkgl.dbf, where SSCCC # are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:POLYID:COUNTY:CFCC:KGLNAME"; # dbffields is which of the above fields we actually want to look at. dbffields="KGLNAME:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; fill_color=255; color=8; name=""; filled=1; pattern=0; display_level=0; label_level=0; label_color=8; font_size=2; symbol="/. "} # name and key are both the KGL name /^KGLNAME=(.*)$/ {name=$1; key=$1; next} # CFCC=D.. for landmarks. Use the same code here and for tgrlk. #D2: residence? #D23: trailer park #D28: campground /^CFCC=D2/ {symbol="/- "; display_level=64; label_level=32} /^CFCC=D23$/ {symbol="/R "; next} /^CFCC=D28$/ {symbol="/; "; next} /^CFCC=D2/ {next} #D31: hospital /^CFCC=D31$/ {color=9; symbol="/h "; display_level=128; label_level=64; next} #D40: unknown educational or religious #D41: sorority or fraternity #D42: convent or monastery #D43: educational institution #D44: religious institution /^CFCC=D4/ {color=8; symbol="/K "; display_level=64; label_level=32} /^CFCC=D4[03]$/ {color=14; next} #D51: airport #D54: harbor /^CFCC=D51$/ {symbol="/' "; display_level=128; label_level=32; next} /^CFCC=D54$/ {symbol="\\s "; display_level=128; label_level=32; next } #DB: state forests, etc. /^CFCC=D8/ {color=73; display_level=64; label_level=32; next} # don't need special end case handling... #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tgrlk.dbfawk000066400000000000000000000224621501463444000201240ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lk" shapefiles which are # named tgrSSCCClk[A-H].dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="TLID:FNODE:TNODE:LENGTH:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC:FRADDL:TOADDL:FRADDR:TOADDR:ZIPL:ZIPR:CENSUS1:CENSUS2:CFCC1:CFCC2:SOURCE"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="TLID:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^TLID=(.*)$/ {key=$1; next} # name: concatenate FEDIRP (direction prefix), FENAME (name), # FETYPE (type: Rd, Ln, Pky, etc.) and FEDIRS (direction suffix). # also abbreviate United States Highway to US, etc. /^FEDIRP=(.+)$/ {name="$1 ";next} /^FENAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^FENAME=State Highway (.*)$/ {name="$(name)State $1";next} /^FENAME=State Route (.*)$/ {name="$(name)SR $1";next} /^FENAME=(.*)$/ {name="$(name)$1; next} /^FETYPE=(.+)$/ {name="$(name) $1"; next} /^FEDIRS=(.+)$/ {name="$(name) $1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway /^CFCC=A1/ {lanes=4; color=4; label_level=512; font_size=3; next} /^CFCC=A2/ {lanes=3; color=8; label_level=256; font_size=2; next} /^CFCC=A3/ {lanes=2; color=8; label_level=128; font_size=1; next} /^CFCC=A3[1-6]/ {display_level=256; next} /^CFCC=A3[7-8]/ {display_level=128; next} /^CFCC=A4/ {display_level=96; label_level=16; color=40; lanes=1; next} /^CFCC=A5/ {lanes=2; color=40; display_level=64; font_size=1; next} /^CFCC=A65/ {lanes=2; color=8; pattern=2; font_size=1; next} /^CFCC=A6[^5]/ {color=40; display_level=64; next} /^CFCC=A7[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} /^CFCC=A7[03-9]/ {lanes=1; color=40; pattern=2; display_level=64; next} # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F10$/{color=255; fill_color=255; label_level=32; display_level=512; pattern=0; next} /^CFCC=F/{display_level=0; next} # (G not used by census; tig2aprs uses for special maps) # H: hydrography # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean # H60 - gravel pit or quarry filled with water # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H/ {lanes=0; color=26; fill_color=26; label_color=26} /^CFCC=H02/ {pattern=2; next} /^CFCC=H[1-6]2/ {lanes=1; pattern=2; next} /^CFCC=H[1-6][013-9]/ {lanes=1; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1} /^CFCC=H81/ {color=15; fill_color=15; next} # X00 - feature not yet classified # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tgrlpt.dbfawk000066400000000000000000000075031501463444000203140ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lpt" landmark point shapefiles which are # named tgrSSCCClpt.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:CFCC:NAME"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="CFCC:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=2; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^NAME=(.*)$/ {name="$1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D28/ {color=10; symbol="/] "; next} /^CFCC=D28/ {color=10; symbol="/\; "; next} /^CFCC=D31/ {color=9; symbol="/h "; next} /^CFCC=D40/ {color=5; next} /^CFCC=D41/ {color=2; next} /^CFCC=D42/ {color=1; next} /^CFCC=D43/ {color=2; symbol="/K "; next} /^CFCC=D44/ {color=1; next} /^CFCC=D51/ {color=14; symbol="/' "; next} /^CFCC=D52/ {color=14; symbol="/= "; next} /^CFCC=D53/ {color=14; symbol="/U "; next} /^CFCC=D54/ {color=1; symbol="/s "; next} /^CFCC=D70/ {color=1; symbol="/r "; next} /^CFCC=D8/ {color=2; next} # X - APRS extension to get all the various APRS symbols. # Useful for home made maps. Perhaps I shouldn't overload tiger/line # stuff with this and just define a new .dbfawk.... # are table, symbol, and overlay, /^CFCC=X(.*)$/ {symbol="$1"; next} Xastir-Release-2.2.2/config/tgrlpy.dbfawk000066400000000000000000000042321501463444000203150ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lpy" landmark polygon shapefiles which are # named tgrSSCCClklpy.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:POLYID:CENID:COUNTY:CFCC:LANDNAME:LANDPOLY"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="CFCC:LANDNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; fill_color=11; color=8; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=2; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^NAME=(.*)$/ {name="$1"; next} /^CFCC=H/ {lanes=0; color=26; fill_color=26} /^CFCC=H02/ {pattern=2; next} /^CFCC=H[1-6]2/ {lanes=1; pattern=2; next} /^CFCC=H[1-6][013-9]/ {lanes=1; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1} /^CFCC=H81/ {color=15; fill_color=15; next} Xastir-Release-2.2.2/config/tgrplc00.dbfawk000066400000000000000000000033041501463444000204260ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "plc" shapefiles which are # named tgrSSCCCplc00.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:COUNTY:PLACE:NAME"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=3; color=4; fill_color=103; name=""; filled=1; pattern=0; display_level=8192; label_level=256; label_color=8; font_size=2; symbol=""} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.2/config/tgrwat.dbfawk000066400000000000000000000042631501463444000203100ustar00rootroot00000000000000# Copyright (C) 2000-2023 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "wat" polygon shapefiles # which are named tgrSSCCCwat.dbf, where SSCCC are the FIPS state and # county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:COUNTY:CFCC:LANDNAME:LANDPOLY"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="CFCC:LANDNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=512; label_color=8; font_size=2; symbol=""} # name: name is just the county name. /^COUNTY=(.*)$/ {name="$1"; next} # key: set the search key to be the FIPS code. Not currently used. # also append County to the name except for Louisiana, use Parish: # XXX - find out what the FIPS code is for Louisiana and replace 99 with it: /^FIPSSTCO=(99.*)$/ {name="$name Parish"; key=$1; next} /^FIPSSTCO=(.*)$/ {name="$name County"; key=$1; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tl_2009_aiannh.dbfawk000066400000000000000000000035041501463444000214040ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { # dbfinfo extracted from tl_2009_27_aiannh.dbf: dbfinfo="AIANNHCE:AIANNHNS:AIANNHID:NAME:NAMELSAD:LSAD:CLASSFP:COMPTYP:AIANNHR:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON:STATEFP:AIANNHFP:PARTFLG"; dbffields="NAMELSAD:MTFCC"; } /^NAMELSAD=(.*)$/ {name="$1";next} /^MTFCC=G21/ { display_level=128; color=65; label_level=96; label_color=6; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_aits.dbfawk000066400000000000000000000034651501463444000211140ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { # dbfinfo extracted from tl_2009_27_aits.dbf: dbfinfo="AIANNHCE:TRSUBCE:TRSUBNS:TRSUBID:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON:STATEFP:TRSUBFP:PARTFLG"; dbffields="NAMELSAD:MTFCC"; } /^NAMELSAD=(.*)$/ {name="$1";next} /^MTFCC=G23/ { display_level=128; color=65; label_level=96; label_color=6; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_arealm.dbfawk000066400000000000000000000106011501463444000214030ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:AREAID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=40; label_color=48; fill_style=0; display_level=128; label_level=96; font_size=0; symbol=""; fill_stipple=0; } /^FULLNAME=(.*)$/ {name="$1";next} /^MTFCC=C3023/ { # Island color=40; label_color=48; font_size=1; display_level=256; label_level=128; next; } /^MTFCC=C3/ { # Other "C3" features not drawn - less than 20 in the whole dataset. display_level=0; next; } # Dwelling areas: /^MTFCC=K1121/ { # Apartment complex display_level=32; label_level=24; next; } /^MTFCC=K1228/ { # Campground display_level=64; label_level=48; filled=1; color=114 fill_color=114; fill_style=2; fill_stipple=2; label_color=0; font_size=1; next; } /^MTFCC=K122/ { # Trailer court, dormitory, hotel/resort, shelter/mission display_level=32; label_level=24; next; } /^MTFCC=K1231/ { # Hospital/hospice/urgent care facility display_level=64; label_level=48; filled=1; fill_color=112; fill_style=2; label_color=12; font_size=1; next; } /^MTFCC=K123[349]/ { # Nursing/retirement home, County home/poor farm, religious quarters display_level=32; label_level=24; next; } /^MTFCC=K123[567]/ { Juvenile Institution/Local Jail or Detention Center/Federal Penitentiary, State Prison display_level=32; label_level=24; filled=1; fill_style=2; fill_stipple=1; label_color=67; font_size=1; next; } # Government facilities: /^MTFCC=21[046]/ { # Governmental/Community Center/Government Center display_level=64; label_level=48; filled=1; fill_color=67; fill_style=2; fill_stipple=2; label_color=15; font_size=1; next; } /^MTFCC=K218/ { # Park/NPS land/Nat'l forest or other federal land/State, regional, county or city park display_level=64; label_level=32; filled=1; color=114 fill_color=114; fill_style=2; label_color=0; font_size=1; next; } # Commercial facilities /^MTFCC=K23/ { # We don't draw "K23" features display_level=0; next; } # Transit /^MTFCC=K24/ { # Marina/Airport/Train Station/Bus Terminal/Marine Terminal/Seaplane Anchorage/etc display_level=128; label_level=64; filled=1; color=115 fill_color=115; fill_style=2; label_color=0; font_size=1; next; } # Education/recreation/misc /^MTFCC=K254[03]/ { # University/College/School/Academy display_level=64; label_level=48; filled=1; fill_color=103; fill_style=2; font_size=0; next; } /^MTFCC=K2561/ { # Golf course display_level=64; label_level=48; filled=1; color=114 fill_color=100; fill_style=2; label_color=10; font_size=1; next; } /^MTFCC=K2582/ { # Cemetery (don't display - overlap w/ pointlm database) display_level=0; next; } /^MTFCC=K3544/ { # Place of worship (don't display - overlap w/ pointlm database) display_level=0; next; } /^MTFCC=K25/ { # All others (Amusement Center, Zoo) display_level=128; label_level=64; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_areawater.dbfawk000066400000000000000000000053071501463444000221240ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:HYDROID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # defaults for items below name=""; filled=1; pattern=0; key=""; lanes=1; fill_color=42; label_color=3; fill_style=0; display_level=128; label_level=32; font_size=0; symbol=""; } /^FULLNAME=(.*)$/ {name="$1";next} /^MTFCC=H2025/ { # Swamp/marsh color=42; fill_style=2; display_level=64; fill_stipple=0; next} /^MTFCC=H2030/ { # Lake/Pond, Reservoir, Bay/Estuary/Gulf/Sound, Ocean/Sea color=42; fill_style=0; next} /^MTFCC=H2040/ { # Reservoir color=42; fill_style=2; fill_stipple=2; display_level=64; next} /^MTFCC=H20[48]1/ { # Treatment Pond, Glacier color=42; fill_style=2; fill_stipple=1; display_level=64; next} /^MTFCC=H205/ { # Bay/Estuary/Gulf/Sound, Ocean/Sea color=42; fill_style=0; display_level=256; next} /^MTFCC=H2060/ { # Quarry filled w/ water color=42; fill_style=2; fill_stipple=2; display_level=64; name="$name (Quarry/Pit)"; next} /^MTFCC=H3010/ { # Stream/river color=42; next} /^MTFCC=H3013/ { # Braided stream color=42; display_level=64; next} /^MTFCC=H302/ { # Canal/ditch/aqueduct color=42; display_level=32; next} #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_county.dbfawk000066400000000000000000000040671501463444000214740ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:COUNTYNS:CNTYIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CSAFP:CBSAFP:METDIVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAMELSAD:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^NAMELSAD=(.*)$/ {name="$1"} /^MTFCC=G/ { # Counties/Parishes display_level=5000; color=254; label_level=2048; label_color=254; next} #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_cousub.dbfawk000066400000000000000000000041721501463444000214500ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo ="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CNECTAFP:NECTAFP:NCTADVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAMELSAD:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^NAMELSAD=(.*)$/ {name="$1";next; } /^MTFCC=G/ { # "County Subdivisions" - better known as cities, towns and townships. display_level=128; label_level=96; color=115; label_color=115; next} #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_edges.dbfawk000066400000000000000000000111251501463444000212330ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH:PERSIST:GCSEFLG:OFFSETL:OFFSETR:TNIDF:TNIDT"; dbffields="MTFCC:FULLNAME"; # level presets l_metro=256; l_county=80; l_city=32; l_town=16; l_hood=8; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^FULLNAME=(.*)$/ {name="$1";next; } # Non-road items: /^MTFCC=L4031/ { # Ski Lift or Arial Tramway display_level=l_city; color=12; pattern=2; name="$name (Ski Lift/Tramway)"; next; } /^MTFCC=L4165/ { # Ferry crossing lanes=3; pattern=2; color=72; label_color=72; display_level=l_metro; label_level=l_county; next; } /^MTFCC=[CHKLP]/ { # Don't draw other non-road items display_level=0; next; } /^MTFCC=R101/ { # Freight Rail (heavy/freight) color=80; label_color=48; pattern=1; lanes=2; display_level=128; label_level=64; next; } /^MTFCC=R105/ { # Passenger Rail (light/mass transit/cog rail) color=67; label_color=67; pattern=2; display_level=128; label_level=64; next; } # Public Roadways /^MTFCC=S11/ { # Freeways/major highways lanes=4; color=102; label_color=102; display_level=1024; label_level=256; font_size=2; next; } /^MTFCC=S12/ { # Secondary roads display_level=256; lanes=3; color=36; label_color=36; label_level=128; font_size=2; next; } /^MTFCC=S14/ { # Local roads, ramps and service drives/frontage roads display_level=40; color=44; label_color=44; label_level=16; color=48; lanes=1; next; } /^MTFCC=S15/ { # 4WD off-road trail color=99; label_color=99; display_level=64; font_size=1; name="$name (OHV/4WD trail)"; next; } /^MTFCC=S16/ { # ramps and service roads for Freeways/major highways color=102; label_color=102; display_level=32; next; } /^MTFCC=S20/ { # road median color=44; label_color=44; pattern=1; display_level=16; next; } /^MTFCC=S173/ { # alley color=44; label_color=44; pattern=1; display_level=32; name="$name (alley)"; next; } # Non-public roads (and public non-roads) /^MTFCC=S171/ { # walkway / pedestrian trail lanes=1; color=65; label_color=65; pattern=1; display_level=64; label_level=32; name="$name (walkway)"; next; } /^MTFCC=S172/ { # stairway lanes=1; color=12; label_color=12; pattern=2; display_level=32; label_level=20; name="$name (stairs)"; next; } /^MTFCC=S174/ { # private road lanes=1; color=23; label_color=23; pattern=2; display_level=32; label_level=20; name="$name (private road)"; next; } /^MTFCC=S17/ { # business park / townhome road / parking lane / "internal census use only" lanes=1; color=23; label_color=23; pattern=1; display_level=32; label_level=20; name="$name (parking/private)"; next; } /^MTFCC=S182/ { # bike path lanes=1; color=65; label_color=65; pattern=1; display_level=64; label_level=32; name="$name (bikeway)"; next; } /^MTFCC=S183/ { # bridle path lanes=1; color=65; label_color=65; pattern=2; display_level=64; label_level=32; name="$name (bridle path)"; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_mil.dbfawk000066400000000000000000000034361501463444000207330ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="ANSICODE:AREAID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON:PARTFLG"; dbffields="FULLNAME:MTFCC"; } /^FULLNAME=(.*)$/ {name="$1"; next; } /^MTFCC=K21/ { # Military installation display_level=128; color=116; label_level=64; label_color=116; fill_style=2; fill_stipple=0; fill_color=116; filled=1; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_nn_county.dbfawk000066400000000000000000000044031501463444000221610ustar00rootroot00000000000000# tl_2009_nn_county.dbfawk # # Copyright (C) 2000-2023 The Xastir Group # # Census.gov 2009 TigerMaps for state counties or equivalent areas. # # Based on work by: # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March 2009 # Edited for 2009 data by: # Peter Gamache, KC0TFB - June, 2010 # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line 2009 Shapefiles. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:COUNTYNS:CNTYIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CSAFP:CBSAFP:METDIVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAMELSAD:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAMELSAD=(.*)$/ {name="$1"} # counties /^MTFCC=G/ {display_level=6000; filled=0; color=45; label_level=2048; label_color=37; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.2/config/tl_2009_pointlm.dbfawk000066400000000000000000000107441501463444000216340ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:POINTID:FULLNAME:MTFCC"; dbffields="FULLNAME:MTFCC"; # level presets l_metro=128; l_county=64; l_city=32; l_town=16; l_hood=8; } BEGIN_RECORD { # Defaults key=""; lanes=1; color=70; fill_color=70; name=""; filled=0; pattern=0; display_level=48; label_level=32; label_color=70; font_size=0; symbol=""; fill_style=0; } /^FULLNAME=(.*)$/ {name="$1"; next; } # Geography /^MTFCC=3022/ { # Mountain Peak or Summit display_level=l_county; next; } /^MTFCC=3022/ { # Islands should be in edges.dbf, not here. display_level=0; next; } /^MTFCC=3026/ { # Quarry next; } /^MTFCC=3027/ { # Dam should be in areawater, not here. display_level=0; next; } # Road features /^MTFCC=C306/ { # ignore cul-de-sacs, roundabouts, gates and toll booths display_level=0; next; } # Towers /^MTFCC=C307[014]/ { # Towers (beacon/observation/lighthouse, antenna and water) display_level=l_city; color=50; label_color=50; symbol="\L"; next; } /^MTFCC=C3072/ { display_level=l_city; color=50; label_color=50; name="$name (antenna tower)"; symbol="/r"; next; } /^MTFCC=C3073/ { display_level=l_city; color=50; label_color=50; name="$name (water tower)"; symbol="/r"; next; } /^MTFCC=C307/ { # ignore other towers (tanks, windmills and monuments) display_level=0; next; } # Locality points /^MTFCC=C308/ { # city names; redundant with cousub.dbf display_level=0; next} # Potential housing (for disaster relief) /^MTFCC=K1231/ { # Hospitals label_color=12; display_level=l_county; symbol="/h"; next} /^MTFCC=K12/ { # Don't display other types display_level=0; next} # other gov't items /^MTFCC=K2110/ { # Military; redundant with mil.dbf display_level=0; next; } /^MTFCC=K2146/ { # Community center display_level=l_city; symbol="/?"; next} /^MTFCC=K2165/ { # Gov't center display_level=l_city; symbol="/?"; next} /^MTFCC=K218/ { # Parks not shown; redundant with arealm.dbf display_level=0; next} /^MTFCC=K2193/ { # fire dept label_color=12; display_level=l_county; symbol="/d"; next} /^MTFCC=K2194/ { # police/sheriff station label_color=9; display_level=l_county; symbol="/!"; next} /^MTFCC=K2196/ { # City hall display_level=l_city; symbol="/?"; next} /^MTFCC=K219/ { # other buildings not shown display_level=0; next} # Transportation /^MTFCC=K2400/ { # Transportation terminal? display_level=l_city; symbol="/U?"; next} /^MTFCC=K245[156]/ { # Airport/airfield, seaplane terminal display_level=l_county; symbol="\^@"; next; } /^MTFCC=K2452/ { # train/trolley/light rail station display_level=l_city; symbol="/=@"; next} /^MTFCC=K2453/ { # bus terminal display_level=l_city; symbol="/U@"; next} /^MTFCC=K2454/ { # marine terminal display_level=l_county; symbol="\s@"; next} # Education/entertainment/misc /^MTFCC=K254[03]/ { # University/school display_level=l_town; symbol="/K"; next} /^MTFCC=K2561/ { # golf course; redundant w/ arealm display_level=0; next; } /^MTFCC=K2582/ { # cemeteries display_level=0; next} /^MTFCC=K3544/ { # religious display_level=0; next} # catch-all rule: /^MTFCC=K/ {display_level=16; label_level=16; next} #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tl_2009_zcta5.dbfawk000066400000000000000000000033641501463444000212000ustar00rootroot00000000000000# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="ZCTA5CE:CLASSFP:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="ZCTA5CE:MTFCC"; } /^ZCTA5CE=(.*)$/ {name="$1";next} /^MTFCC=G6350/ { # Zip code tabulation area, 5-digit display_level=128; color=103; label_level=64; label_color=103; font_size=1; next; } #END_RECORD {} #END {} Xastir-Release-2.2.2/config/tnc-startup.aea000066400000000000000000000015201501463444000205450ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for AEA TNC's. # lines that begin with a pound sign are comments. # # This has not been tweaked yet to be specific to AEA's. # Please modify it and send the patches to the mailing lists. # Thanks. # HID on #CWID off EXP on ECHO off # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on FLow off FUll off HEA off #LFadd off #LFSup ON #AUTOLF off #MCOM off MFILTER 0 MON ON # # Important! Only monitor PID 0xf0 packets: MPROTO OFF # #MResp OFF MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off #SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.2/config/tnc-startup.d700000066400000000000000000000025401501463444000204740ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # TNC Init file for KENWOOD D700. Also reported to work with the # Alinco DR-135TP radio (with the EJ-41U TNC which also uses a Tasco # TNC just like the Kenwoods). Perhaps works with the Alinco DR-635 # radio (with the EJ-50U TNC) too. # # NOTE: TXD on a D700A is fixed at 500ms (1/2 second) in "APRS" # mode. In "packet" mode we can change the txd to other values. # # #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META #Put the TNC in packet mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TNC 2 # Pause for two seconds ##META ##META ##META ##META # Enable 4800 baud GPS # Change to 2 for 9600 baud GPS # Disable both the META line and the GU line for no change ##META GU 1 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META HID off #CWID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off HBAUD 1200 TXDELAY 25 HEADERLN off # Delete following lines if without GPS GBAUD 4800 GPSTEXT $GPRMC LTMH OFF LTM 10 # Xastir-Release-2.2.2/config/tnc-startup.d72_d710000066400000000000000000000014061501463444000211510ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # TNC Init file for KENWOOD TM-D710 or TH-D72 radios. # Contributed by Kai Günter, LA3QMA. # # If using a GPS you must change GBAUD, GPSTEXT, LTMH. # # #Don't send CONTROL-C before this line ##META #TC 1 ##Pause for one second ##META ##META #Put the TNC in packet mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TN 2,0 # Pause for two seconds ##META ##META ##META ##META HID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off HBAUD 1200 TXDELAY 25 HEADERLN off # Delete following lines if without GPS #GBAUD 4800 #GPSTEXT $GPRMC #LTMH OFF # # Xastir-Release-2.2.2/config/tnc-startup.kam000066400000000000000000000013721501463444000205740ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for a Kantronics KAM TNC. # lines that begin with a pound sign are comments. # Edit this file for your tnc! # # Important! Only uncomment if really needed as a fill-in digi: #myalias WIDE1-1 # INTF TERM #One KAM user reports this command does not exist on his KAM #txu on xflow off MONITOR ON MSTAMP OFF HEADERLN OFF #One KAM user reports this command does not exist on his KAM #SCREENLN 0 AUTOLF OFF LFADD OFF CD SOFT MCOM OFF/OFF MCON OFF FILT OFF AUTOCR 0 BEACON EVERY 0 BT % BUDL OFF/OFF CMS DISC CONL OFF CT APRS Network no connected messages supported! ECHO OFF FLOW OFF HID OFF/OFF #CWID EVERY 0 MSTAMP OFF PASSALL OFF # # Important! Monitor only PID 0xf0 packets: PID OFF Xastir-Release-2.2.2/config/tnc-startup.kpc2000066400000000000000000000006141501463444000206610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. # # HID off #CWID every 0 B E 0 DIGI on ECho off FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MON ON MResp OFF MRPt on MSTamp off # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # NEWmode off SCR 0 # Xastir-Release-2.2.2/config/tnc-startup.kpc3000066400000000000000000000034031501463444000206610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. # # This configuration sets up Control-E mode for a KPC-3+ (GPS # connected to the 2nd serial port). When Xastir is actively # getting GPS fixes, the TNC beacons only what Xastir sends to it. # When Xastir stops getting GPS data from the TNC, the TNC will # revert to dumb-tracker mode and start sending NMEA strings out all # by itself at a 20-minute rate. If the GPS get disconnected or # turned off, the dumb-tracker mode will cease to send out beacons. # This last function is done by the "CLEAR" parameter for the BLT # commands. # # Some people prefer to turn off the GPS but still have the TNC # beacon their last good GPS position when in dumb-tracker mode. # To do this, remove the "CLEAR" parameters from the BLT command # lines. # int terminal # Clear out the LT buffers so we don't have old data in there: LT 1 LT 2 LT 3 LT 4 # Clear out the buffer regularly to prevent stale data: BLT 1 00:20:00 CLEAR BLT 2 00:20:00 CLEAR BLT 3 00:00:00 BLT 4 00:00:00 # Set up the NMEA strings to capture: GPSHEAD 1 $GPRMC GPSHEAD 2 $GPGGA # GPSPORT 4800 NORMAL CHECKSUM LGETCHAR $05 # HID off #CWID every 0 # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on ECho off FILT off FLow off FUll off HEA off LFadd off LFSup ON AUTOLF off MCOM off MON ON MResp OFF MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off # # Important! Monitor only PID 0xf0 packets: PID off # SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.2/config/tnc-startup.null000066400000000000000000000000001501463444000207610ustar00rootroot00000000000000Xastir-Release-2.2.2/config/tnc-startup.paccomm000066400000000000000000000016411501463444000214420ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for a Pac-Comm TNC with v5.x firmware. # Adapted from Kantronics startup file by Kurt Freiberger, WB5BBW # lines that begin with a pound sign are comments. HID off #CWID every 0 MON 0 ECHO off #MYCall WB5BBW # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # # # #MY1Alias LOCAL #MY2Alias REGION #MY3Alias WORLD # # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. B E 0 # This enables DIGI On and DIGI-SWAP,DIGI-NOT-OWN, DIGI-ONCE enabled. DIGI 7 FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MFILT $00 MRPt on MSTamp off NEWmode off PASSALL off SCR 0 MON 1 # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # # End of tnc-startup.pac # Xastir-Release-2.2.2/config/tnc-startup.pico000066400000000000000000000024011501463444000207500ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for a dual-port Paccomm PicoPacket TNC. # lines that begin with a pound sign are comments. ECHO off AUTOLF on BEACON EVERY 0 # # Clear the GPS buffers LTEXT % L1TEXT % L2TEXT % L3TEXT % # # Set up the NMEA strings we wish to capture: #GPSTEXT % GPSTEXT $GPRMC # #LG1TEXT % LG1TEXT $GPGGA # LG2TEXT % #LG2TEXT $GPVTG # LG3TEXT % #LG3TEXT $PGRME # # Digipeat,callsign substitution, # no digi of own packets, and digi-once DIGIPEAT 7 ELOC 0 FLOW off FULLDUP off GPS off HEADERLI off HID off #CWID every 0 INTERVAL 0 LFADD off LGETCHAR $05 LOC E 0 # MALL ON MCOM off MCON on MFILTER 0 MONITOR 3 MRPT on MSTAMP off # # Important! Only uncomment if really needed as a fill-in digi: #MYALIAS WIDE1-1 # #MY1ALIAS SAR #MY2ALIAS ESAR #MY3ALIAS ESAR2 NEWMODE off NOMODE on #PACLEN 128 # # Only used in KISS mode? PERSIST 128 # PASSALL off # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # PMS off SCREENLN 0 # # Only used in KISS mode? SLOTTIME 15 # TXDELAY 30 XFLOW off # # # BEACON EVERY 0 must be set to 0 or both Xastir and your TNC will send # beacons which will alternate in everyones lists and fill up their # logs. Do NOT set BEACON EVERY to anything other than 0 while Xastir # is running. Xastir-Release-2.2.2/config/tnc-startup.sys000066400000000000000000000015601501463444000206410ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. int terminal ECHO off HID off #CWID off #CWID every 0 # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on EXP on Filt off FLow off FUll off HEA off LFadd off LFSup on AUTOLF off MCOM off MFILT off MON on MResp off MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off # # # Important! Monitor only PID 0xf0 packets: # *Kantronics* PID off # *TAPR2* MNOAX25 off # *Paccomm* PIDCHECK on # *AEA* MPROTO OFF # End of monitor only PID 0xf0 packets section # # SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.2/config/tnc-startup.thd7000066400000000000000000000032451501463444000206730ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # TNC Init file for KENWOOD TH-D7 # #-------------------------------------------------- # Note: Terminal Control commands are send without # CONTROL-C before the lines. #-------------------------------------------------- # #-------------------------------------------------- # Turn on Terminal Control # # This will make the TH-D7 drop out of Packet mode. # Once out of Packet mode, the TH-D7 will forget # all old TNC settings and even KISS mode, so we # can start from a clean situation. #-------------------------------------------------- # ##META TC 1 # Pause one second ##META ##META # #-------------------------------------------------- # Turn off Terminal Control # # This will make the TH-D7 switch to Packet mode. #-------------------------------------------------- # ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # #-------------------------------------------------- # Initialize the TNC # # This will setup the TH-D7 TNC for use with APRS. #-------------------------------------------------- # HID off #CWID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off # # Enable this line ONLY if you're running 9600 baud packet. It # changes the on-the-air speed from the default 1200 baud. #HBAUD 9600 # TXDELAY 25 # #-------------------------------------------------- # Initialize the GPS # # Enable the commands if running with GPS. # If running without GPS, leave them disabled. #-------------------------------------------------- # #GBAUD 4800 #GPSTEXT $GPRMC #LTMH OFF #LTM 10 # Xastir-Release-2.2.2/config/tnc-startup.tnc2000066400000000000000000000016771501463444000207020ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for a TAPR TNC2 style of TNC. This # includes many TNC's from TAPR, Paccomm, MFJ, AEA, etc that were # based on the original TAPR-2 design. # lines that begin with a pound sign are comments. HID off #CWID every 0 MON 0 ECHO off #MYCall WB5BBW # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # #MY1Alias WIDE #MY2Alias REGION #MY3Alias WORLD # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. B E 0 # This enables DIGI On and DIGI-SWAP,DIGI-NOT-OWN, DIGI-ONCE enabled. DIGI 7 FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MFILT $00 MRPt on MSTamp off NEWmode off PASSALL off SCR 0 MON 1 # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # # End of tnc-startup.tnc2 # Xastir-Release-2.2.2/config/tnc-startup.tnc2-ui000066400000000000000000000003771501463444000213110ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for the TNC2-UI TNC. # lines that begin with a pound sign are comments. HID off #CWID off MONITOR OFF ECHO OFF LF OFF BEACON 0 LTIME 0 HEADER OFF MCOM OFF AXLF OFF MONITOR ON Xastir-Release-2.2.2/config/tnc-stop.d700000066400000000000000000000016511501463444000177610ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # #TNC STOP FILE # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! UNPROTO CQ AUTOLF ON ECHO ON #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META # Turn off AUX port ##META GU 0 ##META #Put the TNC in internal mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TNC 1 # Pause for two seconds ##META ##META ##META ##META # Enable 4800 baud GPS # Change to 2 for 9600 baud GPS # Disable both the META line and the GU line for no change ##META GU 1 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # Xastir-Release-2.2.2/config/tnc-stop.d72_d710000066400000000000000000000013631501463444000204360ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # TNC STOP FILE for Kenwood TM-D710 or TH-D72 radios. # Contributed by Kai Günter, LA3QMA. # # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! # # UNPROTO CQ AUTOLF ON ECHO ON #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META ##META #Put the TNC in internal mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TN 0,0 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # Xastir-Release-2.2.2/config/tnc-stop.sys000066400000000000000000000002361501463444000201230ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # #TNC STOP FILE # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! UNPROTO CQ AUTOLF ON Xastir-Release-2.2.2/config/tnc-stop.thd7000066400000000000000000000016771501463444000201650ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # TNC Stop file for KENWOOD TH-D7 # #-------------------------------------------------- # Note: Terminal Control commands are send without # CONTROL-C before the lines. #-------------------------------------------------- # #-------------------------------------------------- # Turn on Terminal Control # # This will make the TH-D7 drop out of Packet mode. # Once out of Packet mode, the TH-D7 will forget # all TNC settings. No need to restore anything. #-------------------------------------------------- # ##META TC 1 # Pause one second ##META ##META # #-------------------------------------------------- # Resume standalone APRS use. # # GPS en Beacon settings are not changed. Once back # in APRS mode, the GPS and Beacon are resumed as # they were. #-------------------------------------------------- # ##META TNC 1 # Pause one second ##META ##META # Xastir-Release-2.2.2/config/tnc-stop.tnc2-ui000066400000000000000000000002751501463444000205710ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # This is the TNC Startup file for the TNC2-UI TNC. # lines that begin with a pound sign are comments. MONITOR OFF LF ON ECHO ON MONITOR ON Xastir-Release-2.2.2/config/xastir.rgb000066400000000000000000000032231501463444000176210ustar00rootroot00000000000000000 000 000 black 069 069 069 gray27 047 079 079 DarkSlateGray 089 089 089 gray35 135 135 135 gray53 169 169 169 darkgray 186 186 186 gray73 204 204 204 gray80 207 207 207 gray81 211 211 211 lightgray 219 219 219 gray86 255 255 255 white 000 000 255 blue 000 000 238 blue2 000 000 205 blue3 000 000 139 blue4 173 216 230 lightblue 030 144 255 DodgerBlue 065 105 225 RoyalBlue 070 130 180 SteelBlue 000 191 255 DeepSkyBlue 000 000 205 MediumBlue 000 000 128 NavyBlue 000 255 000 green 000 238 000 green2 000 205 000 green3 000 139 000 green4 152 251 152 PaleGreen 050 205 050 LimeGreen 060 179 113 MediumSeaGreen 034 139 034 ForestGreen 000 100 000 DarkGreen 000 255 255 cyan 000 238 238 cyan2 000 205 205 cyan3 000 139 139 cyan4 224 255 255 LightCyan 255 000 000 red 238 000 000 red2 205 000 000 red3 139 000 000 red4 255 000 255 magenta 238 000 238 magenta2 205 000 205 magenta3 139 000 139 magenta4 255 255 000 yellow 238 238 000 yellow2 238 238 150 yellow3 139 139 000 yellow4 250 250 210 LightGoldenrodYellow 238 232 170 PaleGoldenrod 255 248 220 cornsilk 255 165 000 orange 238 154 000 orange2 205 133 000 orange3 205 102 000 DarkOrange3 255 069 000 OrangeRed 178 034 034 firebrick 188 143 143 RosyBrown 255 180 180 RosyBrown2 165 042 042 brown 255 064 064 brown1 205 051 051 brown3 255 130 071 sienna1 064 224 208 turquoise 186 085 211 mediumorchid 153 050 204 DarkOrchid 160 032 240 purple 127 255 000 chartreuse 230 230 250 lavender 221 160 221 plum 238 174 238 plum2 250 128 114 salmon 255 192 203 pink 255 228 225 MistyRose 255 174 185 LightPink1 255 105 180 HotPink 127 255 127 tgr_park_1 255 247 159 tgr_city_1 175 215 127 tgr_forest_1 0 159 255 tgr_water_1 Xastir-Release-2.2.2/configure.ac000066400000000000000000000734771501463444000166560ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. # # # Copyright (C) 2000-2023 The Xastir Group ######################################################################### # SET VERSION HERE! # # Note that the most standard OSS method of doing numbering is: # Major.Minor.PatchLevel # # If we are only doing patches, change the PATCHLEVEL number. # If we add new features, change the MINOR number. # If we feel we've added enough new features or rewritten enough # code to warrant it, change the MAJOR number. # # Also: We adopted the convention of using odd numbers for development # or development releases, even numbers for STABLE releases. # # # AC_INIT(): # It should look something like this: ([xastir], [2.0.8], [xastir@xastir.org]) # The revision number must contain at least one '.' and two digits. AC_INIT([xastir], [2.2.2], [xastir@xastir.org]) ######################################################################### AC_PREREQ(2.60) AC_CONFIG_SRCDIR([src/xastir.h]) #AM_CONFIG_HEADER(config.h) AC_CONFIG_HEADERS(config.h) AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES(yes) echo "" echo "Configuring AC_PACKAGE_NAME AC_PACKAGE_VERSION" echo "" # Take out the dots in order to create the TOCALL AC_DEFINE_UNQUOTED(XASTIR_TOCALL, "`echo AC_PACKAGE_VERSION | sed -e 's/^/APX/' -e 's/\.//g'`", [Defines the version tocall]) # Check for host type AC_CANONICAL_HOST # Define _GNU_SOURCE if appropriate # doesn't work with older (heh) autoconfs # This macro is now obsolete as of autoconf 2.60 and should no longer # be used: AC_GNU_SOURCE # autoconf 2.60 was released in 2006, so it should be safe to assume all # users have at least this version by now. AC_USE_SYSTEM_EXTENSIONS(_GNU_SOURCE) # Checks for programs. AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_AWK AC_PROG_RANLIB #AC_PROG_YACC AM_PROG_CC_C_O # test for devices XASTIR_DETECT_DEVICES # add includes and libs XASTIR_ADD_SEARCH_PATHS # check for pthread first ACX_PTHREAD # add compiler flags XASTIR_COMPILER_FLAGS # Check for binaries use_festival=yes use_gpsman=yes use_err_popups=no use_lsb=no use_spatial_db=no use_postgis=no use_mysql_spatial=no AC_ARG_WITH(festival,[ --without-festival Disable festival features.],use_festival=$withval) AC_ARG_WITH(gpsman,[ --without-gpsman Disable gpsman features.],use_gpsman=$withval) AC_ARG_WITH(errorpopups,[ --with-errorpopups Send error popups to stderr.],use_err_popups=$withval) AC_ARG_WITH(lsb,[ --with-lsb Enable Linux Standard Base.],use_lsb=$withval) # Now that all the various "use_" variables are set, probe for binaries. XASTIR_DETECT_BINARIES # if the probes failed, then make sure the "use_" variables are set to no, # even if we requested them. if test "x${festival}" = "xno"; then use_festival=no fi if test "x${gpsman}" = "xno"; then use_gpsman=no fi # JMT - XXX - what is this and why is it relevant? #AC_DEFINE(_REENTRANT, 1, [Use reentrant code if available.]) AC_DEFINE_UNQUOTED(STIPPLE, 1, [Legacy stuff, use crowbar and lets keep going]) # Checks for libraries. # # # Find the X11 include and library directories. # AC_PATH_XTRA if test "$no_x" = "yes"; then AC_MSG_ERROR(*** No X11! Install the X Window System development headers/libraries! ***) fi CPPFLAGS="$CPPFLAGS $X_CFLAGS" LDFLAGS="$LDFLAGS $X_LIBS" LIBS="$LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" AC_SEARCH_LIBS(tan,math m) AC_CHECK_LIB([Xext], [XextAddDisplay]) #*********************************** # Check for libXp removed on 31 Oct 2015 # This was in place for a very long time, but libxp is now deprecated and # has even been removed from some distros # # XpGetDocumentData is not used *anywhere* in Xastir, but some distros have # a Motif library that is linked against it. This is supposed to be # taken care of by the shared library loader, not by explicit linking, but # as late as 2007 some distros had it linked wrong. It appears as of 2015 # that nobody still does that, and this check causes more harm than good. # # If the build of Xastir fails at link time looking for XpGetDocumentData, # then somebody *does* still do that incorrect shared library linking, # and y9ou'll need to re-enable this on your system # #AC_CHECK_LIB([Xp], [XpGetDocumentData]) #************************************ AC_CHECK_LIB([Xt], [XtDisplay]) AC_CHECK_LIB([Xm], [XmTextFindString]) #use_html2text=no #AC_PATH_PROG(html2text, [html2text --version], no, $BINPATH) #if test "$html2text" != "no"; then # AC_DEFINE_UNQUOTED(HAVE_HTML2TEXT, 1, [Define if you have html2text]) # AC_DEFINE_UNQUOTED(HTML2TEXT_PATH, "${html2text}", [Path to html2text]) # use_html2text=yes #fi use_sed=no AC_PATH_PROG(sed, [sed --version], no, $BINPATH) if test "$sed" != "no"; then AC_DEFINE_UNQUOTED(HAVE_SED, 1, [Define if you have sed]) AC_DEFINE_UNQUOTED(SED_PATH, "${sed}", [Path to sed]) use_sed=yes fi use_mv=no AC_PATH_PROG(mv, [mv --version], no, $BINPATH) if test "$mv" != "no"; then AC_DEFINE_UNQUOTED(HAVE_MV, 1, [Define if you have mv]) AC_DEFINE_UNQUOTED(MV_PATH, "${mv}", [Path to mv]) use_mv=yes fi use_xfontsel=no AC_PATH_PROG(xfontsel, xfontsel, no, $BINPATH) if test "$xfontsel" != "no"; then AC_DEFINE_UNQUOTED(HAVE_XFONTSEL, 1, [Define if you have xfontsel]) AC_DEFINE_UNQUOTED(XFONTSEL_PATH, "${xfontsel}", [Path to xfontsel]) use_xfontsel=yes fi use_curl=no curl_desired=yes # Note: Had to move AC_CHECK_HEADER here instead of inside the first # "if" statement: It corrupted later tests, don't know why. The # only downside is that we check for the libcurl headers even if # --without-libcurl was specified on the command-line. AC_CHECK_HEADER(curl/curl.h, CURL_INC="yes", CURL_INC="no") AC_ARG_WITH(libcurl,[ --without-libcurl Disable libcurl features.],curl_desired=$withval) if test "${curl_desired}" = "yes"; then if test "${CURL_INC}" = "yes"; then if test "${use_lsb}" = "no"; then # Important: when using the three-argument version of AC_CHECK_LIB, you # must do all of what is normally the default behavior in the third argument, # not just the extra stuff you want to accomplish: AC_CHECK_LIB([curl], [curl_global_init], [use_curl="yes" LIBS="${LIBS} -lcurl" AC_DEFINE(HAVE_LIBCURL, 1, [Define to 1 if your `curl' library has curl_global_init.]) ]) else AC_DEFINE(HAVE_LIBCURL, 1, [Define to 1 if your `curl' library has curl_global_init.] ) LIBS="${LIBS} -lcurl" use_curl=yes fi fi fi # Test for wget only if above libcurl tests fail use_wget=no if test "${use_curl}" = "no"; then AC_PATH_PROG(wget, [wget --version], no, $BINPATH) if test "$wget" != "no"; then AC_DEFINE_UNQUOTED(HAVE_WGET, 1, [Define if you have wget]) AC_DEFINE_UNQUOTED(WGET_PATH, "${wget}", [Path to wget]) use_wget=yes fi fi use_retrieval=no if test "${use_curl}" = "yes"; then use_retrieval="yes (libcurl)" else if test "${use_wget}" = "yes"; then use_retrieval="yes (wget)" fi fi # Test for libgps, used for accessing GPSD daemon #use_libgps=no #AC_CHECK_HEADER(gps.h, GPS_INC="yes", GPS_INC="no") #if test "${GPS_INC}" = "yes"; then # AC_CHECK_LIB([gps], [gps_open], # [use_libgps="yes" # LIBS="${LIBS} -lgps" # AC_DEFINE(HAVE_LIBGPS, 1, # [Define to 1 if your `libgps' library has gps_open.]) # ]) #fi # JMT - XXX - why is this here? AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat" AC_SUBST(LIBCOMPAT)]) # Check for sched_yield in librt (Needed for Solaris) AC_CHECK_LIB(rt, sched_yield, LIBS="-lrt $LIBS") # Check for endian AC_C_BIGENDIAN # Our old stuff. Doesn't work in all cases. # Checks for header files. #AC_CHECK_HEADERS([Xm/Xm.h],MOTIF_INC="yes", AC_MSG_ERROR(*** Cannot find Motif include files: Please install one of Motif/OpenMotif/Lesstif development packages. ***)) XASTIR_PATH_MOTIF if test "x$xm_includes" != "x" ; then CFLAGS="$CFLAGS -I$xm_includes" CPPFLAGS="$CPPFLAGS -I$xm_includes" fi if test "x$xm_libraries" != "x" ; then LDFLAGS="-L$xm_libraries $LDFLAGS" fi AC_SUBST(LDFLAGS) AC_SUBST(LIBS) # AC_FUNC_ALLOCA AC_HEADER_DIRENT AC_HEADER_SYS_WAIT # We still check for stdarg.h even though it's standard, because a legacy # file (snprintf.c) still uses its symbol. AC_CHECK_HEADERS([stdarg.h]) AC_CHECK_HEADERS([sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h signal.h]) AC_CHECK_HEADERS([termios.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. # AC_C_CONST AC_TYPE_UID_T AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T AC_STRUCT_TIMEZONE #Some (Mac?) systems don't define this where it should be, so we kludge AC_CHECK_TYPES(socklen_t,,,[#include #include ]) # some BSD systems do not define sighandler_t, but rather sig_t AC_CHECK_TYPES(sighandler_t,,,[#include ]) AC_CHECK_TYPES(sig_t,,,[#include ]) # some BSD systems do not define sighandler_t, but rather sig_t AC_CHECK_TYPES(sigjmp_buf,,,[#include ]) #Force this into config.h.in AH_BOTTOM([#ifndef HAVE_SOCKLEN_T #define socklen_t int #endif]) # Check for tm_gmtoff in tm AC_CHECK_GMTOFF # Checks for library functions. # AC_FUNC_FORK AC_FUNC_GETPGRP AC_FUNC_MALLOC AC_FUNC_MKTIME AC_FUNC_MMAP AC_FUNC_STAT AC_FUNC_STRFTIME AC_FUNC_STRTOD AC_CHECK_FUNCS([getcwd getpgrp gethostbyname gethostname gettimeofday]) AC_CHECK_FUNCS([getwd inet_ntoa memmove mempcpy memset mkdir munmap pow]) AC_CHECK_FUNCS([putenv select setenv setlocale settimeofday signal sigignore]) AC_CHECK_FUNCS([snprintf socket sqrt stpcpy strcasecmp strchr strdup]) AC_CHECK_FUNCS([strerror strncasecmp strpbrk strptime strrchr strstr]) AC_CHECK_FUNCS([strtof strtol strtoul tzset vsnprintf]) # Check for deprecated/current pthread functions AC_CHECK_FUNCS([pthread_mutexattr_setkind_np pthread_mutexattr_settype]) # this is a GNU extension and not present on all systems. AC_CHECK_FUNCS([strndup]) #this is also a recent extension that should not be counted on AC_CHECK_FUNCS([roundf]) # Check for libproj (need to do this before test for geotiff, which is the # only thing we have that uses proj use_proj=yes AC_ARG_WITH(libproj,[ --without-libproj Disable libproj features.],use_proj=$withval) if test "${use_proj}" = "yes"; then use_proj=no AC_CHECK_LIB([proj], [proj_create_crs_to_crs], [use_proj=yes LIBS="$LIBS -lproj" AC_DEFINE(HAVE_PROJ, 1, Define to 1 if you have the `libproj' library (-lproj). )], [ AC_CHECK_LIB([proj], [pj_init], [use_proj=yes LIBS="$LIBS -lproj" AC_DEFINE(HAVE_PROJ, 1, Define to 1 if you have the `libproj' library (-lproj). )])] ) fi # Check for Shapelib use_shapelib=yes shapelib_desired=yes AC_ARG_WITH(shapelib,[ --without-shapelib Disable shapelib features.],shapelib_desired=$withval) if test "${shapelib_desired}" = "no"; then use_shapelib=no fi if test "${shapelib_desired}" = "yes" ; then use_shapelib=no AC_CHECK_HEADERS([shapefil.h libshp/shapefil.h], [AC_CHECK_LIB([shp], [DBFOpen], [use_shapelib=yes LIBS="$LIBS -lshp" AC_DEFINE(HAVE_LIBSHP, 1, [Define to 1 if you have the `shp' library (-lshp).]) ]) break ]) fi # Shapelib requires pcre now use_pcre=no if test "${shapelib_desired}" = "yes" -a "${use_shapelib}" = "yes"; then AC_CHECK_HEADERS([pcre2.h], [AC_CHECK_LIB([pcre2-8],[pcre2_compile_8], [use_pcre="yes (PCRE2)" LIBS="$LIBS -lpcre2-8" ], [use_pcre=no AC_MSG_WARN([Found pcre2 headers but not libraries]) ]) ], [use_pcre=no], [ #define PCRE2_CODE_UNIT_WIDTH 8 ]) if test "${use_pcre}" = "no" then AC_MSG_WARN([Modern PCRE2 not found, checking for legacy version]) AC_CHECK_HEADERS([pcre.h pcre/pcre.h], [AC_CHECK_LIB([pcre], [pcre_compile], [use_pcre="yes (legacy)" LIBS="$LIBS -lpcre" AC_DEFINE(XASTIR_LEGACY_PCRE, 1, Define to 1 if you have the legacy `pcre' library (-lpcre). ) ]) break ]) fi if test "${use_pcre}" = "no" then AC_MSG_ERROR([Shapelib support requires PCRE, and we could not find PCRE. Either disable shapelib by specifying "--without-shapelib" or install PCRE libraries and headers]) fi fi if test "${shapelib_desired}" = "yes" -a "${use_shapelib}" = "no"; then AC_MSG_WARN([**************************************************************** ]) AC_MSG_WARN([Your system does not have shapelib installed. ]) AC_MSG_WARN([Install shapelib on your system to eliminate this warning. ]) AC_MSG_WARN([**************************************************************** ]) use_shapelib=no fi # Check for XPM use_xpm="no" if test "${use_lsb}" = "no"; then AC_CHECK_HEADERS(X11/xpm.h, [ #action if found in addition to setting HAVE_X11_XPM_H AC_SEARCH_LIBS(XpmWriteFileFromPixmap, [Xpm], [ # action if found (in addition to adding -lXpm to LIBS use_xpm="yes" AC_DEFINE(HAVE_LIBXPM, 1, [Define to 1 if you have the `Xpm' library (-lXpm).] ) ]) ], [ # Action if X11/xpm.h is not found: look for Xm/XpmI.h instead AC_CHECK_HEADERS(Xm/XpmI.h, [ # Action if found, in addition to setting HAVE_XM_XPMI_H AC_SEARCH_LIBS(XmeXpmWriteFileFromPixmap, [Xm], [ # action if -lXm is found, in addition to adding -lXm to LIBS use_xpm="yes" AC_DEFINE(HAVE_LIBXPM_IN_XM, 1, [Define to 1 if the `Xm' library (-lXm) is used for Xpm.]) ], [ #action if -lXm not found: issue warning AC_MSG_WARN([**************************************************************** ]) AC_MSG_WARN([Your system does not have a library that contains XpmWriteFileFromPixmap]) AC_MSG_WARN([PNG snapshots cannot work. ]) AC_MSG_WARN([**************************************************************** ]) ]) ]) ]) else AC_DEFINE(HAVE_LIBXPM, 1, Define to 1 if you have the `Xpm' library (-lXpm). ) AC_DEFINE(HAVE_LIBXPM_IN_XM, 1, Define to 1 if the `Xm' library (-lXm) is used for Xpm. ) AC_DEFINE(HAVE_X11_XPM_H, 1, Define to 1 if you have 'X11/xpm.h' ) fi #check for libtiff, libgeotiff # libjpeg.a and libz.a need to be compiled under LSB use_geotiff=yes AC_ARG_WITH(geotiff, [ --without-geotiff Disable geotiff features.], use_geotiff=$withval) if test "${use_geotiff}" = "yes"; then if test "${use_proj}" = "yes" ; then if test "${use_lsb}" = "yes" ; then use_tiff=yes use_geotiff=yes LIBS="$LIBS -lgeotiff -ltiff -ljpeg -lz -lproj" AC_DEFINE(HAVE_TIFF, 1,Define to 1 if you have the 'tiff' library (-ltiff)) AC_DEFINE(HAVE_LIBGEOTIFF, 1,Define to 1 if you have the `geotiff' library (-lgeotiff).) else AC_CHECK_HEADER(xtiffio.h, , use_geotiff="no") if test "${use_geotiff}" = "yes"; then AC_CHECK_LIB(tiff, TIFFClose, use_tiff=yes LIBS="$LIBS -ltiff" AC_DEFINE(HAVE_TIFF, 1,Define to 1 if you have the 'tiff' library (-ltiff))) if test "${use_tiff}" = "yes"; then use_geotiff=no AC_CHECK_LIB(geotiff, GTIFNew, use_geotiff=yes LIBS="$LIBS -lgeotiff" AC_DEFINE(HAVE_LIBGEOTIFF, 1,Define to 1 if you have the `geotiff' library (-lgeotiff).)) else echo "*** Warning: geotiff requires libtiff." use_geotiff=no fi else echo "*** Warning: geotiff include files not found." fi fi else echo "*** Warning: geotiff requires libproj." use_geotiff=no fi fi # Check for spatial database support use_postgis=no AC_ARG_WITH(postgis, [ --with-postgis Enable Postgresql with PostGIS.],use_postgis=$withval) if test "${use_postgis}" != "no"; then XASTIR_CHECK_POSTGIS fi use_mysql=no AC_ARG_WITH(mysql, [ --with-mysql Enable MySQL, with spatial support if available.],use_mysql=$withval) if test "${use_mysql}" != "no"; then XASTIR_CHECK_MYSQL fi if test "${use_postgis}" = "yes"; then use_spatial_db=yes AC_DEFINE(HAVE_SPATIAL_DB, 1, [Spatial database support available] ) AC_DEFINE(HAVE_DB, 1, [Database support available] ) fi if test "${use_mysql_spatial}" = "yes"; then use_spatial_db=yes AC_DEFINE(HAVE_DB, 1, [Database support available] ) AC_DEFINE(HAVE_SPATIAL_DB, 1, [Spatial database support available] ) elif test use_mysql_any = "yes"; then AC_DEFINE(HAVE_DB, 1, [Database support available] ) fi # Check for AX.25 library use_ax25=yes AC_ARG_WITH(ax25,[ --without-ax25 Disable ax25 features.],use_ax25=$withval) if test "${use_ax25}" = "yes"; then use_ax25=no AC_CHECK_HEADERS(netax25/ax25.h, [AC_CHECK_LIB(ax25, ax25_config_load_ports, use_ax25=yes LIBS="$LIBS -lax25" AC_DEFINE(HAVE_LIBAX25, 1, Define to 1 if you have the `ax25' library (-lax25). ) break)]) fi AC_ARG_ENABLE(davis, [ --enable-davis Turn on Davis support], [case "${enableval}" in yes) davis=true ;; no) davis=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-davis) ;; esac],[davis=false]) AM_CONDITIONAL(DAVIS, test x$davis = xtrue) if test "${davis}" = "true"; then davis=yes else davis=no fi # Check for LIBGC, a Garbage Collection library. If found, allow # linking it with Xastir, but require the "--with-libgc" flag to # enable it. use_libgc=no AC_ARG_WITH(libgc,[ --with-libgc Enable libgc features.],use_libgc=$withval) if test "${use_libgc}" = "yes"; then AC_CHECK_HEADERS([gc.h], LIBGC_INC="yes", use_libgc=no) AC_CHECK_LIB([gc], [GC_init], , use_libgc=no) fi # Check whether profiling was requested. If so, add the "-pg" flag # to CFLAGS. Require "--with-profiling" flag to enable it. use_profiling=no AC_ARG_WITH(profiling,[ --with-profiling Enable profiling features.],use_profiling=$withval) if test "${use_profiling}" = "yes"; then CFLAGS="$CFLAGS -pg" fi # Check for Berkeley DB. use_map_cache=yes AC_ARG_WITH(map_cache,[ --without-map-cache Disable Berkeley DB Map Caching.],use_map_cache=$withval) if test "${use_map_cache}" = "yes"; then XASTIR_BERKELEY_DB_CHK fi # Check for GraphicsMagick. If not available/desired then check for # ImageMagick. These checks are VERY important to have as the last, # as they mess up previous checks if they fail. # use_graphicsmagick=yes use_imagemagick=no AC_ARG_WITH(graphicsmagick,[ --without-graphicsmagick Disable graphicsmagick features.],use_graphicsmagick=$withval) if test "${use_graphicsmagick}" = "yes"; then if test "${use_lsb}" = "no"; then XASTIR_CHECK_GRAPHICSMAGICK else MAGIC_BIN="/opt/lsb-tmp/bin/GraphicsMagick-config" CPPFLAGS="$CPPFLAGS `${MAGIC_BIN} --cppflags`" CXXFLAGS="$CXXFLAGS `${MAGIC_BIN} --cflags`" CFLAGS="$CFLAGS `${MAGIC_BIN} --cflags`" LDFLAGS="$LDFLAGS `${MAGIC_BIN} --ldflags`" LIBS="${MAGIC_LIB_DIR} `${MAGIC_BIN} --libs` $LIBS" AC_DEFINE(HAVE_GRAPHICSMAGICK, 1, [GraphicsMagick image library]) fi fi # # Note: This must be a separate "if" as the use_graphicsmagick # variable gets set to "no" if GM is not available above. # if test "${use_graphicsmagick}" = "no"; then use_imagemagick=yes AC_ARG_WITH(imagemagick,[ --without-imagemagick Disable imagemagick features.],use_imagemagick=$withval) if test "${use_imagemagick}" = "yes"; then XASTIR_CHECK_IMAGEMAGICK fi fi # # # if test "${use_imagemagick}" = "yes" -o "${use_graphicsmagick}" = "yes"; then AC_DEFINE(HAVE_MAGICK, 1, [GraphicsMagick or ImageMagick library]) fi # Set XASTIR_DATA_BASE in CPPFLAGS due to Gnu coding standard that requires # datadir expansion to be deferred until make time. if test "x${datadir}" = "x"; then CPPFLAGS="$CPPFLAGS -DXASTIR_DATA_BASE=\\\"${ac_default_prefix}/share/xastir\\\"" else CPPFLAGS="$CPPFLAGS -DXASTIR_DATA_BASE=\\\"${datadir}/xastir\\\"" fi # Add a special option that makes Cygwin link much faster (from # Henk de Groot) AC_MSG_CHECKING([if linker supports --no-keep-memory]) save_LDFLAGS="$LDFLAGS" LDFLAGS="-Wl,--no-keep-memory $LDFLAGS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([], [[return(0);]])], [xa_cv_no_keep_memory=yes], [xa_cv_no_keep_memory=no]) if test "${xa_cv_no_keep_memory}" = "no"; then LDFLAGS="$save_LDFLAGS" AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi # # Assure we have this order for these LIBS: "-lXm -lXt -lX11" by # adding them to the beginning. Add spaces around them for the # following steps. Here I'm adding them to the beginning so the # dupe-check portion will take out the later ones that might be in # the wrong order. If they're in the wrong order, we can get # "Error: Shell widget xastir has zero width and/or height" when # Xastir is started up. Can also get "Error: attempt to add # non-widget child "DropSiteManager" to parent", but that can also # be caused by other problems with libraries. # LIBS=" -lXm -lXt -lX11 $LIBS" # # Remove duplicate entries. Thanks to Paul Lutt, ke7xt, for this! # # Don't get rid of dupes on the LIBS line. We may need the same # "-Llibdir" called out several times, immediately prior to each # "-llibrary" that needs it. # changequote(,) CFLAGS=`echo "$CFLAGS" | awk '{for(i=1;i<=NF;++i) {if (arg[$i]++ == 0) s = s " " $i} print s}'` CPPFLAGS=`echo "$CPPFLAGS" | awk '{for(i=1;i<=NF;++i) {if (arg[$i]++ == 0) s = s " " $i} print s}'` LDFLAGS=`echo "$LDFLAGS" | awk '{for(i=1;i<=NF;++i) {if (arg[$i]++ == 0) s = s " " $i} print s}'` #LIBS=`echo "$LIBS" | awk '{for(i=1;i<=NF;++i) {if (arg[$i]++ == 0) s = s " " $i} print s}'` changequote([,]) # # Remove "-g" CFLAGS/CPPFLAGS entries. Note: This is a _bad_ idea # as debuggers won't have a symbol table to work from! # #changequote(,) #CFLAGS=`echo "$CFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-g") s = s " " $i} print s}'` #CPPFLAGS=`echo "$CPPFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-g") s = s " " $i} print s}'` #changequote([,]) # # Change the compiler optimization if using Windows/Cygwin in order # to reduce memory usage and speed up the compile. Here we change # "-O2" to "-O1" or " " in CFLAGS/CPPFLAGS to reduce the level of # optimization. # We also wish to remove "-no-undefined" from LDFLAGS on Cygwin, as # we use GCC for our linking instead of libtool, and GCC doesn't # like that flag at the link stage. # case "$host_os" in cygwin*) changequote(,) CFLAGS=`echo "$CFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-O2") s = s " " $i} print s}'` CPPFLAGS=`echo "$CPPFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-O2") s = s " " $i} print s}'` LDFLAGS=`echo "$LDFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-no-undefined") s = s " " $i} print s}'` changequote([,]) ;; esac # Create the ILIBS defined variable. We add spaces here in the else # clauses in order to make the REGRESSION_TESTS format nicely. We # take them back out before we define the variable that Xastir uses # for it's Help->About dialog. # if test "${use_ax25}" = "yes"; then ILIBS="AX25" else ILIBS=" " fi if test "${use_festival}" = "yes"; then ILIBS="$ILIBS Festival" else ILIBS="$ILIBS " fi if test "${use_gpsman}" = "yes"; then ILIBS="$ILIBS GPSMan" else ILIBS="$ILIBS " fi if test "${use_graphicsmagick}" = "yes"; then ILIBS="$ILIBS GraphicsMagick" else if test "${use_imagemagick}" = "yes"; then ILIBS="$ILIBS ImageMagick " else ILIBS="$ILIBS " fi fi if test "${use_proj}" = "yes"; then ILIBS="$ILIBS libProj" else ILIBS="$ILIBS " fi if test "${use_geotiff}" = "yes"; then ILIBS="$ILIBS GeoTiff" else ILIBS="$ILIBS " fi if test "${use_shapelib}" = "yes"; then ILIBS="$ILIBS ShapeLib" else ILIBS="$ILIBS " fi if test "${use_pcre}" != "no"; then if test "${use_pcre}" = "yes(legacy)" then ILIBS="$ILIBS PCRE" else ILIBS="$ILIBS PCRE2" fi else ILIBS="$ILIBS " fi if test "${use_map_cache}" = "yes"; then ILIBS="$ILIBS map_caching" else ILIBS="$ILIBS " fi if test "${use_err_popups}" = "yes"; then ILIBS="$ILIBS error_popups" else ILIBS="$ILIBS " fi if test "${use_libgc}" = "yes"; then ILIBS="$ILIBS libgc" else ILIBS="$ILIBS " fi if test "${use_profiling}" = "yes"; then ILIBS="$ILIBS profiling" else ILIBS="$ILIBS " fi if test "${use_lsb}" = "yes"; then ILIBS="$ILIBS LSB" else ILIBS="$ILIBS " fi if test "${use_curl}" = "yes"; then ILIBS="$ILIBS libcurl" else if test "${use_wget}" = "yes"; then ILIBS="$ILIBS wget " else ILIBS="$ILIBS " fi fi # Write out the library information to "summary.log". Here we want # the spaces for the undefined pieces, so REGRESSION_TESTS formats # nicely. echo "$ILIBS" >summary.log # # Remove extraneous spaces from output variables (aesthetic) # ILIBS=`echo $ILIBS | sed -e 's/ */ /g'` X_CFLAGS=`echo $X_CFLAGS | sed -e 's/ */ /g'` X_PRE_LIBS=`echo $X_PRE_LIBS | sed -e 's/ */ /g'` X_LIBS=`echo $X_LIBS | sed -e 's/ */ /g'` X_EXTRA_LIBS=`echo $X_EXTRA_LIBS | sed -e 's/ */ /g'` CC=`echo $CC | sed -e 's/ */ /g'` CFLAGS=`echo $CFLAGS | sed -e 's/ */ /g'` CPPFLAGS=`echo $CPPFLAGS | sed -e 's/ */ /g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/ */ /g'` LDFLAGS=`echo $LDFLAGS | sed -e 's/ */ /g'` TESTED_LIBS=`echo $LIBS | sed -e 's/ */ /g'` MAGICK_DEP_LIBS=`echo $MAGICK_DEP_LIBS | sed -e 's/ */ /g'` LIBS=`echo $LIBS | sed -e 's/ */ /g'` tmp_path="$ac_default_prefix" tmp_bin_path="$ac_default_prefix" if test "x$prefix" != xNONE; then tmp_path="$prefix" tmp_bin_path="$prefix" fi if test "x$exec_prefix" != xNONE; then tmp_bin_path="$exec_prefix" fi AC_DEFINE_UNQUOTED(XASTIR_PATH, "`echo $tmp_path`", [Path to installed Xastir files.]) AC_DEFINE_UNQUOTED(XASTIR_BIN_PATH, "`echo $tmp_bin_path`", [Path to installed Xastir binaries.]) AC_DEFINE_UNQUOTED(XASTIR_INSTALLED_LIBS, "`echo $ILIBS`", [Defines the installed libs]) AC_SUBST(LDFLAGS) AC_SUBST(LIBS) #AC_SUBST(CPPFLAGS) AC_SUBST(X_CFLAGS) #AC_SUBST(LDFLAGS) #AC_SUBST(X_PRE_LIBS) #AC_SUBST(X_LIBS) #AC_SUBST(X_EXTRA_LIBS) AC_CONFIG_FILES([Makefile \ callpass/Makefile \ config/Makefile \ help/Makefile \ scripts/Makefile \ src/Makefile \ src/rtree/Makefile \ symbols/Makefile \ xastir.spec \ xastir-min.spec \ xastir-lsb.spec]) AC_CONFIG_FILES([scripts/get-BOMdata],[chmod +x scripts/get-BOMdata]) AC_CONFIG_FILES([scripts/get-NWSdata],[chmod +x scripts/get-NWSdata]) AC_CONFIG_FILES([scripts/get-gnis],[chmod +x scripts/get-gnis]) AC_CONFIG_FILES([scripts/get-fcc-rac.pl],[chmod +x scripts/get-fcc-rac.pl]) AC_CONFIG_FILES([scripts/icontable.pl],[chmod +x scripts/icontable.pl]) AC_OUTPUT # Please leave these in as they're very useful for debug when we # port to new platforms! Leave them commented out unless doing # debugging on the configure scripts. # #echo "" #echo " LIBS: $LIBS" #echo " LDFLAGS: $LDFLAGS" #echo " CFLAGS: $CFLAGS" #echo " CPPFLAGS: $CPPFLAGS" #echo " X_LIBS: $X_LIBS" #echo " X_PRE_LIBS: $X_PRE_LIBS" #echo "X_EXTRA_LIBS: $X_EXTRA_LIBS" echo =========================================== echo echo AC_PACKAGE_NAME AC_PACKAGE_VERSION has been configured to use the following echo options and external libraries: echo echo MINIMUM OPTIONS: echo " ShapeLib (Vector maps) .................... : $use_shapelib" echo echo RECOMMENDED OPTIONS: echo " Xpm / Snapshots ........................... : $use_xpm" echo -n " GraphicsMagick/ImageMagick (Raster maps) .. : " if test "${use_graphicsmagick}" = "yes"; then echo "yes (GraphicsMagick)" else if test "${use_imagemagick}" = "yes"; then echo "yes (ImageMagick)" else echo "no" fi fi echo " pcre (Shapefile customization) ............ : $use_pcre" echo " Berkeley DB map caching-Raster map speedups : $use_map_cache" echo " internet map retrieval .................... : $use_retrieval" echo echo FOR THE ADVENTUROUS: echo " AX25 (Linux Kernel I/O Drivers) ........... : $use_ax25" echo " libproj (USGS Topos & Aerial Photos) ...... : $use_proj" echo " GeoTiff (USGS Topos & Aerial Photos) ...... : $use_geotiff" echo " Festival (Text-to-speech) ................. : $use_festival" echo " GPSMan/gpsmanshp (GPS downloads) .......... : $use_gpsman" #echo " GPSD Client (libgps) ...................... : $use_libgps" if test "${use_err_popups}" = "yes" -o "${use_libgc}" = "yes" -o "${use_profiling}" = "yes" -o "${use_lsb}" = "yes" -o "${use_spatial_db}" = "yes" -o "$use_mysql_any" = "yes"; then echo echo DEVELOPER OPTIONS: echo " ErrorPopups (Old Method) .................. : $use_err_popups" echo " libgc (Debug memory usage) ................ : $use_libgc" echo " profiling (Debug code efficiency) ......... : $use_profiling" echo " Linux Standard Base (LSB) ................. : $use_lsb" echo " Spatial database support .................. : $use_spatial_db" echo " Spatial database Postgresql/Postgis ....... : $use_postgis" echo " MySQL ..................................... : $use_mysql_any" echo " MySQL Spatial database support ............ : $use_mysql_spatial" fi #echo Davis/MySQL............................. : $davis echo echo AC_PACKAGE_NAME will be installed in $prefix/bin. if test "x$xastirpath" != "x" ; then echo Warning: You have an old copy of Xastir at $xastirpath. fi echo "Type 'make' to build Xastir (Use 'gmake' instead on some systems)." Xastir-Release-2.2.2/git_commit_message_template000066400000000000000000000002231501463444000220200ustar00rootroot00000000000000#If applied, this commit will... # Explain why this change is being made # Provide links to tracker entries, articles or other resources below Xastir-Release-2.2.2/help/000077500000000000000000000000001501463444000152765ustar00rootroot00000000000000Xastir-Release-2.2.2/help/.vimrc000066400000000000000000000014331501463444000164200ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/help/Makefile.am000066400000000000000000000006461501463444000173400ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # helpdir = ${pkgdatadir}/help EXTRA_DIST = \ help-Dutch.dat \ help-English.dat \ help-French.dat \ help-German.dat \ help-Italian.dat \ help-Portuguese.dat \ help-Spanish.dat help_DATA = \ help-Dutch.dat \ help-English.dat \ help-French.dat \ help-German.dat \ help-Italian.dat \ help-Portuguese.dat \ help-Spanish.dat Xastir-Release-2.2.2/help/help-Dutch.dat000066400000000000000000004303761501463444000200020ustar00rootroot00000000000000HELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: http://www.xastir.org http://github.com/Xastir/Xastir There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See http://www.xastir.org to subscribe. For more information on the GNU License look at: http://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X-windows Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html". A great deal of information on APRS(tm) can be found in the APRSdos documentation written by Bob Bruninga. An additional source of information is the APRS(tm) specification, available from http://www.tapr.org . HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA. See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.ew.usna.edu/~bruninga/aprs.html "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degreees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have recieved one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: http://web.usna.navy.mil/~bruninga/dfing.html and the APRSdos documentation for details on these useful techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In hundredth of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In hundredth of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (http://wxsvr.net/) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects [CAD object support has moved from the right click menu to Map/Draw CAD Objects]. CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normaly) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Find Address This option brings up a search dialog where you can enter an address. It will center on the map if the address is found. The path to the geo-coder file is saved between calls. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with ImageMagick support, and does not apply to geoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Configure Tigermap Turning this option on causes Xastir to download the map from the US census bureau's online tiger mapping server. The dialog that comes up allows one to select which layers are displayed, as well as the brightness of the resulting map. This is only available if you have compiled with ImageMagick support. Tigermaps are always loaded as the bottom layer; they do not have layering settings in the Map Chooser. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser and/or Tiger Maps dialog will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions in the README.MAPS file. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the currently available vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported, as well as PocketAPRS format maps and GNIS (Geographic Names Information System) label files. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with ImageMagick support, enabling support for many graphic formats as maps (see "http://www.imagemagick.org/www/formats.html"). Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. Details of locations to obtain many of the above types of maps are found in the file README.MAPS Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in README.MAPS. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with ImageMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/ImageMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (ImageMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. ImageMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use ImageMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. ImageMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: TIGERMAP A file with just the word "TIGERMAP" will cause Xastir to retrieve an online Tiger map of the area on screen. These are not available for every place in the world. "tigermap.geo" is automatically installed in the maps directory. TERRASERVER-SATELLITE A file with just the word "TERRASERVER-SATELLITE" will cause Xastir to retrieve a Terraserver satellite photo of the area on screen. Those services are not available for every place in the world. Note that using the Terraserver maps at any zoom above 256 will probably take a long time to load, won't show much detail, and probably won't display correctly. This is a limit of Microsoft's Terraserver, not Xastir. Also note that crossing UTM zone boundaries is not supported by Terraserver. "terraserver.geo" is automatically installed in the maps directory. TERRASERVER-TOPO A file with just the word "TERRASERVER-TOPO" will cause Xastir to retrieve a topographic map of the area on screen. Those services are not available for every place in the world. Note that using the maps at any zoom above 256 will probably take a long time to load, won't show much detail, and probably won't display correctly. This is a limit of Microsoft's Terraserver, not Xastir. Also note that crossing UTM zone boundaries is not supported by Terraserver. "terraserver-topo.geo" is automatically installed in the maps directory. TERRASERVER-URBAN Same as above but with Terraserver colored urban-area satellite images. "terraserver-urban.geo" is automatically installed in the maps directory. TERRASERVER-REFLECTIVITY Same as above but with Terraserver reflectivity images. "terraserver-reflectivity.geo" is automatically installed in the maps directory. TOPORAMA-250k Canadian 1:250k scale topo maps, downloaded from findu.com. "CanadaTopo250k.geo" is automatically installed in the maps directory. TOPORAMA-50k Canadian 1:50k scale topo maps, downloaded from findu.com. "CanadaTopo50k.geo" is automatically installed in the maps directory. WMSSERVER Allows use of Web Map Services (WMS). An example "WMSRadar.geo" is automatically installed in the maps directory. geoTIFF maps are a combination of two files as well: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS geoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. GNIS (Geographic Names Information System) data is a collection of names of locations, or geographic features. These labels behave like map labels in Dos/WinAPRS maps. As you zoom in, more labels will appear, assuming you've selected the GNIS file as a map and have enabled Map Labels in the Maps menu. If you have some of them in the xastir/GNIS directory, you can also search for map labels within Xastir. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in README.MAPS. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the README.MAPS file. Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: ImageMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the ImageMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapblast2geo.pl This script creates .geo files for Mapblast pixel maps. It includes usage information. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. split_gnis.bash This will take a GNIS data-point file (typically for a whole state, 8+MB), break it down into smaller chunks (typically for a county, 30-200k) it will also throw away the trailing spaces and s at EOL. split_gnis.pl This is a Perl version of the above script. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases [MySQL,Postgis] (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxilliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found in the APRS(tm) Reference which you could get from http://www.tapr.org Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>What was new in Xastir 1.0 Over the past year, Xastir has been under active development, and this new release is the culmination of those efforts. Development has been run by Chuck Byam, who agreed to take over for Frank Giannandrea. Many other individuals have contributed to this project, and are listed in the AUTHORS file. The Xastir package now uses GNU autoconf to build makefiles and select features based on the libraries and software one has installed. No more editing makefiles as in previous releases! Starting Xastir 1.0, one probably won't immediately notice any major changes. The familiar interface of previous Xastir versions has been retained for the most part. The great majority of the changes are improvements in efficiency under the hood: * Startup time for the program has been improved. * Memory usage has greatly improved, with dynamic allocation of separate station, trail, and weather data on an as-needed basis. No longer will memory be wasted on stationary stations for trail data, nor will non-weather stations waste memory for weather information. With these modifications, Xastir can even be connected to the internet link comfortably on a 16MB machine. * Improvements have been made to avoid having to reload maps from disk at every minor change; Weather alerts and changes to the display and tracking options no longer cause the maps to reload, rather the trails and symbols are redrawn alone. * Improvements have been made to various dialog boxes that re-drew often, to redraw less often, to allow them to be usable on slower systems. This is also true of tracking a station, with the map redrawing only if the station approaches the edge of the screen. Thanks to these changes, Xastir is perfectly usable on slower Pentium(tm) machines. Native GeoTIFF support is now included, and will be compiled into one's copy of Xastir if they have the GeoTIFF libraries installed on their system. These map files are of very high quality, and are especially useful in search and rescue operations. Maps on this format are available from the USGS, and commercially on CD-ROM. Xastir understands how to convert from the NAD-27 datum to the new WGS-84 datum, so maps of both format can be read accurately. New shortcut buttons have been added to the map selection dialog to enable one to pick all maps of a specific type. Support for the Festival Speech Synthesis System is now available to announce new stations and band openings. The old system of alert sounds has been retained as well. Xastir now supports adding and deleting objects. Finally, Xastir users are able to manage resources with this useful feature. Objects are helpful for coordinating events, directing travelers, and doing search and rescue work. The County Warning Area maps that display weather alerts are no longer painted onto the maps below, but are shaded onto the maps. While this does make the colors unpredictable, it is now possible to see the road-maps below the alert! A new and useful feature is the change in the orientation of a symbol based on the direction in which it is moving. Even without a trail, a quick glance can tell you a mobile station's bearing. There are several more new options in the display menu, enabling one to decide more precisely what is displayed and what isn't. Panning and control over the map has been enhanced: There are now arrow buttons visible at the top of the screen to pan the map. The map can also be panned with the arrow keys, and the zoom can be adjusted with the page up and page down keys. There are new option in the click menu, to center the map where you clicked or to place an object where you clicked. The panning options in this menu have been removed in favor of the new controls at the top of the screen. Support for altnet has been added, enabling one to have a private APRS(tm) network for special events, search and rescue, storm chasing, or whenever else the user doesn't want to be bothered by the hundreds of APRS(tm) stations around. There are numerous small changes, both visible and invisible to the user. The interface control dialog now has a "Start all" and "Stop all" option, to save the user the time of performing these actions for each interface. The station setup dialog now shows you your symbol, so you don't have to exit the dialog to see which symbol you chose. Several buffer overflows that caused unpredictable behavior and/or crashes have been fixed. And many minor improvements have been made to the source code to ensure that it compiles correctly on various systems. Enjoy the new Xastir! HELP-INDEX>What was new in Xastir 1.1 What was new in Xastir 1.1 This new release, Xastir 1.1, adds significant new features and enhancements to the user interface. Unlike 1.0, the interface changes will take some getting used to, but the flexibility and versatility of the enhanced interface will more than make up for the troubles. Among the improvements to the user interface: * Keyboard shortcuts for menus and dialogs, menu reorganization, and mouse behavior changes. * The ability to move objects or measure distance with the mouse, using the appropriate check-boxes in the toolbar. * A scale has been added to allow one to judge distance on a map. * Map labels for windows-style APRS(tm) maps are rotated to match the marked map features. * The user interface for dealing with objects has been entirely redesigned. * Station info boxes can be set to automatically update. * Tear-off menus. Allow you to keep a menu on the screen and play with different options. Tear off a menu by clicking on the dashed-line portion. Map support has been greatly enhanced, with PocketAPRS, ESRI Shapefiles, GNIS labels and many graphics formats with ImageMagick. Additionally, support for downloading graphical maps from web-servers has been added, allowing Xastir to use online radar, Tiger, and Terraserver maps. Xastir 1.1 supports much more of the APRS(tm) protocol than its predecessor: * It can add, modify, move and view area objects, signpost objects, and items. These features are invaluable for event coordination and search and rescue use. Objects and items are also periodically retransmitted. * Support for displaying position ambiguity squares, pre-calculated radio ranges, Maidenhead grid squares, and weather objects. These features aren't extremely common, but do come up occasionally. * Support for the APRS(tm) radio direction finding features. These features are useful for anything from tracking jammers to locating lost hikers. Xastir supports both Omni and Beam reports. Other notable improvements: * Xastir can now search for a specified location or landmark using GNIS data. * Track logs can now be exported to file. * Maps can be printed if certain tools and libraries are present. * Support for retrieving historical track data from findu.com. * Xastir now compiles and runs on Mac OS X, Solaris and FreeBSD with only minimal changes; see README for details. * Several major bugs found in 1.0 have been corrected, including the problems loading DOS maps and the problems with the weather reporting. Other minor bugs and memory leaks have been fixed. And several more errors have been corrected in the parsing routines, so Xastir should remain stable no matter what is thrown at it! HELP-INDEX>What was new in Xastir 1.2 What was new in Xastir 1.2 The latest Xastir release adds numerous new capabilities, keeping Xastir a benchmark for APRS(tm) programs on any operating system. Xastir's hardware support has been enhanced, with * Support for Serial KISS TNCs * Support for Serial TNCs with GPS on the AUX port * Support for using AGWPE as a TNC * Support for Dallas One-Wire weather station (see http://melhuish.info/simon/projects/oww/) * Support for more weather stations via the wx200d daemon (WX-200/WM-918/ WMR-918/WMR-968) * Support for the different sized rain gauges of the Peet Brothers weather stations. Additionally, several bugs in the weather reporting code were corrected, and support for setting the system clock based on the GPS was added. There have been many additions and improvements to the Xastir user interface: The most notable is the addition of dead-reckoning. This means that stations that are moving will continue to move on your screen in the direction and at the speed speed that they last reported. The estimated location can be shown with any combination of a ghosted icon, a dashed line from the last position, or an arc of expected possible distance and angle. Also very notable are the improvements to the Map Chooser. Maps can now be selected a directory at a time, or individually. And the new map properties dialog allows individual control of map layering, map color filling, and consideration for auto-maps. Additionally, with extent caching under the hood, auto-maps regains much of its formal usefulness even with many maps installed! Bulletins pop up on screen, and emergency beacons cause an alert with the locate station dialog on hand. These changes are helpful in emergencies and event coordination. Xastir can now be set to use one of several coordinate systems, including UTM, dd.ddddd, dd mm.mmm, and dd mm ss.s. This is helpful for coordinating with other groups using a different system. The online Tiger maps can now be enabled from the map menu, and options can be adjusted to request maps with just the data you want displayed. The stations menu has been reorganized, allowing more intuitive filtering of stations shown and of accompanying data. Other smaller interface changes include: * The density of the grid-lines can be adjusted with the +, =, and - keys. * Objects and item lists have been added to the view menu. * Station maidenhead grid squares are now shown in station info and the coordinate calculator. * There is a check-box "Track me" to enable easily tracking your own station * The length of trails downloaded from findu.com can now be specified. * Xastir can now ID via voice IDs or Screen IDs, by editing the configuration file. This is intended for configurations when the Xastir screen is seen remotely via fast-scan TV. * Timestamps are written to log files every 30 seconds of operation, to keep a record of when data was heard. * The status bar can display the course/distance to your station when enabled in the file|configure menu. * Range scales are now shown opposite the map scale. This is an attempt to standardize various APRS(tm) client approaches to zoom levels. New additions under-the-hood: * Tracked proximity alarms. * Export waypoints within proximity boundaries. Your GPS can show you the locations of APRS(tm) stations as waypoints on the GPS map screen. * Export trail as ESRI Shapefile. New feature if you have Shapelib compiled in. Station Info->Store Track button also creates a Shapefile map of the station's track now. The weather reporting features have been improved, with the addition of optional wind barbs to weather stations and decoding of storm wind radius data. Weather alert shading is now done with pixmap stipples showing the type of alert. Further information on an alert is available over the internet from the WXSVR by simply double-clicking the alert in the weather alerts list. Weather alerts now use the newer ESRI Shapefile-format maps. Xastir's map support has been improved with enhancements to the ESRI Shapefile code to handle point-type ESRI Shapefiles. Additionally, speed improvements have been made in the ImageMagick graphical map loading, and many color-correction features have been added. As mentioned above, the Map Chooser has been greatly improved, and weather alerts use ESRI Shapefile-format maps. Under the hood, Xastir has had several major improvements: The messaging system has been largely rewritten, and the annoying timed updates to dialogs no longer occur. The new messaging system allows multiple messages to be queued, and implements reply-ack's for speed. Xastir also attempts to specify a reasonable path for the message based on received messages. This improves speed and congestion control. The messaging GUI has been largely untouched, and remains high on the list of future improvements. The build process has been significantly improved; Xastir is now able to be built on numerous operating systems with few manual interventions. Xastir now supports GPSMan/gpsmanshp, allowing the importing of waypoints, tracks, and routes from several types of GPS receivers. This allows you to create ESRI Shapefile-format maps out of GPS data. Xastir now implements SmartBeaconing(tm), which greatly improves trail quality and reduces unneeded channel usage. See the "Configure SmartBeaconing" help topic. IGating support has also improved, with the ability to configure a specific RF path for IGated packets, and the addition of a 29 second anti-dupe queue to reduce unnecessary redundancy on the RF channel. Map extents and filenames are now cached, so maps will not be loaded from disk unless they are on screen. This is a major improvement for map types that did not specify this information. Additionally, auto-maps uses this information, making it usable even with many maps installed. Objects controlled by Xastir are now stored in a file, so a restart of Xastir will not cause them to be lost. Additionally, Xastir now supports the compressed format for objects and items, which can help reduce RF channel congestion. It also gives you better location accuracy of the placed objects. See the help topic "Configure Default Operation". Xastir now drops root privileges when not needed if run setuid root. Please read the information about this in INSTALL; this change provides only limited protection. Xastir now supports using a private colormap with the command-line argument "-i". This is recommended for systems running in 8-bit color mode. Additionally, several more buffer overruns and other errors were corrected in Xastir's data parser, and numerous other bugs have been fixed. Enjoy the new Xastir! HELP-INDEX>What's new in Xastir 1.3 What's new in Xastir 1.3 This latest Xastir release greatly improves on the efficiency and usability of Xastir, and adds many helpful and often-requested new features. .geo files can now have REFRESH tags, to specify how often the file is reloaded. This is useful for weather radars and other dynamic images. .geo files can also have a TRANSPARENT tag to make a certain color transparent, and a CROP tag to specify a specific region to display. Some Opentrac packets are now decoded and displayed. See http://opentrac.org/ for more details. The default main Xastir directory is now /usr/local/share/xastir; please see the upgrade notes in README for migration information. This more closely mirrors the behavior of other applications. If you're installing from a binary package (rpm/deb/etc), the default install location may be /usr/share/xastir. Xastir efficiency has been greatly improved. Changes in data structures and timing values have made this Xastir release the most efficient yet. Additionally, map redraw sequences are interruptible, so map panning speed has been improved. dbfawk support - Experimental support for configurable shapefile metadata, in an awk-like language. See README.MAPS for more details; this must be turned on with a specific switch to the configure command. GDAL/OGR support - Experimental support for GDAL and loading of native Tiger data (.RT1 files). This is automatically enabled if the GDAL library is found. Support for UTM w/special zones and MGRS coordinate systems. Cad drawing mode allows one to draw regions on your screen using the center mouse button. This feature is not yet complete, but is functional. User interface changes: * Several of the menus have been reorganized to have a hierarchical design. * Additionally, a few colors have been modified for better visibility. * The map label font and style are more configurable * The cursor changes to let one know if they're in move object or measure mode. * If the coordinate system is set to UTM, and "Map Grid" is selected, an UTM grid is displayed. Snapshot mode now generates a .geo file, allowing the image to later be used as a map. Tiger maps have been moved back the chooser, as was the pre-1.2 behavior. This is more consistent. Xastir-Release-2.2.2/help/help-English.dat000066400000000000000000004242031501463444000203140ustar00rootroot00000000000000HELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: http://www.xastir.org http://github.com/Xastir/Xastir There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See http://www.xastir.org to subscribe. For more information on the GNU License look at: http://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X-windows Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html". A great deal of information on APRS(tm) can be found in the APRSdos documentation written by Bob Bruninga. An additional source of information is the APRS(tm) specification, available from http://www.tapr.org . HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occurred right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA. See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.ew.usna.edu/~bruninga/aprs.html "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degrees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have received one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: http://web.usna.navy.mil/~bruninga/dfing.html and the APRSdos documentation for details on these useful techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In hundredth of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In hundredth of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (http://wxsvr.net/) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects [CAD object support has moved from the right click menu to Map/Draw CAD Objects]. CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normally) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Find Address This option brings up a search dialog where you can enter an address. It will center on the map if the address is found. The path to the geo-coder file is saved between calls. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with ImageMagick support, and does not apply to geoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions in the README.MAPS file. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the currently available vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported, as well as PocketAPRS format maps and GNIS (Geographic Names Information System) label files. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with ImageMagick support, enabling support for many graphic formats as maps (see "http://www.imagemagick.org/www/formats.html"). Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. Details of locations to obtain many of the above types of maps are found in the file README.MAPS Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in README.MAPS. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with ImageMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/ImageMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (ImageMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. ImageMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use ImageMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. ImageMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: TOPORAMA-250k Canadian 1:250k scale topo maps, downloaded from findu.com. "CanadaTopo250k.geo" is automatically installed in the maps directory. TOPORAMA-50k Canadian 1:50k scale topo maps, downloaded from findu.com. "CanadaTopo50k.geo" is automatically installed in the maps directory. WMSSERVER Allows use of Web Map Services (WMS). An example "WMSRadar.geo" is automatically installed in the maps directory. geoTIFF maps are a combination of two files as well: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS geoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. GNIS (Geographic Names Information System) data is a collection of names of locations, or geographic features. These labels behave like map labels in Dos/WinAPRS maps. As you zoom in, more labels will appear, assuming you've selected the GNIS file as a map and have enabled Map Labels in the Maps menu. If you have some of them in the xastir/GNIS directory, you can also search for map labels within Xastir. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in README.MAPS. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the README.MAPS file. Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: ImageMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the ImageMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapblast2geo.pl This script creates .geo files for Mapblast pixel maps. It includes usage information. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. split_gnis.bash This will take a GNIS data-point file (typically for a whole state, 8+MB), break it down into smaller chunks (typically for a county, 30-200k) it will also throw away the trailing spaces and s at EOL. split_gnis.pl This is a Perl version of the above script. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases [MySQL,Postgis] (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxiliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found in the APRS(tm) Reference which you could get from http://www.tapr.org Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>What was new in Xastir 1.0 Over the past year, Xastir has been under active development, and this new release is the culmination of those efforts. Development has been run by Chuck Byam, who agreed to take over for Frank Giannandrea. Many other individuals have contributed to this project, and are listed in the AUTHORS file. The Xastir package now uses GNU autoconf to build makefiles and select features based on the libraries and software one has installed. No more editing makefiles as in previous releases! Starting Xastir 1.0, one probably won't immediately notice any major changes. The familiar interface of previous Xastir versions has been retained for the most part. The great majority of the changes are improvements in efficiency under the hood: * Startup time for the program has been improved. * Memory usage has greatly improved, with dynamic allocation of separate station, trail, and weather data on an as-needed basis. No longer will memory be wasted on stationary stations for trail data, nor will non-weather stations waste memory for weather information. With these modifications, Xastir can even be connected to the internet link comfortably on a 16MB machine. * Improvements have been made to avoid having to reload maps from disk at every minor change; Weather alerts and changes to the display and tracking options no longer cause the maps to reload, rather the trails and symbols are redrawn alone. * Improvements have been made to various dialog boxes that re-drew often, to redraw less often, to allow them to be usable on slower systems. This is also true of tracking a station, with the map redrawing only if the station approaches the edge of the screen. Thanks to these changes, Xastir is perfectly usable on slower Pentium(tm) machines. Native GeoTIFF support is now included, and will be compiled into one's copy of Xastir if they have the GeoTIFF libraries installed on their system. These map files are of very high quality, and are especially useful in search and rescue operations. Maps on this format are available from the USGS, and commercially on CD-ROM. Xastir understands how to convert from the NAD-27 datum to the new WGS-84 datum, so maps of both format can be read accurately. New shortcut buttons have been added to the map selection dialog to enable one to pick all maps of a specific type. Support for the Festival Speech Synthesis System is now available to announce new stations and band openings. The old system of alert sounds has been retained as well. Xastir now supports adding and deleting objects. Finally, Xastir users are able to manage resources with this useful feature. Objects are helpful for coordinating events, directing travelers, and doing search and rescue work. The County Warning Area maps that display weather alerts are no longer painted onto the maps below, but are shaded onto the maps. While this does make the colors unpredictable, it is now possible to see the road-maps below the alert! A new and useful feature is the change in the orientation of a symbol based on the direction in which it is moving. Even without a trail, a quick glance can tell you a mobile station's bearing. There are several more new options in the display menu, enabling one to decide more precisely what is displayed and what isn't. Panning and control over the map has been enhanced: There are now arrow buttons visible at the top of the screen to pan the map. The map can also be panned with the arrow keys, and the zoom can be adjusted with the page up and page down keys. There are new option in the click menu, to center the map where you clicked or to place an object where you clicked. The panning options in this menu have been removed in favor of the new controls at the top of the screen. Support for altnet has been added, enabling one to have a private APRS(tm) network for special events, search and rescue, storm chasing, or whenever else the user doesn't want to be bothered by the hundreds of APRS(tm) stations around. There are numerous small changes, both visible and invisible to the user. The interface control dialog now has a "Start all" and "Stop all" option, to save the user the time of performing these actions for each interface. The station setup dialog now shows you your symbol, so you don't have to exit the dialog to see which symbol you chose. Several buffer overflows that caused unpredictable behavior and/or crashes have been fixed. And many minor improvements have been made to the source code to ensure that it compiles correctly on various systems. Enjoy the new Xastir! HELP-INDEX>What was new in Xastir 1.1 What was new in Xastir 1.1 This new release, Xastir 1.1, adds significant new features and enhancements to the user interface. Unlike 1.0, the interface changes will take some getting used to, but the flexibility and versatility of the enhanced interface will more than make up for the troubles. Among the improvements to the user interface: * Keyboard shortcuts for menus and dialogs, menu reorganization, and mouse behavior changes. * The ability to move objects or measure distance with the mouse, using the appropriate check-boxes in the toolbar. * A scale has been added to allow one to judge distance on a map. * Map labels for windows-style APRS(tm) maps are rotated to match the marked map features. * The user interface for dealing with objects has been entirely redesigned. * Station info boxes can be set to automatically update. * Tear-off menus. Allow you to keep a menu on the screen and play with different options. Tear off a menu by clicking on the dashed-line portion. Map support has been greatly enhanced, with PocketAPRS, ESRI Shapefiles, GNIS labels and many graphics formats with ImageMagick. Additionally, support for downloading graphical maps from web-servers has been added, allowing Xastir to use online radar, Tiger, and Terraserver maps. Xastir 1.1 supports much more of the APRS(tm) protocol than its predecessor: * It can add, modify, move and view area objects, signpost objects, and items. These features are invaluable for event coordination and search and rescue use. Objects and items are also periodically retransmitted. * Support for displaying position ambiguity squares, pre-calculated radio ranges, Maidenhead grid squares, and weather objects. These features aren't extremely common, but do come up occasionally. * Support for the APRS(tm) radio direction finding features. These features are useful for anything from tracking jammers to locating lost hikers. Xastir supports both Omni and Beam reports. Other notable improvements: * Xastir can now search for a specified location or landmark using GNIS data. * Track logs can now be exported to file. * Maps can be printed if certain tools and libraries are present. * Support for retrieving historical track data from findu.com. * Xastir now compiles and runs on Mac OS X, Solaris and FreeBSD with only minimal changes; see README for details. * Several major bugs found in 1.0 have been corrected, including the problems loading DOS maps and the problems with the weather reporting. Other minor bugs and memory leaks have been fixed. And several more errors have been corrected in the parsing routines, so Xastir should remain stable no matter what is thrown at it! HELP-INDEX>What was new in Xastir 1.2 What was new in Xastir 1.2 The latest Xastir release adds numerous new capabilities, keeping Xastir a benchmark for APRS(tm) programs on any operating system. Xastir's hardware support has been enhanced, with * Support for Serial KISS TNCs * Support for Serial TNCs with GPS on the AUX port * Support for using AGWPE as a TNC * Support for Dallas One-Wire weather station (see http://melhuish.info/simon/projects/oww/) * Support for more weather stations via the wx200d daemon (WX-200/WM-918/ WMR-918/WMR-968) * Support for the different sized rain gauges of the Peet Brothers weather stations. Additionally, several bugs in the weather reporting code were corrected, and support for setting the system clock based on the GPS was added. There have been many additions and improvements to the Xastir user interface: The most notable is the addition of dead-reckoning. This means that stations that are moving will continue to move on your screen in the direction and at the speed speed that they last reported. The estimated location can be shown with any combination of a ghosted icon, a dashed line from the last position, or an arc of expected possible distance and angle. Also very notable are the improvements to the Map Chooser. Maps can now be selected a directory at a time, or individually. And the new map properties dialog allows individual control of map layering, map color filling, and consideration for auto-maps. Additionally, with extent caching under the hood, auto-maps regains much of its formal usefulness even with many maps installed! Bulletins pop up on screen, and emergency beacons cause an alert with the locate station dialog on hand. These changes are helpful in emergencies and event coordination. Xastir can now be set to use one of several coordinate systems, including UTM, dd.ddddd, dd mm.mmm, and dd mm ss.s. This is helpful for coordinating with other groups using a different system. The online Tiger maps can now be enabled from the map menu, and options can be adjusted to request maps with just the data you want displayed. The stations menu has been reorganized, allowing more intuitive filtering of stations shown and of accompanying data. Other smaller interface changes include: * The density of the grid-lines can be adjusted with the +, =, and - keys. * Objects and item lists have been added to the view menu. * Station maidenhead grid squares are now shown in station info and the coordinate calculator. * There is a check-box "Track me" to enable easily tracking your own station * The length of trails downloaded from findu.com can now be specified. * Xastir can now ID via voice IDs or Screen IDs, by editing the configuration file. This is intended for configurations when the Xastir screen is seen remotely via fast-scan TV. * Timestamps are written to log files every 30 seconds of operation, to keep a record of when data was heard. * The status bar can display the course/distance to your station when enabled in the file|configure menu. * Range scales are now shown opposite the map scale. This is an attempt to standardize various APRS(tm) client approaches to zoom levels. New additions under-the-hood: * Tracked proximity alarms. * Export waypoints within proximity boundaries. Your GPS can show you the locations of APRS(tm) stations as waypoints on the GPS map screen. * Export trail as ESRI Shapefile. New feature if you have Shapelib compiled in. Station Info->Store Track button also creates a Shapefile map of the station's track now. The weather reporting features have been improved, with the addition of optional wind barbs to weather stations and decoding of storm wind radius data. Weather alert shading is now done with pixmap stipples showing the type of alert. Further information on an alert is available over the internet from the WXSVR by simply double-clicking the alert in the weather alerts list. Weather alerts now use the newer ESRI Shapefile-format maps. Xastir's map support has been improved with enhancements to the ESRI Shapefile code to handle point-type ESRI Shapefiles. Additionally, speed improvements have been made in the ImageMagick graphical map loading, and many color-correction features have been added. As mentioned above, the Map Chooser has been greatly improved, and weather alerts use ESRI Shapefile-format maps. Under the hood, Xastir has had several major improvements: The messaging system has been largely rewritten, and the annoying timed updates to dialogs no longer occur. The new messaging system allows multiple messages to be queued, and implements reply-ack's for speed. Xastir also attempts to specify a reasonable path for the message based on received messages. This improves speed and congestion control. The messaging GUI has been largely untouched, and remains high on the list of future improvements. The build process has been significantly improved; Xastir is now able to be built on numerous operating systems with few manual interventions. Xastir now supports GPSMan/gpsmanshp, allowing the importing of waypoints, tracks, and routes from several types of GPS receivers. This allows you to create ESRI Shapefile-format maps out of GPS data. Xastir now implements SmartBeaconing(tm), which greatly improves trail quality and reduces unneeded channel usage. See the "Configure SmartBeaconing" help topic. IGating support has also improved, with the ability to configure a specific RF path for IGated packets, and the addition of a 29 second anti-dupe queue to reduce unnecessary redundancy on the RF channel. Map extents and filenames are now cached, so maps will not be loaded from disk unless they are on screen. This is a major improvement for map types that did not specify this information. Additionally, auto-maps uses this information, making it usable even with many maps installed. Objects controlled by Xastir are now stored in a file, so a restart of Xastir will not cause them to be lost. Additionally, Xastir now supports the compressed format for objects and items, which can help reduce RF channel congestion. It also gives you better location accuracy of the placed objects. See the help topic "Configure Default Operation". Xastir now drops root privileges when not needed if run setuid root. Please read the information about this in INSTALL; this change provides only limited protection. Xastir now supports using a private colormap with the command-line argument "-i". This is recommended for systems running in 8-bit color mode. Additionally, several more buffer overruns and other errors were corrected in Xastir's data parser, and numerous other bugs have been fixed. Enjoy the new Xastir! HELP-INDEX>What's new in Xastir 1.3 What's new in Xastir 1.3 This latest Xastir release greatly improves on the efficiency and usability of Xastir, and adds many helpful and often-requested new features. .geo files can now have REFRESH tags, to specify how often the file is reloaded. This is useful for weather radars and other dynamic images. .geo files can also have a TRANSPARENT tag to make a certain color transparent, and a CROP tag to specify a specific region to display. Some Opentrac packets are now decoded and displayed. See http://opentrac.org/ for more details. The default main Xastir directory is now /usr/local/share/xastir; please see the upgrade notes in README for migration information. This more closely mirrors the behavior of other applications. If you're installing from a binary package (rpm/deb/etc), the default install location may be /usr/share/xastir. Xastir efficiency has been greatly improved. Changes in data structures and timing values have made this Xastir release the most efficient yet. Additionally, map redraw sequences are interruptible, so map panning speed has been improved. dbfawk support - Experimental support for configurable shapefile metadata, in an awk-like language. See README.MAPS for more details; this must be turned on with a specific switch to the configure command. GDAL/OGR support - Experimental support for GDAL and loading of native Tiger data (.RT1 files). This is automatically enabled if the GDAL library is found. Support for UTM w/special zones and MGRS coordinate systems. Cad drawing mode allows one to draw regions on your screen using the center mouse button. This feature is not yet complete, but is functional. User interface changes: * Several of the menus have been reorganized to have a hierarchical design. * Additionally, a few colors have been modified for better visibility. * The map label font and style are more configurable * The cursor changes to let one know if they're in move object or measure mode. * If the coordinate system is set to UTM, and "Map Grid" is selected, an UTM grid is displayed. Snapshot mode now generates a .geo file, allowing the image to later be used as a map. Tiger maps have been moved back the chooser, as was the pre-1.2 behavior. This is more consistent. Xastir-Release-2.2.2/help/help-French.dat000066400000000000000000001033231501463444000201250ustar00rootroot00000000000000HELP-INDEX>ME LIRE EN PREMIER - License ME LIRE EN PREMIER pour XASTIR Traduction Francaise par F1SJE F1SJE@F1SJE.FRPA.FRA.EU Correction et derniers peaufinages F1IOL@F6KBF.FRPA.FRA.EU !!! NOTE: Ces documentations ne sont peut-tre pas jour ou incompltes Les plus rcentes informations sont dans le README.1ST dans le rpertoire Xastir. Ce programme est destin a tre utilis par des radio-amateurs DANS LE CADRE DE LEUR REGLEMENTATION NATIONALE. LICENSE : XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Ce programme est libre; vous pouvez le redistribuer et le modifier dans les conditions dfinies dans la "GNU General Public License" (version 2 ou suprieure) dfinie par la "Free Software Fondation". mais SANS AUCUNE GARANTIE. Voir la "GNU General Public License" pour plus de dtails. Vous devriez avoir recu une copie de la "GNU General Public License" avec ce programme sinon crivez : the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Plus d'informations sur ce programme peuvent tre trouve sur sa page Web : http://www.xastir.org http://github.com/Xastir/Xastir Pour plus d'informations sur la License GNU regardez sur : http://www.gnu.org HELP-INDEX>Bienvenue! Et notes de l'auteur. Bienvenue dans Xastir XASTIR, ou X-windows Amateur Station Tracking and Information Reporting. C'est un programme APRS(tm) dont les sources sont ouvertes et libres d'utilisation et de diffusion. Ce programme est en cours de dveloppement et ne devrait pas tre vu comme un produit fini. J'aurai besoin de votre aide pour le rendre plus fonctionnel. J'ai beaucoup d'ides mais peu de temps alors si vous pensez pouvoir m'aider n'hsitez pas et faite moi le savoir! 73s Frank Giannandrea APRS[tm] est une marque dpose de Bob Bruninga, Sa page d'accueil est "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Dbuter Dbuter Maintenant que Xastir fonctionne il faut le configurer ! Le menu Configurer va vous permettre de paramtrer votre station. La plupart de options par dfaut vous permettent dj de travailler. Le sous menu dfaut vous permet de slectionner les valeurs des diffrents intervals de temps, les options de transmission et les fonctions du gateway internet. Le sous menu interfaces vous permet de paramtrer vos priphriques srie, AX25, GPS, Stations mto, Connexions internet etc... Vous pouvez galement modifier les paramtres de ces interfaces avec ce menu. Pour commencer le plus important est de configurer la station; indicatif, Latitude/Longitude (Si vous n'avez pas de GPS), incertitude quant la position et autres informations. Alarmes sonores va configurer les sons en fonction des vnements. Mesure vous permettra de choisr entre systme mtrique ou mesures anglaises. NOTE : Dans les menus les options grises sont actives, quand vous slectionnez vous faites passer l'option en gris. HELP-INDEX>Configuration de la station Configuration de la station Entrez votre indicatif/SSID. Le dfaut est NOCALL, si vous ne savez pas ce que ca veut dire peut-etre ne devriez vous pas utiliser ce programme. Ensuite entrez latitude et longitude en degrs, minutes, centimes N pour Nord, S pour Sud, E pour Est et attention W pour Ouest (Ndt : allez on ne va pas modifier les sources pour ca hi ! ) Maintenant entrez votre Groupe/Overlay et le symbole de votre station. Regardez le listing des tables pour choisir votre symbole. Par dfaut le symbole est x pour xwindows/Unix et le groupe est "/". Si vous voulez autre chose entrez la lettre ou le chiffre dans la fentre Groupe/Overlay et prenez un symbole dans le groupe "\". Ce n'est pas obligatoire mais si vous voulez entrez ensuite la puissance, la hauteur et le gain de votre antenne en vous aidant des tableaux ci-dessous : Chiffre a utiliser 0 1 2 3 4 5 6 7 8 9 Puissance (en watts) 0 1 4 9 16 25 36 49 64 81 Exemple : Entrez 6 pour 36 Watts Idem pour la hauteur, ce n'est pas la hauteur au dessus du sol mais la hauteur au dessus du niveau de la mer. Chiffre a utiliser 0 1 2 3 4 5 6 7 8 9 Hauteur 10 20 40 80 160 320 640 1280 2560 5120 Exemple : Entrez 7 pour 1280m Pour le gain mettez simplement le gain de votre antenne en dB. Ci dessous en degrs par rapport au nord Chiffre a utiliser 0 1 2 3 4 5 6 7 8 9 Direction (deg) 0 45 90 135 180 225 270 315 360 None Utilisez 0 pour une antenne omnidirectionnelle (Verticale) Entrez un commentaire, ce n'est pas exig mais personnalisera votre station. L'incertitude quant votre position vous permet de grer la prcision avec laquelle vous allez transmettre votre position. Avec aucune votre station transmettra la position exacte que vous avez entre ou recue par GPS sinon votre station sera vue quelque part dans les limites choisies. cliquez sur OK pour sauvegarder vos changements, cliquez sur annuler pour conserver les paramtres courants. HELP-INDEX>Comment utiliser mon GPS avec Xastir Comment utiliser mon GPS avec Xastir Vous avez 3 solutions, un GPS en rseau , un GPS sur port srie ou un GPS sur port srie avec TNC et cble HSP. L'intrt d'un GPS en rseau est que vous pouvez le partager avec d'autres programmes. Xastir peut se connecter en rseau sur un dmon nomm GPSD. Ce programme envoie des donnes GPS standards sur le rseau. Certaines versions autorisent une connexion GPS sur internet. Une fois install sur votre machine (ou une autre en rseau) vous pouvez y connnecter Xastir en crant une interface. Cliquez sur Configurer/Interfaces Ajouter Rseau GPS (avec gpsd) Entrez le nom de la machine ou vous avez install GPSD et le nom du port. Validez les 2 autres options selon ce que vous voulez. GPS srie : C'est un GPS srie standard connect sur port srie qui doit transmettre ses donnes au format NEMA. Procdez comme pour gpsd pour l'ajouter, mettez le port srie utilis, en principe les paramtres par dfaut pour le port srie doivent fonctionner sinon ajustez les l'aide de la doc de votre appareil. HSP TNC/GPS: Regardez "Comment utiliser mon TNC avec Xastir?" HELP-INDEX>Comment utiliser mon TNC avec Xastir? Comment utiliser mon TNC avec Xastir? La encore vous avez trois solutions : Un TNC en rseau (AX25), un TNC sur port srie et un TNC avec cble HSP et GPS. AX25 : C'est simplement un des ports du kernel AX25 de Linux, vous devez avoir les librairies AX25 d'installes et le support AX25 dans le Kernel. TNC Srie : TNC Srie avec HSP et GPS : HELP-INDEX>Configurer les Defauts Configurer les Defauts cliquez sur Configurer/Defaut. Slectionnez l'intervalle de temps au del duquel votre station sera considre comme vieille, 2 heures par default. Au bout de cet intervalle de temps l'icone de la station deviendra ombre ou transparente. Cliquez sur OK pour sauvegarder vos changements, Cliquez sur annuler pour conserver les paramtres courants. HELP-INDEX>Configurer le port GPS Configurer le port GPS cliquez sur Configurer/Interfaces Ajouter Srie GPS pour un GPS seul, vous utiliserez un port srie style ttyS1. Si vous avez un cble HSP qui vous permet de partager le port TNC avec un GPS vous devez slectionner Srie TNC/GPS sur cble HSP. C'est un cble spcial qui ne fonctionne pas sur toutes combinaisons de machines/GPS/TNC. Attention aux paramtres de transmission, soyez sympas avec les autres utilisateurs de la frquence. Pour activer l'utilisation du GPS slectionner l'option autorisation de transmettre sinon vous transmettrez les donnes que vous avez configures dans le sous menu station. Ces donnes seront mises a jours automatiquement si vous utilisez un GPS. Quand vous utilisez GPS vous denenez une station mobile avec vitesse et direction mme si vous ne bougez pas, les donnes transmises changent. (Je changerai cela avec une option plus tard) Vous devrez slectionnez les intervalles de transmission directement avec le GPS, les options par defaut de votre station ne seront plus prises en compte. Si vous etes en fixe mettez 10 minutes, sinon choissisez les options selon vos besoins. Cliquez sur OK pour sauvegarder vos changements, Cliquez sur annuler pour conserver les paramtres courants. HELP-INDEX>Configurer le port TNC Configurer le port TNC cliquez sur Configurer/Interface Ajouter Choisir votre TNC Slectionnez activer au dmarrage et autorisation de transmettre selon vos besoins. Entrez le port et paramtrez le. Entrez le chemin des UNPROTOS. Xastir par dfaut a dj le chemin VIA XX. Vous pouvez en ajouter 3 autres de manire a tre bien entendu mme dans de mauvaises conditions. En fonction des champs remplis Xastir commencera un cycle d'envoi vers ces destinations, l'une aprs l'autre a chaque fois qu'il sera l'heure de transmettre. Si vous tes en local sans digi mettez WIDE2-2, si vous etes QRP ou loin d'un digi WIDE1-1,WIDE2-2 fonctionnera mieux. Si vous tes prs d'un digi vous pouvez mettre INDICATIF,WIDE2-2. La plupart d'entre vous n'avez besoin que d'un chemin mais si vous n'etes pas bien dgag mettez en plusieurs, demandez aux stations qui vous entourent. Cliquez sur OK pour sauvegarder vos changements, Cliquez sur annuler pour conserver les paramtres courants. HELP-INDEX>Configurer la connexion Internet Configurer la connexion Internet Vous devez connatre un serveur et un n de port, par defaut www.aprs.net port 10151. Un mot de passe valide autorisera votre station transmettre par internet et tre retransmise sur l'air. Pour obtenir un mot de passe contacter Steve Dimse, K4HG www.aprs.net en lui prcisant vos nom, indicatif etc etc... Aprs vrification il vous donnera votre code. Sans code par d'accs sur l'air mais vous tes quand mme forward sur Internet. Validez reconnexion sur erreur rseau pour une reconnexion automatique en cas de coupure. Dans Configurer/options vous avez la possiblit de devenir un Gateway vous aussi. FAITES TRES ATTENTION cette option, contactez Steve Dimse et veillez rester en conformit avec la rglementation en vigueur. Dans interface/fichier journal vous avez une option pour enregistrer tous les vnements du Gateway. Cliquez sur OK pour sauvegarder vos changements, Cliquez sur annuler pour conserver les paramtres courants. APRS[tm] est une marque dpose de Bob Bruninga, Sa page d'accueil est "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>Configurer alertes sonores Configurer alertes sonores Bien videment vous devez avoir une carte son ! il vous faudra aussi un programme qui joue les .wav, mettez le chemin complet dans la fentre commande audio. Choix disponibles : Nouvelle station Nouveau message Proximit Ouverture de bande Distance Minimum Distance Maximum Alerte Mto HELP-INDEX>Configuration des Units Configuration des Units Ceci selectionne le systme d'units, par defaut mtrique. Sinon les mesures anglaises sont disponibles. HELP-INDEX>Ligne de status infrieure Ligne de status infrieure En bas de la fentre vous pouvez voir diffrents messages : 1re fenetre : messages gnraux. 2me fentre : Latitude/Longitude du pointeur sur la carte. 3me fentre : Nombre de stations dans la base de donne. 4me fentre : Niveau de Zoom et Tr si le suivi de station est actif. Les 2 dernires fentres montrent le status du TNC et du rseau. Un ">" pour des donnes sortantes et un "<" pour des donnes entrantes. HELP-INDEX>Mouvements de la carte (Zoom et N.S.E.W) et menu options Mouvements de la carte (Zoom et N.S.E.W) et menu options Les mouvements de la carte sont trs simple, la facilit et la rapidit des mouvements dpend de la vitesse du processeur et du niveau de dtail des cartes charges. Il suffit de cliquer sur un point de carte pour voir s'ouvrir un menu qui permet de Zoomer sur ce point, voir + au nord, sud est ou ouest par rapport au centre de la carte; plus le zoom est petit plus le grossissement est grand. Le sous menu information sur la station vous donne les lments de la station la plus proche du point ou vous avez cliqu. S'il y a plusieurs stations non loin un choix vous sera propos. HELP-INDEX>Menu Cartes et choix de cartes Menu Cartes et choix de cartes Carte automatique Actif/Inactif Si actif toutes les cartes du sous rpertoire "map" et toutes celle des rpertoires dessous seront affiches si elles correspondent la rgion sur laquelle vous travaillez. Ceci peut ralentir considrablement le systme si vous avez beaucoup de cartes et un ordinateur trs lent. Si inactif seules les cartes choisies dans cartes/choisir une carte seront affiches. Quadrillage Actif/Inactif Active un quadrillage tous les 10. Niveau Actif/Inactif Active le filtrage des petits dtails quand le niveau de zoom montre une large surface, fonctionne seulement avec le cartes gnres avec "Tiger Line maps" (Site aprs.rutgers.edu). Choisir une carte Cliquez simplement sur les cartes que vous voulez afficher. Vous pouvez en prendre autant que vous voulez. cliquez sur OK pour afficher vos cartes, cliquez sur annuler pour conserver les paramtres courants. HELP-INDEX>Options Visualisation Options Visualisation Ces options vous permettent d'afficher des donnes autour des stations se trouvant sur la carte. Altitude Actif/Inactif Si actif une ligne bleue de donnes aparait au dessus de l'indicatif, indiquant la dernire altitude connue de la station. Route Actif/Inactif Si actif une ligne verte de donnes aparait au dessous de l'indicatif, indiquant le dernier azimut connu de la station. Vitesse Actif/Inactif Si actif une ligne rouge de donnes aparait au dessous de l'indicatif ou de la trajectoire indiquant la dernire vitesse connue de la station. Distance/Orientation Actif/Inactif Si actif deux lignes de donnes aparaissent gauche de l'indicatif, la ligne du dessus indique la distance par rapport votre station, celle du dessous l'azimut. Trajectoire des stations Actif/Inactif Si actif toutes les stations en mouvement traceront une ligne de couleur affichant les 100 dernires positions. Quand la station devient vieille et que sont icones est transparente la trajectoire n'est plus en ligne continue. PHG Actif/Inactif Si actif on verra des cercles Puissance/Gain autour de la station. Suivre une station Ouvrira une fentre ou vous pourrez entrer un indicatif. cliquez sur suivre maintenant et l'affichage ira sur cette station et continuera de la suivre quand elle enverra d'autres donnes. cliquez sur fin de suivi pour arrter. Cliquez sur Annuler pour quitter sans changement. Information Mto Si actif Les dernires donnes mto seront affiches (T, Vitesse et direction du vent, rafales, humidit) HELP-INDEX>Messages Messages Composer un message et message de groupe C'est a peu prt la mme chose. Composer un message enverra votre message une unique station, inversement vous ne recevrez des messages que de cette station. Message de groupe enverra un message a un groupe de personnes et inversement vous recevrez tous les messages posts dans ce groupe. Actuellement les messages de groupe ne fonctionnent pas tout fait bien. Dans chacun de ces crans il y a une fentre Message, une ligne Message, une fentre ident. de la station et quelques boutons. Entrez en premier l'indicatif de la station ou le groupe. Ceci fait vous recevrez dj tous les messages de la station ou du groupe; une fentre s'ouvrira s'il n'y en a pas d'ouverte. Vous pouvez maintenant entrer un message de 250 caractres maxi sur la ligne message, cliquez sur transmettre maintenant pour l'envoyer. Le bouton restera gris j'usqu'a reception d'un accus de rception. Les messages recus seront tris et s'afficheront dans la fentre message. En mode groupe vous verrez l'indicatif de l'expditeur suivi du message; les messages seront tris par indicatif. Quand vous avez termin cliquez sur fermer. Le bouton nouvelle identit vous permet de voir les anciens messages qu'une station a envoys; tapez son indicatif pour les afficher. Bien entendu ce bouton peut servir changer la station avec qui vous parlez. Le bouton effacer tous les messages effacera tous les messages de la fentre en cours. Effacer tous les messages sortants Efface tous les messages non acquitts. Rponse automatique Active ou dsactive la rponse automatique. Message de rponse automatique Configure un message de rponse automatique. HELP-INDEX>Effacer toutes les stations Effacer toutes les stations cliquez sur fichier/Effacer toutes les stations enlevera toutes les station de votre cran et de la base de donnes station. HELP-INDEX>Relire un fichier journal Relire un fichier journal cliquez sur Fichier/ouvrir un fichier journal. Choisissez un fichier journal, votre station va se comporter comme si elle recevait en mmettait de nouveau, simulant les vnements du fichier journal. Ca peut bien sur crer quelques messages d'alerte si par exemple vous avez eu une session message, votre station va renvoyer les messages un fichier journal ! HELP-INDEX>Localiser une Station Localiser une Station Cliquer sur examiner/localiser une station, une fentre s'ouvre, entrez un indicatif ou une partie. Par dfaut Xastir cherchera la correspondance exacte (D'une station ou d'un objet). Case exact vous permettra de chercher sans prendre en compte la diffrence majuscule/minuscule. Cliquez sur trouver maintenant centrera l'cran sur la premire correspondance trouve. Cliquer sur annuler fermera la fentre. HELP-INDEX>Table des symboles Table des symboles Symbole Groupe / Groupe \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat Xastir-Release-2.2.2/help/help-German.dat000066400000000000000000002607511501463444000201420ustar00rootroot00000000000000HELP-INDEX>Einfhrende Worte / Lizenzbestimmungen Einfhrende Worte / Lizenzbestimmungen Fr die aktuellsten Informationen und genauere Installationshinweise lesen sie bitte die README Datei im Xastir Hauptverzeichnis. Beachten Sie auch die Dateien LICENCE und COPYING fr weitere Informationen. Bitte denken sie daran, da dieses Programm fr den Einsatz im Amateurfunk bestimmt ist. In Deutschland mu man im Besitz eines Funkzeugnises sein, um auf Amateurfunkfrequenzen senden zu drfen. Informationen zum Erwerb eines Funkzeugisses findet man beim Amateurfunkclub DARC http://www.darc.de. Auch in anderen Lndern gelten hnliche Bestimmungen, die zu beachten sind. Die Entwicklung der Software und die Dokumentation erfolgte zunchst in Englisch, so da im Zweifelsfall die englische Version aktueller sein knnte. Die vorliegende deutsche Hilfedatei wurde von DK7IN bersetzt. Korrekturen und Anregungen bitte an xastir@dk7in.de LIZENZBESTIMMUNGEN fr XASTIR: XASTIR steht unter der GNU Lizenz, im Folgenden der englische Wortlaut. Die Details der GNU-Lizenz finden sich in der Datei LICENCE. XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA Weitere Informationen zum Programm findet man unter: http://www.xastir.org http://github.com/Xastir/Xastir Es gibt einige Mailinglisten zu XASTIR. Melden sie sich zu einer oder beiden unter http://www.xastir.org an, um die neuesten Diskussionen rund um XASTIR zu verfolgen. Weitere Informationen zur GNU Lizenz finden sich auf: http://www.gnu.org Informationen ber Freie Software in deutscher Sprache finden Sie bei der Free Software Foundation Europe http://fsfeurope.org/index.de.html HELP-INDEX>Willkommen! und Anmerkungen der Autoren Willkommen! und Anmerkungen der Autoren XASTIR (X-Window Amateur Station Tracking and Information Reporting) XASTIR ist ein APRS(tm)-Programm, das als Open Source frei benutzt und an andere weitergegeben werden darf. Das Programm befindet sich momentan im Entwicklungsstadium und sollte nicht als fertiges Produkt angesehen werden! Mit ihrer Mitarbeit kann dieses Programm besser werden. Wenn sie also Programmiererfahrung haben, oder Dokumentation schreiben knnen, knnen wir ihre Hilfe gebrauchen. Wir haben eine Menge Ideen aber nur begrenzte Zeit. Wenn sie also denken, einen Beitrag leisten zu knnen, lassen sie es uns wissen! APRS[tm] ist ein Warenzeichen von Bob Bruninga, seine Homepage ist "http://web.usna.navy.mil/~bruninga/aprs.html" Beachten Sie bitte, da sehr viel Information zu APRS(tm) in der von Bob Bruninga geschriebenen Dokumentationen zu APRSdos enthalten ist. Eine weitere Informationsquelle ist die von http://www.tapr.org als PDF-Dokument erhltliche APRS Spezifikation. HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Der erste Aufruf von Xastir Der erste Aufruf von Xastir Beim ersten Start von Xastir sollten sie das Programm aus einem Terminalfenster heraus aufrufen, um mgliche Fehlermeldungen sehen zu knnen. Da auf den meisten Systemen der Pfad so eingerichtet ist, da Programme in /usr/local/bin gefunden werden, reicht es am Prompt "xastir &" einzugeben. Auf anderen Systemen mu "/usr/local/bin/xastir &" eingegeben werden, um das Programm zu starten. Das '&' sorgt dafr, da Xastir im Hintergrund gestartet wir, so da das Terminalfenster noch anderweitig verwendet werden kann. Sie knnen beim Aufruf auch gleich die Sprache whlen. Um die Sprache zu ndern, rufen sie Xastir mit der Option -l auf: xastir -lGerman Weitere Mglichkeiten sind: xastir -l Dutch xastir -l English xastir -l French xastir -l Italian xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish Die so gewhlte Sprache wird in der Konfigurationsdatei des Benutzers gespeichert und auch beim nchsten Aufruf ohne diese Option verwendet. Bei einem neu installierten Xastir ist die Voreinstellung Englisch bis zu einer nderung mit dieser Option. Die Menus am oberen Rand knnen auch mit Tastenkrzeln erreicht werden. Diese funktionieren gegebenenfalls nicht, wenn NumLock eingeschaltet ist. Vor der Benutzung mu Xastir und einige Schnittstellen konfiguriert werden. Die Schnittstellenkonfiguration ist detailliert in der Hilfe unter "Schnittstellen" beschrieben. HELP-INDEX>Stationsdaten Stationsdaten Klicken sie auf Datei, Einstellungen, dann auf Meine Stationsdaten Tragen sie ihr Amateurfunk-Rufzeichen ein. Tragen sie die Position ihrer Station ein, wenn sie Xastir nicht zusammen mit einem GPS-Empfnger einsetzen. Sie knnen ihre ungefhre Position auch mit einer Karte in Xastir bestimmen indem sie die Maus auf der Karte plazieren und die Position in der Statuszeile ablesen. Wenn sie einen GPS-Empfnger haben knnen sie diesen Schritt berspringen und stattdessen spter den GPS-Empfnger einrichten. Whlen sie ein Symbol fr ihre Station, hierzu ist die Angabe der Gruppe und des eigentlichen Symbolzeichens erforderlich. Sie knnen dies manuell eintragen, oder nach Drcken auf Auswahl aus einer grafischen Symbolbersicht auswhlen. Es stehen zwei Gruppen von Symbolen zur Verfgung. Eine Beschreibung der Symbolbedeutung findet sich im Hilfetext "Symboltabelle". Fr einige Symbole der sekundren Gruppe kann auch ein Overlay spezifiziert werden. Hierbei wird das Symbol zusammen mit dem Overlay-Zeichen dargestellt, z.B. ein Autosymbol mit der Zahl 1. Um Overlays zu nutzen mssen sie ein Symbol der sekundren Gruppe whlen und das gewnschte berlagerungszeichen in das Feld Gruppe/Overlay eintragen. Nur Zahlen und Grobuchstaben sind als Overlay zulssig. Nach den APRS-Spezifikationen kann nicht jedes Symbol berlagert werden, aber Xastir erzwingt dies nicht, wie mglicherweise andere Programme. Beachten sie, da bisher auch nicht alle Symbole belegt sind und manche eventuell nicht ganz den APRS-Spezifikationen entsprechen. Tragen sie als nchstes die Daten fr Leistung, Hhe, Gewinn und Vorzugsrichtung fr ihre Station ein. Es ist eine sinnvolle Information wird aber nicht unbedingt bentigt. Whlen sie einfach "Kein PHG", wenn sie diese Daten nicht aussenden wollen. Diese Einstellungen geben eine grobe Vorstellung von der Reichweite ihrer Station. Whlen sie die Werte, die den ihren am nchsten kommen. Eine andere Mglichkeit wre es, stattdessen die Reichweite RNG in Meilen im Kommentar zu spezifizieren. Fr Details ziehen sie bitte die APRS-Spezifikationen zu Rate. Benutzen sie hier bitte die nicht die Hhe ber dem Boden oder Meereshhe, sondern die Hhe gegenber dem durchschnittlichen Gelnde. Die Angabe ist in Fu, Meter mssen mit 3,28 multipliziert werden. Als Gewinn tragen sie den Antennengewinn in dBi ein. Anmerkung: Die Angabe des Gewinns ist primr fr Vertikalantennen gedacht, fr Beams sollten kleinere Werte eingetragen werden. Die Grund hierfr ist, da bei gesetzter Vorzugsrichtung, die Ellipse fr die Reichweite nur um ein Drittel in die angegebene Richtung vergrert wird. Wird der Gewinn eines Beams grer angegeben, so wird nur die Reichweitenmarkierung unrealistisch gro, statt da die deren Richtwirkung erhht wrde. Bei der Angabe einer Vorzugsrichtung ihrer Antenne wren z.B. 90 eine Antenne, die nach Osten weist. Geben sie einen Kommentar ein, dies ist nicht notwendig, erlaubt aber die bermittlung sinnvoller Informationen, wie z.B. den Namen und die E-Mail-Adresse. Es wird zusammen mit den Positionsmeldungen bertragen. Die Positionsverschleierung erlaubt ihnen einszustellen, wie genau ihre Position bermittelt wird. Bei "Keine" werden die exakten eingetragenen oder vom GPS empfangenen Daten ausgesendet. Die anderen Mglichkeiten setzen die bermittelte Position irgendwo in den gewhlten Bereich. Einige Stationen, die nicht ganz den Spezifikationen entsprechen, verstehen jedoch keine Positionsverschleierung, so z.B. auch findu.com. Bei einem Klick auf OK werden die nderungen gesichert, bei Abbrechen bleiben die vorherigen Einstellungen erhalten. HELP-INDEX>Grundeinstellungen Grundeinstellungen Klicken sie auf Datei, Einstellungen, dann auf Grundeinstellungen Auf dieser Seite werden einige Standardwerte fr den Programmablauf eingestellt. Alte Stationen werden nach einiger Zeit schemenhaft dargestellt und die zugehrigen Spuren gestrichelt. In der ersten Zeile wird festgelegt, nach welcher Zeit eine Station nur noch schemenhaft angezeigt wird. In der nchsten Zeile wird festgelegt, nach welcher Zeit eine Station ganz vom Bildschirm verschwindet. Nach dem Doppelten dieser Zeit wird die Station dann auch aus den internen Datenbanken gelscht. Die dritte Zeile legt fest, in welchen Abstnden die eigene Position bermittelt wird. Fr Feststationen sind 30 Minuten ein guter Wert, es sollten auf alle Flle nicht unter 10 Minuten sein. Bei Mobilstationen kann ein krzeres Intervall sinnvoll sein. Diese Einstellung wird auch verwendet, um Objekte und Items wiederholt zu senden. Versuchen sie hier eine sinnvolle Einstellung zu finden, um nicht zu viel unntigen Verkehr zu produzieren. GPS Zeit legt das Zeitintervall fest, nach dem nach neuen GPS Daten geschaut wird. Diese Option ist fr Stationen mit gemeinsamen Zugriff auf TNC und GPS ber ein HSP-Kabel. Mit dem Sendeformat der Station wird festgelegt, welche Art von Paketen die Station sendet. IGate Options ermglicht die Errichtung einer Brcke zwischen Internet und Funk. Diese Option sollte mit Vorsicht benutzt werden. Als Fumkamateur sind sie selbst dafr verantwortlich, was aus dem Internet kommt und ber ihre Funkanlage ausgesendet wird. Sie mssen auerdem bei jeder Schnittstelle eine IGate-Einstellung machen, damit dies funktioniert. Wenn sie wollen, da ihr IGate NWS Wetterwarnungen ber Funk weitergibt, mssen sie eine Datei ~/.xastir/data/nws-stations.txt anlegen, in der alle Stationen aufgefhrt sind (wie z.B. "PHISVR"), deren Daten sie ber Funk weiterreichen wollen. Bei Aktivierung von "Sende komprimierte Position" wird die Position in einem neueren, komprimierten Format gesendet. Hierdurch werden die gesendeten Pakete krzer, so da die Kapazitt des APRS(tm) Netzwerks steigt. Die maximale Auflsung der gesendeten Position ist ebenfalls hher. Allerdings knnen einige ltere Programme, einschlielich krzlich erschienener Versionen von WinAPRS, dieses Format noch nicht dekodieren. Auch findu.com kann damit Probleme haben. Wenn "Sende Wetter Rohdaten" gewhlt wurde, werden auch Pakete gesendet, die unverarbeitete Wetterstationsdaten enthalten. Dies ist ntzlich fr Wetterstationen mit ASCII-Daten, wie Peet Bros. Wetterstationen. Sie knnen auerdem Alternatives Netz aktivieren, und dort ein eigenes Krzel eintragen. Alternatives Netz erlaubt ihnen damit, ein privates APRS-Netzwerk aufzubauen, mit Stationen, die ebenfalls Alternatives Netz aktiviert haben und das gleiche Rufzeichen benutzen. HELP-INDEX>Audio Alarm Audio Alarm Klicken sie auf Datei, Einstellungen, dann Audio Alarm. Um diese Option zu nutzen, bentigen sie eine Soundkarte und ein Programm, das Audiodateien im WAV-Format abspielt. Tragen sie als Kommando dieses Programm ein und eventuell bentigte Kommandozeilen- parameter. Das ganze funktioniert natrlich nicht, wenn die einzige Soundkarte im System fr ein Soundmodem benutzt wird... Fr verschiedene Ereignisse kann eine Datei eingetragen werden, z.B. eine wav-Datei, die abgespielt werden soll. Bei einigen Ereignissen knnen zustzliche Parameter gendert werden. Fr jedes Ereignis kann einzeln festgelegt werden, ob eine akustische Meldung erfolgen soll. Momentan steht zur Verfgung: Abspielen einer Ansage beim Auftauchen einer neuen Station Abspielen einer Ansage bei einer neuen Nachricht Abspielen einer Ansage, wenn Daten von einer Station empfangen werden, die sich innerhalb einer min/max Entfernung gem den Annherungs-Einstellungen befindet Abspielen einer Ansage, wenn Daten von einer Station ber TNC empfangen werden, die sich innerhalb einer min/max Entfernung gem den Bandffnungs-Einstellungen befindet Abspielen einer Ansage bei einer Wetterwarnung HELP-INDEX>Sprachausgabe Sprachausgabe Klicken sie auf Datei, Einstellungen, dann Sprachausgabe. Um diese Option zu nutzen, bentigen sie neben einer Soundkarte die 'Festival' Sprachsynthese Software. Installieren sie Festival und starten sie es als Server bevor sie Xastir aufrufen. Das Kommando hierfr heit blicherweise "festival --server &". Nachdem Festival installiert ist, kann Xastir fr folgende Flle eine Sprachausgabe vornehmen: o Ansagen des Rufzeichens einer neuen Station. o Ansagen, da eine neue Nachricht eingetroffen ist. o Den Text einer Nachricht vorlesen. o Eine Ansage, wenn Daten von einer Station empfangen wurden, die sich innerhalb einer min/max Entfernung gem den Annherungs-Einstellungen (siehe Audio Alarm) befindet. o Eine Ansage, wenn Daten von einer Station ber TNC empfangen werden, die sich innerhalb einer min/max Entfernung gem den Bandffnungs-Einstellungen (siehe Audio Alarm) befindet. o Die Ansage einer Wetterwarnung ist bisher noch nicht verfgbar. Informationen zu Festival erhalten sie ber: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Maeinheiten Maeinheiten Als Standardeinstellung wird das metrische System mit mm, cm, m, km, km/h, usw. verwendet. Wenn sie englische Maeinheiten bevorzugen, klicken sie auf Datei, Einstellungen und aktivieren sie Englische Mae, um Zoll, Fu, mph, usw. anzuzeigen. HELP-INDEX>Einstellungen sichern Einstellungen sichern ber Datei, Einstellungen, Einstellungen sichern knnen alle vorgenommenen Einstellungen sofort in der Konfigurationsdatei gespeichert werden. Aber auch beim Verlassen des Programms werden die Einstellungen gespeichert. HELP-INDEX>Statuszeile Statuszeile Am unteren Rand des Bildschirms werden verschiedene Statusmeldungen dargestellt: Im ersten Feld (links) werden allgemeine Statusmeldungen angezeigt, sie werden nach kurzer Zeit wieder gelscht. Das zweite Feld zeigt bei Mausbewegungen die aktuelle Position auf der Karte unter dem Mauszeiger an. Ein drittes Feld zeigt die Anzahl der insgesamt empfangenen Stationen in der Datenbank an. Das vierte Feld zeigt den aktuellen Zoomstatus an und ein "Tr", wenn eine Station verfolgt wird (Tracking). Das letzte Feld zeigt mit Symbolen den Status fr jedes Gert an, wobei die Schnittstellen von links nach rechts (0 bis 9) gezhlt werden. Der Status wird vertikal in drei Bereiche unterteilt. Oben Art des Gerts, in der Mitte der Datenflu und unten der Betriebszustand. Die Art des Gerts kann anhand der Farbe unterschieden werden. Blau steht fr die verschiedenen TNC Gerte, grn sind GPS-Empfnger, gelb Internet Server und orange Wetterstationen. In der Mitte zeigt ein links weisender Pfeil empfangene Daten an, ein rechtsweisender Pfeil steht fr ber dieses Gert gesendete Daten. Ein grnes Rechteck im unteren Bereich zeigt, da diese Schnittstelle aktiviert ist. Ein rotes Rechteck deutet auf eine aktive Schnittstelle hin, bei der aber ein Fehler aufgetreten ist. Anderenfalls wird nichts angezeigt, wenn die Schnittstelle nicht aktiv ist. HELP-INDEX>Verschieben der Karte und Mauszeiger-Menu Verschieben der Karte und Mauszeiger-Menu Das Verschieben der Karte ist sehr einfach, die Geschwindigkeit des Bildaufbaus hngt jedoch von der Rechnerleistung und dem Umfang der zu ladenden Kartendaten ab. Zoomen: Man kann in der Karte zoomen, indem man auf der Karte mit der rechten Maustaste klickt (und diese gedrckt hlt). Es erscheint ein PopUp-Menu, mit der Mglichkeit, hinein oder heraus zu zoomen, oder auf eine der vordefinierten Skalierungsfaktoren zu wechseln. Die Zoom-Funktionen zentrieren die Karte gleichzeitig an dem Punkt, an dem die rechte Maustaste gedrckt wurde. Bei "Zoomebenen" erhlt man ein Untermenu. Die Skalierungen 1-64 sind fr die nhere Umgebung, whrend 256 und hher grere Bereiche darstellen. Je kleiner die Zahl, umso lokaler wird der Kartenausschnitt. Ein schnelleres Hineinzoomen in einen Kartenausschnitt kann mit der Maus erreicht werden, wenn man auf mit der linken Maustaste auf eine Ecke des gewnschten Ausschnitts klickt, bei gedrckter Maustaste zur gegenberliegeden Ecke fhrt und dort die Taste loslt. Die Karte wird in der Mitte des gewhlten Ausschnitts neu zentriert, fr die Skalierung wird nur die Hhe des Ausschnitts verwendet, die Breite wird der Bildschirmgre entsprechend angepat. Die Schaltknpfe "Messen" und "Bewegen" drfen hierfr nicht aktiviert sein. Weiterhin besteht die Mglichkeit die PgUp und PgDn Tasten zum Zoomen zu verwenden. Hierbei bleibt das Zentrum er Karte erhalten. Verschieben/Zentrieren: Die Karte kann bei gleicher Auflsung neu zentriert werden, indem man mit der linken Maustaste auf das neue Zentrum klickt. Beim Klicken mit der mittleren Maustaste wird die Karte neu zentriert, auerdem wird die Auflsung durch Herauszoomen auf die Hlfte reduziert. Ein Verschieben kann ber das Mauszeiger-Menu oder durch die Pfeile am oberen Bildschirmrand erfolgen. Die Karte wird nur um einen Teil der Bildschirmgre verschoben, so da gengend Daten bestehen bleiben, um sich wieder zurechtzufinden. Auch die Cursortasten verschieben die Karte. Informationen zum Mauszeiger-Menu: "Stationsinfo" versucht zunchst die Station zu finden, die der Stelle, an der die rechte Maustaste gedrckt wurde, am nchsten liegt. Befinden sich dort mehrere Stationen, so kommt zunchst ein PopUp-Fenster mit einer Stationsliste, aus der man die gewnschte whlen kann. Danach, oder wenn nur eine Station direkt in unmittelbarer Nhe ist, ffnet ein Fenster mit verschiedenen Daten zu dieser Station. Bei Mobilstationen mit vielen Daten kann dies auf langsamen Computern etwas Zeit bentigen. Um alte Stationen zu sehen, kann vorbergehend "Alte Daten zeigen" im Menu "Ansicht" eingeschaltet werden. ber den Menupunkt "Letzte Ansicht" kann der vorherigen Kartenausschnitt wieder hergestellt werden. Fr Informationen zu Objekten siehe den Hilfetext "Objekte und Items" HELP-INDEX>Objekte und Items Objekte und Items Eine Station kann verschiedene Objekte auf der Karte setzen, deren Position auch ber Funk an andere Stationen weitergegeben wird. Bei den Namen fr Objekte bestehen nicht so viele Einschrnkungen wie fr die Stationsnamen. Objekte und Items sind ziemlich das gleiche, sie werden manchmal fr etwas unterschiedliche Zwecke angewandt. Objekte werden oft fr bewegliche oder vernderliche Dinge eingsetzt, wie z.B. Wirbelstrme, whrend Items im Allgemeinen fr unbewegliche Dinge, z.B. eine Wasserstation, eingesetzt werden. Da Items von einigen APRS-Programmen nicht dekodiert werden knnen, werden aber oftmals auch unbewegliche Objekte verwendet. ber das Mauszeiger-Menu hat man Zugriff zu "Objekt Neu" und "Objekt ndern. Mageblich fr das Objekt ist dabei die Position des Mauszeigers bei Aufruf des Mauszeiger-Menus. Neben normalen Objekten mit einem Symbol an der Position gibt es noch spezielle Objekte. Flchenobjekte sind geeignet, wenn es darum geht einen greren Bereich auf der Karte zu markieren. Man kann damit auch Wege, Straen oder Grenzen zeichnen, ein Suchgebiet abstecken, oder wenn es sein mu auch ein Schachbrett um ber APRS zu spielen :-) Beachten sie, da Flchenobjekte nicht in allen APRS-Programmen implementiert sind und wenn, dann auch teilweise unterschiedlich dargestellt werden. Die anderen beiden, Signpost und Peil-Objekte werden weiter unten beschrieben. Objekte werden in den gleichen Abstnden wie die eigenen Stationsdaten, die in "Datei-Einstellungen-Grundeinstellungen" festgelegt sind, wiederholt ausgesendet, insgesamt bis zum Doppelten der ebenfalls dort definierten Anzeigezeit fr Stationen. Auch gelschte Objekte werden wiederholt gesendet, bis sie in der Datenbank auslaufen. Bei "Objekt Neu" wird die Position, an der das Mauszeiger-Menu geffnet wurde, als Vorgabe fr ein neu zu erstellendes Objekt verwendet. Nach Eingabe eines Namens kann man ein anderes Symbol fr das Objekt whlen, einen Kommentar eintragen und es ber das Menu ein neues Objekt oder Item erstellen. Bei "Objekt ndern" erhlt man einen hnlichen Dialog, bei dem allerdings die Daten des Objekt an der Position des Mauszeigers bereits eingetragen sind. Einige Daten, wie z.B. der Objektname, knnen nicht gendert werden. Hierber ist auch das Lschen eines Objekts mglich. Objekte und Items knnen auch mit der Maus auf der Karte verschoben werden, wenn der Schaltknopf "Bewegen" auf der oberen Leiste aktiviert ist. Erluterung der einzelnen Eintrge im Objekt-Dialog: = Signpost-Objekt = Durch Aktivieren wird aus dem Objekt ein Signpost-Objekt, auf einem Hinweisschild knnen drei Zeichen dargestellt werden, die sichtbar werden, wenn an der betreffenden Position hineingezoomt wird. Hinweis: Das funktioniert SO noch nicht... = Flchenobjekt = Hierdurch wird das Objekt als ein Flchenobjekt definiert, zustzlich werden die unten erluterten Steuerfunktionen fr Flchenobjekte eingeschaltet. = Peil-Objekt = Hierbei handelt es sich um eine Peilmeldung, die mit dem DF-Symbol markiert wird. Sie knnen zwischen einer Meldung mit Rundstrahl- oder Richtantenne whlen und die spezifischen Daten eintragen. Nhere Details ber diese Techniken finden sich unter http://web.usna.navy.mil/~bruninga/dfing.html und in der APRSdos Dokumentation. = Name = Dies ist der Name des Objekts, der aus bis zu neun Zeichen bestehen kann, wobei auch Leerzeichen innerhalb des Namens zulssig sind. Beim ndern eines Objekts kann der Name nicht mehr gendert werden. Falls trotzdem erforderlich, mu das Objekt zunchst gelscht und dann mit neuem Namen neu erstellt werden. Wenn Sie das Objekt als Flchenobjekt, Signpost- oder Peil-Objekt definieren, wird der dann unntige Name gelscht. = Stations-Symbol = Whlen sie ein Symbol fr das Objekt, hierzu ist die Angabe der Gruppe und des eigentlichen Symbolzeichens erforderlich. Sie knnen dies manuell eintragen, oder nach Drcken auf "Auswahl" aus einer grafischen Symbolbersicht auswhlen. Es stehen zwei Gruppen von Symbolen zur Verfgung. Eine Beschreibung der Symbolbedeutung findet sich im Hilfetext "Symboltabelle". Bei Signpost-, Flchen- und Peil-Objekten lt sich das Symbol nicht ndern. = Position = Hier wird die Position des Objekts eingegeben. Wenn Sie ein neues Objekt erstellen, so wurde dort bereits die Position eingetragen, an der Sie mit der rechten Maustaste geklickt hatten, um das Mauszeiger-Menu aufzurufen. Wenn Sie das Objekt verschoben haben, so steht dort die neue Position. Sie knnen die Daten aber auch manuell eintragen, z.B. wenn Ihnen jemand eine Position ber Sprechfunk durchgegeben hat. = Allgemeine Optionen = Hier knnen Sie die Geschwindigkeit, die Bewegungsrichtung und die Hhe des Objekts eintragen. Bei einigen Objekten ist die Angabe von Geschwindigkeit und Richtung nicht mglich, die Felder sind dann in Grau dargestellt. = Signpost Text = Hier knnen Sie fr ein Signpost-Objekt den Text (ein bis drei Zeichen) angeben, der auf dem Hinweisschild erscheinen soll. Beachten Sie, da Xastir Signpost-Objekte momentan noch nicht richtig anzeigt. = Flchenobjekt = Flchenobjekte werden eingesetzt, um spezielle Teile einer Karte herauszuheben oder zustzliche Details zu zeichnen. Hierzu dienen die folgenden Eintrge: = Helle Farben = Wenn aktiviert, werden hellere, sonst dunklere Farben fr die Flchen verwendet. = Flchen fllen = Wenn markiert, werden die Flchen mit Objektfarbe gefllt, ansonsten wird nur die Umrandung dargestellt. = Objekt-Typ = Verschiedene geometrische Grundformen knnen hier gewhlt werden: Kreis/Ellipse, Linie nach rechts, Linie nach links, Dreieck, Rechteck = Objektfarbe = Hier wird die Farbe gewhlt in der das Objekt gezeichnet wird. Dies wird auch durch das Markieren von "Helle Farben" (siehe oben) beeinflut. Es stehen zur Verfgung: Schwarz, Blau, Grn, Cyan, Rot, Violett, Gelb, Grau = nach oben = Ausdehnung des Flchenobjekts nach oben in 1/100 Grad. = nach links = Ausdehnung des Flchenobjekts nach links in 1/100 Grad. = Korridor = Gibt die Breite eines Linienobjekts an und wird in Meilen spezifiziert. Denken Sie daran, Ihre Objekte zu lschen, wenn sie nicht mehr bentigt werden. Anderenfalls werden sie wiederholt gesendet und erscheinen auf dem Bildschirm anderer Stationen bis sie verfallen. HELP-INDEX>Listendarstellungen Listendarstellungen ber den Menupunkt "Zeige" knnen verschiedene Daten der Stationen meist in Form von Listen dargestellt werden. = Berichte = Berichte (bulletin boards) sind eine Mglichkeit, ber APRS Nachrichten und wichtige Ankndigungen an alle zu senden. Wenn Sie mit dem Internet verbunden sind, ist es sinnvoll, den Einzugsbereich auf wenige 100km einzustellen um so Berichte aus anderen Teilen der Welt zu ignorieren. Der Eintrag einer '0' im Feld Bereich bedeutet keinerlei Einschrnkungen, d.h. alle Berichte werden empfangen. Klicken Sie auf "neuen Bereich setzen" um den eingegebenen Wert zu bernehmen. Xastir untersttzt das Senden von Berichten momentan noch nicht. = Packet Radio = Hier werden die ber Packet Radio oder das Internet ankommenden Rohdaten dargestellt. Es kann gewhlt werden, ob nur Daten vom TNC, nur Daten aus dem Internet, oder beides angezeigt werden soll. = Mobilstationen = Dies ist eine Liste von Stationen, die sich bewegen, typischerweise also Mobilstationen. Die Bedeutung des Symbols wird dabei ignoriert, es wird nur festgestellt, ob sich die Station bewegt. Die angezeigte Information umfat neben der letzten bekannten Position auch Geschwindigkeit, Bewegungsrichtung, Hhe, Anzahl der empfangenen Pakete, Anzahl der sichtbaren Satelliten sowie Abstand und Richtung von unserer eigenen Station. = Alle Stationen = Hier wird eine Tabelle mit allen Stationen in alphabetischer Reihenfolge angezeigt. Es umfat auch die Anzahl der gehrten Pakete, die Zeit zu der die Station zuletzt gehrt wurde, den Pfad, den das letzte Paket genommen hatte, PHG und natrlich den Kommentar. = Lokale Stationen = Eine hnliche Tabelle wie zuvor, allerdings werden nur Stationen angezeigt, die ber den eigenen TNC gehrt wurden. = Letzte Stationen = Eine Liste mit allen Stationen in der Reihenfolge, in der sie gehrt wurden. Die zuletzt gehrten Stationen stehen oben am Beginn der Liste. Angezeigt wird wiederum die Anzahl der gehrten Pakete, die Zeit zu der die Station zuletzt gehrt wurde, den Pfad, den das letzte Paket genommen hatte, PHG und der Kommentar. = Wetterstationen = Diese Liste umfat nur APRS Wetterstationen mit deren Daten. Aufgefhrt werden Windgeschwindigkeit- und richtung, Geschwindigkeit von Ben, die Temperatur, die Luftfeuchtigkeit, den Druck, Regenmenge whrend der letzten Stunde, seit Mitternacht und whrend der letzten 24 Stunden. = Eigene Wetterdaten = Wenn eine eigene Wetterstation vorhanden ist und in Xastir konfiguriert wurde, so werden deren Wetterdaten hier angezeigt. = Wetterwarnung = Zeigt die empfangenen Wetterwarnungen des amerikanischen NWS an. = Nachrichten = Zeigt den Nachrichtenverkehr zwischen den verschiedenen Stationen solange das Fenster geffnet ist. Dies beinhaltet Quelle und Ziel, ber welche Schnittstelle sie lif und den Inhalt der Nachricht. ber "Bereich" kann die Anzeige auf Nachrichten von Stationen in der Umgebung beschrnkt werden, bei Eingabe von '0' werden alle Nachrichten angezeigt. = Laufzeit = Zeigt an, seit wie lange Xastir bereits luft. HELP-INDEX>Kartenauswahl und Einstellungen Kartenauswahl und Einstellungen = Kartenauswahl = Hiermit erhalten sie eine Liste aller Dateien im Kartenverzeichnis. Wenn sie einen Dateinamen markieren, so wird die Karte beim Klicken auf OK geladen und angezeigt, wenn sie in den aktuellen Bildauschnitt fllt. Sie knnen mehrere Karten gleichzeitig auswhlen. Abbruch verwirft die nderungen in der Kartenauswahl. Es gibt auch Buttons um alle Karten gleichzeitig abzuwhlen oder bestimmte Kartentypen zu laden. = Ausschnitte = Genaueres siehe im Hilfetext zu "Gespeicherte Kartenausschnitten" = Objekt in Karte suchen = Hiermit erhalten Sie einen Dialog zur Suche eines bestimmten Objekts in einer GNIS Datei. Falls gefunden wird die Karte an dieser Stelle neu zentriert. Die zuletzt befragte GNIS-Datei wird beim nchsten Aufruf wiederum als Vorgabe gewhlt. = Alle Karten verbergen = Hiermit kann das Laden aller Karten vorbergehend verhindert werden. Dies ist vor allem dann vorteilhaft, wenn man die Karte oft verschiebt oder zoomt und der langsame Kartenaufbau dazwischen strend wirkt. Bei einem Neustart von Xastir ist diese Option immer ausgeschaltet. = Automatische Karte (An/Aus) = Falls eingeschaltet, wird jede Karte im Kartenverzeichnis oder einem Unterverzeichnis geladen, die fr den aktuell dargestellten Ausschnitt gltig ist. Sie knnen beliebig viele Uterverzeichnis-Ebenen unterhalb des Kartenverzeichnisses anlegen, die automatisch durchsucht werden. Alle Karten werden im dargestellten Ausschnitt berlagert. Die Reihenfolge hngt von der alphabetischen Sortierung ab, gegebenenfalls kann man Links auf andere Namen anlegen, um die Sortierung flexibler handhaben zu knnen. Wenn sie viele oder komplexe Karten haben, oder einen langsamen Computer, dann kann das Laden der Karten sehr lange dauern. Wenn diese Option ausgeschaltet ist, werden die in der Kartenauswahl markierten Karten geladen. = Gitter (An/Aus) = Wenn eingeschaltet wird ein Kartengitter mit, je nach Zoomebene, 10 Grad bzw. 1 Grad Abstand gezeichnet. = Ebenen (An/Aus) = Falls eingeschaltet, werden Details bei der Darstellung herausgefiltert wenn grere Bereiche durch herauszoomen dargestellt werden. Dies funktioniert nicht mit allen Karten, es verringert auch nicht die Ladezeit, sondern sorgt nur dafr, da der Bildschirm lesbar bleibt. Ein Beispiel hierfr sind Karten die aus den Tiger Line Karten von aprs.rutgers.edu erzeugt wurden. = Kartenbeschriftungen = Hiermit knnen Kartenbeschriftungen ein- oder ausgeschaltet werden, die in Karten im dosAPRS, WinAPRS, GNIS und ESRI Shapefile Format enthalten sind. = Flchen einfrben (An/Aus) = Diese Option legt das Einfrben bei Vektorkarten fest. In manchen Fllen ist es sinnvoll, die Fllung zu entfernen, um darunterliegende weitere Karten sehen zu knnen. Die Karten werden in alphabetischer Reihenfolge geladen, so da ein Umbenennen oder ein Link eine weitere Mglichkeit in diesem Fall darstellt. = Wetterwarnung Counties = Bei Wetterwarnungen des amerikanischen NWS knnen einzelne Counties, fr die eine Wetterwarnung vorliegt, eingefrbt werden. Dies kann hiermit gesteuert werden. = Hintergrundfarbe (An/Aus) = Ermglicht die Auswahl der bei transparenten Karten durchscheinenden Hintergrundfarbe. = Intensitt = Hiermit kann die Farbsttigung der Karte gesteuert werden. Dieser Menupunkt erscheint nur, wenn Xastir mit GeoTIFF-Untersttzung und/oder ImageMagick zusammen kompiliert wurde. = Textdarstellung = Ermglicht die Auswahl zwischen zwei verschiedenen Arten der Schriftdarstellung fr Stationsinformationen auf der Karte. = Mauszeiger-Menu = ffnet das Mauszeiger-Menu, das sonst beim Klick mit der rechten Maustaste erscheint. Eine Anmerkung zu Karten: Viele der zur Zeit erhltlichen Vektorkarten fr die USA sind mit dem NAD-27 Datum erstellt worden, whrend Xastir und andere APRS Programme das aktuelle WGS-84 Datum verwenden. Wenn man sehr weit auf einen kleinen Kartenausschnitt herein zoomt werden die Abweichungen durch das falsche Kartendatum deutlich. Bei den USGS Topographischen Karten wird die Datumsabweichung von Xastir korrigiert, so da Positionen hiermit im Allgemeinen genauer sind als mit anderen topographischen Karten. HELP-INDEX>Kartendateien und County-Daten fr Wetterwarnungen Kartendateien und County-Daten fr Wetterwarnungen Kartentypen Xastir kann mit den verschiedensten Kartentypen arbeiten. Alle DosAPRS-, WinAPRS- und MacAPRS-Karten werden untersttzt. Zustzlich untersttzt Xastir von Haus aus Karten im PocketAPRS-Format, Bezeichnungen aus GNIS- Dateien (Geographic Names Information System) und Karten im XPixmap- Grafikformat. Xastir kann so kompiliert werden, da externe Bibliotheken eingebunden werden knnen, um topographische Karten im GeoTIFF-Format und ESRI Shapefiles zu untersttzen. Die Fhigkeit mit Karten in den verschiedensten Grafikformaten umzugehen kann durch das Kompilieren mit ImageMagick-Untersttzung stark erweitert werden (siehe "http://www.imagemagick.org/www/formats.html"). Xastir untersttzt die Darstellung von Bereichen von Wetterwarnungen auf Karten, hierzu knnen die Daten im klassischen dosAPRS/WinAPRS-Format vorliegen, die Einbindung im neuen ESRI Shapefile-Format wird in Krze vollstndig sein. Einen Hinweis auf die Quellen von verschiedenen Kartenformaten finden Sie in der Datei README.1ST. Karten-Verzeichnisse Alle Kartendateien sollten unter /usr/local/share/xastir/maps auf Ihrm Computer gespeichert werden. Zur besseren Organisation und Trennung der Karten knnen sie dort auch beliebige Unterverzeichnisse anlegen. Bei der Kartenauswahl werden die Karten mit ihrem ralativen Pfad alphabetisch sortiert angezeigt. Symbolische Links knnen helfen, um die Reihenfolge gegebenenfalls zu ndern. Hinweise zur Installation und Organisation der Karten finden sich ebenfalls in README.1ST. Fr Karten im Pixelgrafikformat werden immer zwei Dateien bentigt, zum einen die Grafikdatei im .xpm Format (oder andere Formate bei ImageMagick-Untersttzung) und eine Kalibrierungsdatei (.geo). Das Standardgrafikformat ohne zustzliche Bibliotheken ist .xpm, um Platz zu sparen knnen diese Dateien aber auch mit gzip gepackt werden ("gzip map.xpm" erzeugt die komprimierte Datei "map.xpm.gz"). Dies wird von Xastir automatisch erkannt und beim Laden der Karte bercksichtigt. Sie knnen XView, Gimp, ImageMagick oder andere Programme benutzen, um Grafiken zu konvertieren, die als gif, jpg oder tiff-Dateien vorliegen, wenn Sie nicht ImageMagick hinzukompilieren wollen. Sollten Sie Probleme mit Karten im .xpm-Format haben, versuchen Sie zunchst, die Grafik in Gimp zu laden und wieder abzuspeichern, hierdurch werden alle, evtl. unbekannten, Farbnamen in Binrdarstellung umgewandelt. Die .geo-Datei ist eine Textdatei, die Kartenposition in der Welt festlegt. Zur Erluterung hier die Datei world1.geo: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Dieses einfache Beispiel besteht aus vier grundlegenden Komponenten. Die erste Zeile (FILENAME) legt die Grafikdatei fest, die fr diese Karte benutzt werden soll. Bei einer komprimierten .xpm-Datei ist die Angabe der Endung ".gz" optional. Wenn kein Pfad angegeben wird, wird die Grafikdatei im gleichen Verzeichnis wie die .geo-Datei gesucht. Unter FILENAME kann auch eine URL angegeben werden, unter der Xastir die Kartengrafik mittels wget herunterladen kann. Dies bedeutet, da so ziemlich jedes Bild, da ber HTTP oder FTP im Internet verfgbar ist, als Karte dienen kann. Die zweite Zeile ist eine Kommenarzeile, dies wird durch ein '#' als erstes Zeichen einer Zeile festgelegt. Die letzten beiden Zeilen binden x-y-Positionen in der Grafikdatei an Koordinaten (Lngen- und Breitengrade) in der realen Welt. Zwei solche Punkte werden bentigt und sie sollten fr eine hohe Genauigkeit mglichst weit auseinander in den Ecken der Grafikdatei liegen, z.B. oben links und unten rechts. Um eine solche Karte zu verwenden, whlen Sie in der Kartenauswahl die zugehrige .geo-Datei. Die Gre der Grafikdatei kann optional ebenfalls in der .geo-Datei angegeben werden: FILENAME Agnes_Mountain.xpm.gz # # X Y Lon Lat # ---- ---- ------------- ----------- TIEPOINT 0 0 -121.00120491 48.37481943 TIEPOINT 1337 1999 -120.87619806 48.24982052 # IMAGESIZE 1338 2000 Mit IMAGESIZE wird die Bildgre in Pixel angegeben. Xastir benutzt diese Information, um Karten, die nicht in den aktuell dargestellten Ausschnitt fallen, mglichst schnell aussortieren zu knnen. Wird dies nicht angegeben, mu Xastir die Grafikdatei zum Berechnen auf alle Flle immer laden. Wenn Xastir mit Untersttzung von ImageMagick kompiliert wurde, so stehen auer .xpm smtliche Grafikformate zur Verfgung, die von ImageMagick selbst oder seinen Bibliotheken untersttzt werden. Es gibt verschiedene "spezielle" .geo-Dateien, die von Xastir verwendet werden knnen: o Eine Datei mit dem Wort "FINDU" und einer weiteren Zeile "CALL " ldt historische Spurdaten der mit dem Call spezifizierten Station. Dies ist allerdings inzwischen ber das Stationsmenu einfacher zu bewerkstelligen. geoTIFF Karten sind ebenfalls eine Kombination aus zwei Dateien, einer .tif und einer .fgd Datei. Die .tif-Datei enthlt die eigentlichen Kartendaten, die .fgd-Kalibrierungsdatei bentigt nur vier Eintrge wie im folgenden Fall, kann aber viele Andere Eintrge zustzlich enhalten: 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir benutzt diese vier Zeilen, um die Eckpunkte der Karte zu berechnen, und um festzustellen, ob die Karte in den gerade angezeigten Ausschnitt fllt. Wenn es sich bei Ihren Daten um topographische USGS-Karten handelt, sollten auch die .fgd-Dateien vorliegen. Xastir ist in der Lage das Datum von NAD27 in WGS84 umzurechnen, so da auch USGS-Karten unter Xastir eine hhere Genauigkeit erreichen. Wenn Sie keine .fgd-Datei haben, wird die Karte problemlos geladen, allerdings werden die weien Rnder am Kartenrand nicht beschnitten und die Karte knnte eine leicht falsche Gre und Rotation besitzen. Xastir kann nun USGS geoTIFF topographische Karten direkt von einer CD laden. Mounten Sie das CD-ROM manuell oder automatisch durch automounter, und achten Sie darauf, da ein symbolischer Link im Kartenverzeichnis auf das gemountete Laufwerk zeigt. Das war es! Auch Shapefiles sind eine Kombination aus mehreren Dateien, .shp, .dbf und .shx. Sie mssen nur die .shp-Datei auswhlen, um die Karte zu laden. Die anderen Dateien mssen jedoch vorhanden sein, um die Karte ordnungsgem laden zu knnen. GNIS (Geographic Names Information System) Daten bestehen aus einer Sammlung von Namen von Orten oder geographischen Objekten mit ihren jeweiligen Positionen. Diese Bezeichnungen werden wie die in Dos/WinAPRS Karten dargestellt. Je weiter man hineinzoomt, umso mehr detailiertere Bezeichnungen erscheinen, unter der Annahme, da eine GNIS-Datei als Karte gewhlt wurde und die Darstellung von Bezeichnungen im Kartenmenu eingeschaltet wurden. County Karten fr Wetterwarnungen Alle County-Karten sollten im Verzeichnis /usr/local/share/xastir/Counties gespeichert werden. Es gibt verschiedene Formate fr diese Karten, aber dieses Verzeichnis wird immer Unterverzeichnisse fr jeden Staat/Marine- Bereich haben (Abkrzung aus zwei Buchstaben). Das alte Format benutzt .map, whrend das neue Format Z.map benutzt. Die Installation wird ausfhrlicher in README.1ST im Abschnitt ber die Quelle von Karten beschrieben. Wenn eine NWS Nachricht empfangen wird, so werden die entsprechenden Bereiche eingefrbt, um den Bereich der Warnung zu kennzeichnen. Die verschiedenen Farben beschreiben dabei die Art der Warnung. Ursprnglich wurden folgende Farben verwendet: Cyan for advisory, yellow for watch, red for warning, orange for cancelled alert, royal blue for tests, and green for undetermined alert levels. Inzwischen knnen die Farben davon etwas abweichen, da die Flchen nun nicht mehr gefllt werden, sondern nur noch in der Farbe gendert werden, so da man die darunterliegende Karte noch erkennen kann. Die Darstellung von Wetterwarnungen kann im Kartenmenu ein- bzw. ausgeschaltet werden. HELP-INDEX>Ansicht Ansicht Die Optionen in diesem Menu erlauben ihnen festzulegen, welche Daten zu den Stationen auf der Karte angezeigt werden sollen. Es erlaubt Ihnen auch Stationen zu suchen und zu verfolgen, oder Stationen oder deren Spur zu lschen. = Station finden = Siehe hierzu unter "Stationen finden". = Verfolge Station = Siehe hierzu unter "Verfolgen von Stationen". = Spur von Findu holen = Ldt alte Spurdaten einer Station aus dem Internet von findu.com. Momentan werden die Daten der letzten beiden Wochen geladen. = Symbole = Hiermit kann festgelegt werden, ob Symbole auf der Karte gezeichnet werden sollen. Die meisten folgenden Optionen hngen hiervon ebenfalls ab. Bei alten Stationen wird das Symbol nur noch schememhaft in der Standardausrichtung gezeichnet, die zugehrige Spur wird gestrichelt und alle Daten auer dem Rufzeichen verschwinden vom Bildschirm. = Symbole drehen = Wenn eingeschaltet, werden einige Symbole auf der Karte gedreht, um so die Richtung, in die sich Mobilstationen bewegen, anzudeuten. = Rufzeichen = Zeigt das Rufzeichen der Station rechts vom Symbol an. = Geschwindigkeit = Zeigt die Geschwindigkeit einer Station in roter Schrift unterhalb von Rufzeichen und Richtung an, sofern eine Geschwindigkeit bermittelt wird. = - kurz = Wenn markiert wird die Geschwindigkeit in Kurzform ohne Einheit angezeigt. = Hhe = Zeigt die Hhe oberhalb des Rufzeichens in blauer Schrift an, sofern sie bermittelt wurde. = Kurs = Zeigt die Richtung, in die sich die Station bewegt, unterhalb des Rufzeichens in grner Schrift an, sofern die Station einen Kurs bermittelt. = Entfernung/Richtung = Ermglicht die Anzeige der Entfernung von der eigenen Station und der Richtung, in der sich die Station von der eigenen Station aus befindet. Diese beiden Werte werden links vom Symbol dargestellt. = Wetterdaten = Wenn eingeschaltet, werden bei Wetterstationen unterhalb des Symbols die letzten Wetterdaten aufgelistet (Temperatur, Wind- und Ben- geschwindigkeit, Windrichtung und Feuchtigkeit. = - nur Temperatur = Wenn markiert wird nur die Temperatur angezeigt. = Leistung/Gewinn = Wenn PHG-Daten bermittelt werden, wird ein Kreis um die Station gezeichnet, dessen Radius aus Leistung, Hhe und Antennengewinn berechnet wird. Wenn sich zwei Kreise berschneiden sind die Stationen theoretisch in Reichweite fr eine Simplexverbindung. In der Praxis is dies aber nur eine sehr grobe Nherung, vor allem in Gegenden mit sich nderndem Gelnde. = - mit Standardwert = Fr Stationen, die keine PHG-Daten bermitteln, wird stattdessen ein Standardwert gen den APRS-Spezifikationen verwendet. = - bei Mobilstationen = Hiermit knnen auch fr Mobilstationen Entfernungskreise gezeichnet werden. = Positionsverschleierung = Wenn eingeschaltet, wird die Flche markiert, in der sich eine Station mit Positionsverschleierung befinden kann. Die betreffende Station wird in der Mitte dieses Bereichs positioniert. = Alte Daten zeigen = Xastir zeigt Daten auch noch an, nachdem sie eigentlich bereits als alt deklariert wurden. Diese Zeiten knnen unter Datei-Einstellungen- Grundeinstellungen gemdert werden. = DF Kreise zeigen = Wenn eingeschaltet, werden auch alle Kreise fr Peilungen (Direction Finding) angezeigt. = Spuren = Wenn markiert, wird fr Mobilstationen eine farbige Spur mit den letzten maximal 100 Positionen gezeichnet. Jeder neuen Mobilstation wird hierzu eine neue Farbe aus einer Tabelle zugewiesen. = Stationen lschen = Dies lscht alle Stationsdaten auer den eigenen. Dies ist z.B. ntzlich, wenn der Speicher knapp bemessen ist. = Spuren Lschen = Lschen alle Spuren der Mobilstationen. Dies ist z.B. ntzlich, wenn der Speicher knapp bemessen ist. Die Spur einzelner Stationen kann auch ber das StationsInfo Menu gelscht werden. HELP-INDEX>Nachrichten Nachrichten = Schicke Nachricht an = Hiermit knnen Nachrichten mit einer einzelnen Station ausgetauscht werden. Dies ist auch ber das Menu StationsInfo mglich. = ffne Gruppen Nachricht= Dies funktioniert hnlich, nur da die Nachrichten an einen Gruppennamen geschickt werden. Die Gruppen werden in der Datei "groups" in ~/.xastir/config definiert. Gruppennachrichten sind noch nicht voll implementiert und einige Probleme mssen noch beseitigt werden. In Zukunft wird es auch mglich sein, Bulletins zu verschicken, dies ist aber momentan noch nicht implementiert. Im Nachrichtenfenster mu zunchst das Rufzeichen der Station eingetragen werden, der man eine Nachricht schicken will. Darunter kann man dann eine Zeile des Nachrichtentexts (max. 250 Zeichen) eingeben und mit "Sende jetzt!" abschicken. Bis zu einer Besttigung (ACK) durch die Gegenstation bleibt dieser Button inaktiv (grau). Es stehen maximal zehn Fenster fr Nachrichten an verschiedene Rufzeichen zur Verfgung. Beim Empfang einer an die eigene Station gerichteten Nachricht ffnet sich automatisch das Nachrichtenfenster, wobei das Rufzeichen des Absenders bereits eingetragen ist. Im groen Fenster sind oben die ausgehenden und unten die eingetroffenen Nachrichten sortiert nach ihrer Zeilennummer aufgelistet. Mit "Beenden" wird das Nachrichtenfenster verlassen. Mit "Neues Rufzeichen" kann man nachschauen, welche Nachrichten eine Station frher gesendet hatte. Sie knnen dies auch einsetzen, um mit einer anderen Station Nachrichten auszutauschen. Mit "Lsche Nachrichten" wird die angezeigte Liste mit Nachrichten gelscht. = Lsche alle ausgehenden Nachrichten = Hiermit werden alle noch nicht besttigten gesendeten Nachrichten gelscht. Anderenfalls wird mehrfach versucht, diese zuzustellen. = Stationen Allgemein = Dies sendet ein ?APRS? Paket, wodurch alle lokalen Stationen mit ihrer Position und/oder ihrem Status antworten sollten. Viele Programme ignorieren diese Anfrage, da eine Antwort zu einer Flut von Daten fhren kann. = IGate Stationen = Dies sendet ein ?IGATE? Paket, wodurch alle IGate-Stationen antworten und ihre Mglichkeiten mitteilen sollten. = Wetterstationen = Dies sendet ein ?WX? Paket, wodurch alle lokalen Wetterstationen ihre Position und die Wetterdaten senden sollten. = Setze automatische Antwort = Legt den Text fest, der als automatische Antwort gesendet wird. = Automatische Antwort = Hiermit kann ein vorbereiteter Standardtext bei jeder ankommenden Nachricht als Antwort versandt werden. HELP-INDEX>Schnittstellen Schnittstellen In diesem Menu knnen Einstellungen zu den vershiedenen Schnittstellen gemacht werden. = Schnittstellen Ein/Aus = Diese Option ffnet ein Fenster, in dem Sie alle Ihre konfigurierten Schnittstellen ein- oder ausschalten knnen. = Einstellungen = Eine Liste mit den installierten Schnittstellen erscheint und erlaubt Ihnen deren Einstellungen zu nden und weitere Schnittstellen hinzuzufgen bzw. vorhandene zu lschen. Nheres finden Sie unter "Schnittstellen Konfiguration" = Nicht senden: ALLES = Wenn markiert wird berhaupt NICHT gesendet. Fr diese und die folgenden beiden Optionen gilt, da es sich um globale Einstellungen handelt, die fr alle Schnittstellen gelten. Die meisten Schnittstellen bieten auch die Mglichkeit, das Senden ber diese spezielle Schnittstelle einzeln auszuschalten. = Nicht senden: Meine Position = Wenn markiert wird die eigene Position nicht gesendet. = Nicht senden: Objekte = Wenn markiert wird die eigenen Objekte nicht gesendet. = Sende jetzt! = Fhrt dazu, da alle eingeschalteten Schnittstellen ein Positions- Paket senden. Es ist nicht funktionsfhig (grau), wenn das Senden grundstzlich ausgeschaltet ist. HELP-INDEX>Stations-Info Stations-Info Das Fenster Stations-Info zeigt alle Daten an, die von Xastir fr diese Station dekodiert wurden. Es knnen die folgenden Informationen angezeigt werden: Die Anzahl der gehrten Pakete, die Uhrzeit, zu der die Station zuletzt gehrt wurde, ber welche Schnittstelle dies erfolgte, den Kommentar, PHG (aus Leistung, Hhe und Gewinn), Entfernung und Richtung von meiner Station, Wetterdaten und die letzte Position. Bei Stationen, die sich bewegen, folgt ein Tracklog mit den neuesten Daten ganz oben. Ein '+' vor einer Zeile markiert den Start eines neuen Tracks (wenn zuvor eine groe Zeit- bzw. Ortsdifferenz vorlag). Ein Stern am Ende einer Zeile weist darauf hin, da die Station an der jeweiligen Position auf direktem Weg gehrt werden konnte (ohne Digipeater). Nur fr die eigene Station gibt es ein Feld "Echo von", das die letzten sechs Digipeater auffhrt, die mein Paket als erste weitergegeben haben. Am unteren Rand des Fensters befinden sich zwei Reihen mit vier Aktions- feldern, deren Funktion abhngig von der Art der dargestellten Station ist. Fr Objekte/Items: Track speichern Objekt ndern --leer-- Schlieen ? Stationsversion ? Trace ? unbest. Nachrichten Stationsanfrage Fr andere Stationen: Track speichern Nachricht senden FCC/RAC Datenbank Schlieen ? Stationsversion ? Trace ? unbest. Nachrichten Stationsanfrage Bei sich bewegenden Stationen fehlt die Anfrage nach der Stationsversion, stattdessen findet sich dort "Spur lschen". Hiermit werden alle Bewegungsdaten dieser Station in der Datenbank und vom Bildschirm gelscht. Mit "Spur speichern" wird die Position und falls vorhanden, alle Bewegungsdaten in einer Datei auf der Festplatte gespeichert. Das derzeit benutzte Format ist dem hnlich, das bei GPS-Empfngern zum Einsatz kommt, die Spezifikationen knnten sich aber in zuknftigen Versionen noch ndern. Es gibt momentan keinen Weg, diese Daten wieder einzulesen, dies ist aber fr die Zukunft geplant. Das Ziel ist es auch GPS Tracklog-Dateien in hnlicher Art laden und darstellen zu knnen. Diese Tracklog-Dateien werden im Verzeichnis ~/.xastir/tracklogs abgelegt, der Dateiname besteht aus dem jeweiligen Rufzeichen mit der Erweiterung ".trk". "Objekt/Item ndern" ffnet das Fenster zum ndern von Objekten. "Sende Nachricht" ffnet fr diese Station ein Nachrichtenfenster und ermglicht an diese Station eine Nachricht zu senden. Wenn die FCC (U.S. Federal Communications Commission) oder RAC (Radio Amateurs of Canada) Datenbank installiert ist und das Rufzeichen aus dem US-amerikanischen bzw. kanadischen Kontingent stammt, so ist das "FCC/RAC Suche"-Feld vorhanden, sonst nicht. Die FCC- und RAC-Dateien sollten sich im Verzeichnis /usr/local/share/xastir/fcc befinden, wobei auf Gro-/Kleinschreibung zu achten ist. Wenn die Suche erfolgreich ist, wird Name und Adresse der Station im Stations-Info Fenster angezeigt. Anweisungen zur Installation dieser Datenbanken finden sich in der Datei README.1ST. Xastir erzeugt beim Start eine Indexdatei fr jede dieser Datenbanken. Wenn eine Rufzeichendatei aktualisiert wird, whrend Xastir luft, so wird der Index bei der nchsten Suche erstellt oder neu aufgebaut. Spezielle Prfixe werden NICHT bercksichtigt. HELP-INDEX>Erstellen von Protokolldateien Erstellen von Protokolldateien Xastir kann empfangene Daten in Protokolldateien schreiben, so da sie spter wieder eingespielt werden, oder zu Debuggingzwecken analysiert werden knnen. Alle diese Einstellungen werden im Menu "Datei" vorgenommen. = TNC protokollieren = Protokolliert alle Daten, die ber den TNC empfangen bzw. gesendet werden. Dieses Protokoll kann ber "Protokolldatei laden" zu einem spteren Zeitpunkt wieder eingelesen werden. = Netz protokollieren = Protokolliert alle Daten, die ber das Internet empfangen bzw. gesendet werden. Dieses Protokoll kann ber "Protokolldatei laden" zu einem spteren Zeitpunkt wieder eingelesen werden. Wenn Sie keine Schnittstelle gestartet haben und Ihre Position oder die eigenen Objekte lokal protokollieren wollen, ist dies die geeignete Methode. = IGate protokollieren = Protokolliert alle weitergereichten Daten in beide Richtungen, bei unterdrckten Weiterleitungen auch den Grund hierfr. Dies beinhaltet auch NWS Nachrichten, die in Richtung Funk weitergeleitet werden (gem ~/.xastir/data/nws-stations.txt: eine Textdatei, die alle Rufzeichen bzw. NWS Station wie z.B. "SECIND" angibt, deren Daten ber Funk weitergegeben werden sollen). = Wetter protokollieren = Protokolliert alle Wetterdaten, die von Ihrer Wetterstation empfangen werden. HELP-INDEX>Wiedergeben einer Protokolldatei Wiedergeben einer Protokolldatei Klicken sie auf Datei, dann auf "Protokolldatei laden". In einem Auswahlfenster knnen sie eine Datei auswhlen, deren Inhalt von Xastir geladen werden soll. Es mu sich dabei um eine Datei mit TNC Rohdaten handeln, wie sie auch von Xastir als Protokolldatei geschrieben werden kann. Die Station funktioniert dabei weiterhin wie gewohnt, die eingespielten Daten werden aber nicht wieder ausgesendet. Wenn sie Daten protokollieren, finden sie diese Dateien blicherweise in ~/.xastir/logs/ HELP-INDEX>Finden einer Station Finden einer Station Klicken sie auf Ansicht, dann auf "Station finden". Ein Fenster erscheint, in dem sie das Rufzeichen der zu suchenden Station eingeben knnen. In der Standardeinstellung wird nach bereinstimmung mit dem kompletten Rufzeichen (Exact Match) gesucht. Bei Objekten, die Kleinbuchstaben enthalten, mu "Match Case" gewhlt werden! Entgegen dem Namen wird ohne "Match Case" der Suchbegriff nur in Grobuchstaben umgesetzt... Mit "Finde jetzt!" wird der Suchvorgang gestarted und bei Erfolg der Bildausschnitt so justiert, da die Station mit einer bereinstimmung in der Mitte zu sehen ist. HELP-INDEX>Gespeicherte Kartenausschnitte Gespeicherte Kartenausschnitte Klicken sie auf Karten, dann auf "Ausschnitte" und sie erhalten ein PopUp-Fenster mit frher gespeicherten Kartenausschnitten. Beim ersten Aufruf wird diese Liste noch leer sein. Sie knnen den aktuellen Kartenausschnitt unter einem Namen speichern. Geben sie diesen Namen unter "Neuer Name" ein und whlen anschlieend "Hinzufgen". Nach Markieren eines Namens aus der Liste knnen sie den gespeicherten Kartenausschnitt durch "Aktivieren!" wieder herstellen. Durch Markieren und "Lschen" knnen Eintrge aus der Liste auch wieder entfernt werden. "Karte - Objekt in Karte suchen" ist eine weitere Mglichkeit, um einen Kartenausschnitt zu ndern, indem ein bestimmtes Objekt bei installierten GNIS-Dateien gesucht werden kann. HELP-INDEX>Verfolgen einer Station Verfolgen einer Station (Tracking) Klicken sie auf Ansicht, dann auf "Verfolge Station". Geben sie das Rufzeichen ein und drcken sie "Verfolge jetzt!". Die verfolgte Station bleibt nun immer auf dem Bildschirm sichtbar. Wenn die Station nahe an den Rand des Kartenausschnitts gelangt, wird die Karte nachgefhrt. Um das Tracking wieder aufzuheben klicken sie auf "Verfolgung aufheben". HELP-INDEX>Schnittstellen Konfiguration Schnittstellen Konfiguration Klicken sie auf Schnittstellen, dann auf Einstellungen Es erscheint ein Fenster "Installierte Schnittstellen", fr die verschiedenen Gerte, die sie mit Xastir zusammen benutzen wollen. Dort knnen sie Schnittstellen hinzufgen, lschen und deren Eigenschaften ndern. Durch Klick auf "Hinzufgen" knnen sie ein neues Gert anmelden, es erscheint ein Fenster zur Auswahl des Schnittstellentyps. Momentan sind verfgbar: Serieller TNC Serieller TNC plus GPS mit HSP-Kabel Serieller GPS-Empfnger Serielle Wetterstation Internet Server AX.25 TNC GPS ber Netzwerk (via gpsd) Wetterstation ber Netzwerk Markieren sie das gewnschte Gert aus der Liste und Klicken auf "Hinzufgen", es erscheint dann ein Fenster, indem sie die verschiedene Eigenschaften fr dieses Gert festlegen knnen. Tragen sie die bentigten Werte ein und besttigen sie mit OK. Ein Gert kann nach Markierung mit einem Klick auf "Lschen" wieder entfernt werden. Mit "Einstellungen" erhalten sie fr das markierte Gert aus der Schnittstellenliste ein Fenster, indem sie verschiedene Parameter ndern knnen. Weiterfrende Hilfe findet man in den Abschnitten fr die einzelnen Schnittstellentypen. HELP-INDEX>Serieller TNC Serieller TNC Dieser Abschnitt behandelt das Hinzufgen oder ndern von seriellen TNCs und seriellen TNCs mit einem GPS ber ein HSP-Kabel. Wenn sie ein HSP-Kabel besitzen, knnen sie diesen Eintrag auswhlen und dann sowohl den TNC als auch den GPS-Empfnger ber die gleiche serielle Schnittstelle anschlieen. Es handelt sich um ein spezielles Kabel, bei dem die Empfangsleitung durch den Computer zwischen den beiden Gerten umgeschaltet werden kann. Es arbeitet mglicherweise nicht mit allen mglichen Kombinationen von Computer, TNC und GPS. Der TNC und der GPS mssen auf die gleichen Kommunikationsparameter eingestellt werden, blicherweise also 4800 bps, 8 Datenbits, keine Paritt und 1 Stopbit. Optionen fr die TNC-Schnittstelle: Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten gesendet werden drfen. Als TNC Port wird das Unix Device eingetragen, mit dem der TNC (oder TNC und GPS) verbunden ist. Normalerweise geben sie hier /dev/ttyS0 (COM1), /dev/ttyS1 (COM2) etc. an. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr 8 Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Bei Verwendung des HSP-Kabels mssen diese Einstellungen fr TNC und GPS identisch sein. Mit den IGate Optionen knnen sie festlegen, in welche Richtung Internetverkehr ber diese Schnittstelle erfolgen kann. Dies kann fr jedes Gert getrennt eingestellt werden. Wenn sie kein IGate betreiben, lassen sie die Einstellungen auf "Disable". Tragen sie bis zu drei UNPROTO Pfade ein, Xastir gibt dabei das Zielrufzeichen vor. Falls mehrere Pfade (bis zu drei) eingetragen wurden, so verwendet Xastir diese abwechselnd bei jeder Aussendung, um so auch in schwierigen Situationen gehrt zu werden. Wenn sie nur lokalen Verkehr haben, so gengt ein einzelnes WIDE2-2. Bei wenig Leistung oder grerer Entfernung von einem Digipeater drfte "WIDE1-1,WIDE2-2" besser funktionieren. Wenn sie das Rufzeichen eines benachbarten Digis kennen, knnen sie auch alle Pakete ber diesen schicken, indem sie es an erster Stelle nennen, also z.B. "DB0XYZ,WIDE2-2". Fr die meisten Stationen wird ein Pfad gengen, in abgelegenen Gegenden oder unter schwierigen Bedingungen kann es sinnvoll sein, mehrere einzutragen. Am besten lt es sich mit rtlichen Funkamateuren abklren, welcher Pfad geeignet ist, um einerseits gut gehrt zu werden, andererseits aber die Frequenzen nicht unntig zu belasten. In Gegenden mit intelligenten Digis, die Wiederholungsschleifen weitgehend vermeiden, kann auch z.B. WIDE3-3 oder "WIDE1-1,WIDE3-3" verwendet werden. Die TNC Startup und Shutdown Dateien befinden sich im Verzeichnis /usr/local/share/xastir/config und werden beim Starten bzw. Stoppen der TNC-Verbindung zur Initialisierung ausgefhrt. Es handelt sich um normale Textdateien mit Kommandos, die an den TNC gesendet werden. HELP-INDEX>AX.25 TNC Schnittstellen AX.25 TNC Schnittstellen Als AX.25 TNC Device kann jedes Gert verwendet werden, da ber ein Linux AX.25 Treiber angesprochen werden kann. Hierbei handelt es sich um einen Kernel-Treiber, der z.B. auch das Baycom-Modem oder ein Packet Radio ber die Soundkarte untersttzt. Diese Gerte mssen vor dem Start von Xastir in Linux eingerichtet werden, bevor sie benutzt werden knnen. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten gesendet werden drfen. Mit den IGate Optionen knnen sie festlegen, in welche Richtung Internetverkehr ber diese Schnittstelle erfolgen kann. Dies kann fr jedes Gert getrennt eingestellt werden. Wenn sie kein IGate betreiben, lassen sie die Einstellungen auf "Disable". Geben sie den fr das AX.25-Gert festgelegten Device-Namen an, wie er in der Datei /etc/ax25/axports steht. Tragen sie bis zu drei UNPROTO Pfade ein, Xastir gibt dabei das Zielrufzeichen vor. Falls mehrere Pfade (bis zu drei) eingetragen wurden, so verwendet Xastir diese abwechselnd bei jeder Aussendung, um so auch in schwierigen Situationen gehrt zu werden. Wenn sie nur lokalen Verkehr haben, so gengt ein einzelnes WIDE2-2. Bei wenig Leistung oder grerer Entfernung von einem Digipeater drfte "WIDE1-1,WIDE2-2" besser funktionieren. Wenn sie das Rufzeichen eines benachbarten Digis kennen, knnen sie auch alle Pakete ber diesen schicken, indem sie es an erster Stelle nennen, also z.B. "DB0XYZ,WIDE2-2". Fr die meisten Stationen wird ein Pfad gengen, in abgelegenen Gegenden oder unter schwierigen Bedingungen kann es sinnvoll sein, mehrere einzutragen. Am besten lt es sich mit rtlichen Funkamateuren abklren, welcher Pfad geeignet ist, um einerseits gut gehrt zu werden, andererseits aber die Frequenzen nicht unntig zu belasten. In Gegenden mit intelligenten Digis, die Wiederholungsschleifen weitgehend vermeiden, kann auch z.B. WIDE3-3 oder "WIDE1-1,WIDE3-3" verwendet werden. Anmerkung: Um die AX.25 Treiber verwenden zu knnen, mu Xastir unter "root"-Rechten laufen. Um Xastir als normaler Benutzer zu starten, mu das suid Bit beim Xastir-Programm gesetzt werden. Hierzu dient das folgende Kommando (als root): "chmod a+s /usr/local/bin/xastir". Beachten sie bitte, da jedes Programm, das auf diese Weise luft, als Sicherheitsrisiko angesehen werden kann. Es wurde nicht besonders auf mgliche Sicherheitsrisiken hin getestet, benutzen sie es also in einer Mehrbenutzer-Umgebung mit Vorsicht und auf eigenes Riskio! HELP-INDEX>Serieller GPS Serieller GPS Setzen sie die serielle Schnittstelle fr den GPS Empfnger. Gngige Eintrge sind hier /dev/ttyS0 (COM1) oder /dev/ttyS1 (COM2). Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr acht Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Die Daten mssen mit denen des GPS-Empfngers bereinstimmen, die meisten Gerte verwenden im bentigten NMEA-Modus 4800 bps und 8N1. HELP-INDEX>GPS ber Netzwerk GPS ber Netzwerk Wenn sie die GPS-Daten fr verschiedene Programme bzw. Computer bentigen, ist diese Auswahl die geeignetste. Hierzu mu vorher der gpsd eingerichtet worden sein, von dem Xastir dann, neben anderen Programmen, die GPS-Daten beziehen kann. Tragen sie Namen (oder IP-Adresse) und Port-Nummer fr den gpsd Rechner in ihrem Netzwerk ein. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. HELP-INDEX>Internet Server Internet Server Internet Server erlauben ihnen Daten aus der ganzen Welt zu empfangen und lokale Daten ins Internet zu senden. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten ins Internet gesendet werden drfen. Tragen sie Namen (oder IP-Adresse) und Port-Nummer des Internet Servers ein, den sie ansprechen wollen. Geben sie einen gltigen Schlssel (Pass-Code) ein um Daten ber ein IGate senden zu knnen. Wenn sie keinen Schlssel passend zu ihrem Rufzeichen haben, knnen sie einen mit dem beigefgten Programm "callpass" erzeugen. Wenn es noch nicht bereits kompiliert wurde, geben hierzu sie im src Verzeicnis "make callpass" ein. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. HELP-INDEX>Serielle Wetterstation Serielle Wetterstation Tragen sie die serielle Schnittstelle fr die Wetterstation ein. Gngige Eintrge sind hier /dev/ttyS0 (COM1) oder /dev/ttyS1 (COM2). Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr acht Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Die Daten mssen mit denen ihrer Wetterstation bereinstimmen. Durch die Angabe der "Datenart" kann festgelegt werden, welche Daten das Programm ber die serielle Schnittstelle erwartet. Bei "Automatisch" wird zunchst nach Wetterdaten im Binrformat geschaut, wie es die Radio Shack WX-200 Wetterstation liefert. Falls keine Binrdaten im Datenstrom gefunden werden, versucht Xastir eine Wetterstation mit ASCII-Daten zu finden (wie Peet Bros.). HELP-INDEX>Wetterstation ber Netzwerk Wetterstation ber Netzwerk Xastir kann Wetterdaten Server wie den wx200d ansprechen. wx200d erlaubt mehrere Netzwerkverbindungen, so da Wetterdaten gleichzeitig verschiednen Programmen oder Computern zur Verfgung steht. Tragen sie Namen (oder IP-Adresse) und Port-Nummer des Wetterdaten Servers in ihrem Netzwerk ein. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. Wie im vorigen Abschnitt kann durch Angabe von "Datenart" die automatische Auswahl berschrieben werden. HELP-INDEX>Ausdrucken des Bildschirms Ausdrucken des Bildschirms Xastir kann den dargestellten Kartenausschnitt in Schwarz-Wei oder in Farbe ausdrucken. Hierbei wird das Bild zunchst als XPixmap-Datei gespeichert, dann werden externen Zusatzprogramme gestartet, um es ins PostScript-Format zu konvertieren, zu skalieren und rotieren, eine Vorschau zu ermglichen und es schlielich zu drucken. Hierfr mu Ihr System so eingerichtet sein, da Sie PostScript-Dateien drucken knnen, gewhnlich wird hierfr ghostscript, installierte Druckerfilter sowie ein lp oder lpr Druckerspooler bentigt. Fr die Erstellung der Ausdrucke mssen dann die folgenden Pakete installiert sein: ImageMagick (speziell "convert"), Ghostscript nebst Schriften, und "gv". Wenn diese Pakete funktionsfhig sind, so sollte kurz nach dem Druckbefehl in Xastir ein "gv"-Fenster aufgehen, in dem man das Druckbild zunchst begutachten kann. Falls das Ergebnis zufriedenstellend ist, kann es von gv aus ausgedruckt werden. Beachten Sie, da es in Abhngigkeit von den dargestellten Karten sinnvoll sein kann, den Kartenhintergrund auf weie Farbe zu ndern, hierdurch kann gegebenenfalls einiges an Tinte gespart werden. HELP-INDEX>Erstellen automatischer Schnappschsse Erstellen automatischer Schnappschsse Xastir hat die Fhigkeit, wiederholt automatische Schnappschsse des dargestellten Kartenausschnitts anzufertigen. Momentan erfolgt dies alle fnf Minuten. Unter der Voraussetzung, da "convert" aus dem ImageMagick- Paket installiert ist, erzeugt Xastir eine XPM-Datei in /var/tmp und konvertiert diese dann in die PNG-Datei /var/tmp/xastir_snap.png. Hiermit kann das aktuelle Geschehen z.B. auf einer regelmig aktualisierten Webpage dargestellt werden. Schnappschsse werden ber Datei - Schnappschsse eingeschaltet. HELP-INDEX>Symboltabelle Symboltabelle Dies sind die Definitionen der fr ihre Station oder fr Objekte whlbaren Symbole. Es stehen zwei Gruppen zur Verfgung, mit teilweise unterschiedlichen Symbolen bei gleichem Symbolbuchstaben. Die Grafiken aus der alternative Gruppe "\" werden auch herangezogen, wenn ein Overlay erfolgen soll. Hierzu wird als Gruppe ein Buchstabe [A-Z] oder eine Zahl [0-9] eingegeben, dies erscheint dann berlagert ber dem Symbol. Die aktuelle Liste findet man in der APRS Reference, die es bei http://www.tapr.org gibt. Symboltabelle Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>Was war neu in Xastir V1.0 Was war neu in Xastir V1.0 Whrend des vergangenen Jahres wurde Xastir weiterentwickelt und dieses Release ist das Ergebnis dieser Bemhungen. Die Entwicklung wurde von Chuck Byam geleitet, der das Projekt mit dem Einverstndnis von Frank Giannandrea bernommen hat. Viele andere haben zum Erfolg des Projects beigetragen, eine Auflistung findet sich in der Datei AUTHORS. Das Xastir Paket benutzt nun GNU autoconf um die Makefiles zu erstellen und verschiedene Eigenschaften aufgrund der installierten Bibliotheken und Software auszuwhlen. Beim Start von Xastir V1.0 werden sie womglich nicht sofort grere nderungen entdecken. Die bekannte Bedienoberflche wurde weitgehend beibehalten. Der grte Teil der nderungen bleibt im Verborgenen und dient einer Steigerungen der Effizienz: o Die Startzeit des Programms wurde verbessert o Der Speicherbedarf wurde durch dynamische Speicherzuweisung fr Stationen, Spuren und Wetterdaten stark verbessert. D.h. es wird kein Speicher mehr verschwendet fr nicht vorhandene Spurdaten bei festen Stationen oder Wetterdaten bei den meisten Stationen. Mit diesen nderungen ist es mglich, Xastir komfortabel mit dem Internet zu verbinden, auch wenn nur sehr wenig Speicher vorhanden ist. o Das Laden der Karten wurde verbessert, indem nun nicht mehr bei jeder kleinen nderung die Karte neu von der Festplatte geladen werden mu. Wetterwarnungen und nderungen an den Einstellungen fr die Darstellung und Tracking Optionen erfordern kein Neuladen der Karten, stattdessen werden nur die Symbole und die Spuren neu gezeichnet. o Verschiedene Dialog-Fenster, die frher hufig neu gezeichnet wurden, werden nun nur bei Bedarf aktualisiert und sind damit auch auf langsameren Systemen akzeptabel. Dies gilt auch fr das Verfolgen einer Station (Tracking), wobei die Karte nun nur neu gezeichnet wird, wenn die Station sich dem Rand des Bildschirms nhert. Dank dieser nderungen kann Xastir problemlos auch auf langsameren Pentium(tm) Rechnern eingesetzt werden. Untersttzung fr das GeoTIFF Kartenformat ist nun vorhanden und wird in Xastir einkompiliert, wenn die GeoTiff Bibliotheken auf dem System installiert sind. Diese Karten sind von hoher Qualitt und besonders fr Such- und Rettungsoperationen zu gebrauchen. Karten in diesem Format sind vom USGS und kommerziell auf CD-ROM erhltlich. Xastir wei, wie das Datum von NAD-27 in WGS-84 umzurechnen ist, so da Karten in beiden Formaten ohne Genauigkeitsverlust gelesen werden knnen. Zustzliche Tasten wurden in der Kartenauswahl hinzugefgt, um schnell alle Karten einer bestimmten Art auszuwhlen. Das oben gesagte gilt in erster Linie fr die USA, wo es jede Menge Karten gibt. Bei uns gibt es zwar schnere topgraphische Karten, dafr gibt es aber so gut wie nichts kostenlos, und damit auch kein verbreitetes Standardformat. Xastir untersttzt nun das Setzen und Lschen von Objekten. Objekte knnen verwendet werden, um Treffen anzuzeigen, Reisenden Hinweise zu geben oder Such- und Rettungseinstze durchzufhren. Die amerikanischen County Wetterwarnungs-Karten werden nicht mehr direkt auf die Karten gezeichnet, sondern mit der Karte berlagert. Einerseits sind die Farben dadurch verflscht, aber es ist nun mglich, die Straenkarten auch im Warnungsgebiet zu erkennen. Eine neue und ntzliche Eigenschaft ist, da sich die Ausrichtung einiger Symbole ndert, je nachdem in welche Richtung sich z.B. ein Fahrzeug bewegt. Auch ohne die zurckgelegte Spur kann man die Richtung einer Mobilstation mit einem Blick erfassen. Es gibt einige weitere Optionen im Menu Darstellung mit denen man genauer festlegen kann, was angezeigt werden soll und was nicht. Das Verschieben und die Kontrolle ber den Kartenausschnitt wurde verbessert: Es gibt nun Pfeile oben rechts im Menu, um die Karte mit der Maus zu verschieben. Die Karte kann auch mit den Cursortasten verschoben werden und die Vergrerung kann mit den PgUp und PgDn Tasten eingestellt werden. Im PopUp-Menu der linken Maustaste gibt es neue Optionen um die Karte an der aktuellen Position zu zentrieren oder dort ein Pbjekt zu platzieren. Die Verschiebemglichkeiten ber dieses Menu wurden zugunsten der oben genannten entfernt. Untersttzung fr Alternative Netzwerke wurde hinzugefgt, hiermit wird es mglich, ein privates APRS(tm) Netzwerk einzurichten fr Veranstaltungen, fr Such- und Rettungseinstze, Sturmjagd, oder fr alles wo der Benutzer nicht von Hunderten von APRS(tm)-Stationen um ihn herum genervt werden will. Es gibt viele kleine nderungen, sichtbar oder unsichtbar fr den Benutzer. Die Schnittstellen-Steuerung hat nun eine Option, um alle Schnittstellen gleichzeitig zu starten oder zu stoppen, um dem Benutzer es zu ersparen, dies fr jede Schnittstelle einzeln tun zu mssen. Die Stationseinstellungen zeigen nun das gewhlte Symbol, so da man das Fenster nicht mehr verlassen mu, um es zu sehen. Einige Pufferberlufe, die unvorhersagbares Verhalten oder Programmabstrze hervorgerufen hatten, wurden beseitigt. Und viele kleinere nderungen wurden am Quelltext vorgenommen, damit Xastir auf verschiedenen Systemen fehlerfrei bersetzt werden kann. Viel Freude mit dem neuen Xastir! Xastir-Release-2.2.2/help/help-Italian.dat000066400000000000000000001427751501463444000203170ustar00rootroot00000000000000HELP-INDEX>Leggimi - Licenza Leggimi - Licenza Per informazioni sulla versione corrente del programma leggere README.1ST nella cartella di Xastir. Questo programma sviluppato per essere usato all'interno della comunit radioamatoriale, negli Stati Uniti la FCC non autorizza a trasmettere per radio se non sei radioamatore. Gli utenti di altri paesi devono attenersi alle leggi locali in merito. LICENZA: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Questo programma un software libero; pu' essere ridistribuito e modificato secondo i termini della Licenza GNU GPL, pubblicata dalla Free Software Foundation; anche la versione 2 della licenza valida, come anche le versioni seguenti. ma SENZA ALCUNA GARANZIA; senza la garanzia di COMMERCIABILITA' o ADATTAMENTO PER UN PARTICOLARE USO. Vedere la Licenza GNU GPL per maggiori dettagli. Dovrebbe essere pervenuta a voi la licenza GNU assieme al programma; se cos non fosse segnalate l'evento alla Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Ulteriori informazioni sul software possono essere ottenute via: Web, http://www.xastir.org http://github.com/Xastir/Xastir Per maggiori informazioni riguardo la licenza pubblica GNU GPL: http://www.gnu.org HELP-INDEX>Benvenuti! e note dell'Autore Benvenuti! - note dell'autore XASTIR, o X-windows Amateur Station Tracking and Information Reporting. un programma APRS(tm) sviluppato liberamente e di libero uso, pu essere liberamente distribuito. Attualmente il programma in fase di sviluppo e non deve essere visto come un prodotto finito! Il tuo aiuto servir a renderlo migliore. Se sai programmare o vuoi scrivere documentazione, il tuo aiuto mi risulter molto gradito! Ho molte idee ma cos poco tempo! Quindi se pensi che manchi qualcosa, fammelo sapere. 73, Frank Giannandrea Traduzione della guida a cura di Alessandro Frigeri, IK0YUP. APRS[tm] un marchio registrato di Bob Bruninga, la sua pagina "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Avviare Xastir Avviare Xastir per la prima volta La prima volta che si lancia Xastir, dovrebbe essere fatto da un terminale in maniera tale che qualsiasi messaggio di errore salti alla vista. Nella maggior parte dei sistemi il percorso di ricerca dei file eseguibili comprende la cartella /usr/local/bin e tutto quello che serve per avviare il programma dare il comando xastir al prompt. Nei sistemi dove il percorso "/usr/local/bin" non impostato bisogner digitare "/usr/local/bin/xastir" per avviare il programma. Si pu anche impostare un linguaggio diverso dall'originale. Per impostare o cambiare il linguaggio usato da xastir bisogna utilizzare la seguente sintassi: xastir -l Attualmente le scelte sono: English Dutch French German Spanish Italian ElmerFudd MuppetsSwedishChef OldeEnglish PigLatin PirateEnglish Questa opzione viene memorizzata nel file di configurazione dell'utente e resa disponibile per i seguenti usi del programma. Per le nuove installazioni Xastir user l'inglese a meno che non venga specificato un linguaggio differente con l'opzione -l. NOTA: Nei menu, le opzioni in grigio sono quelle selezionate, come anche nelle opzioni di on/off, la scelta attivata sar evidenziata dalla colorazione grigia. HELP-INDEX>Informazioni sulla configurazione della stazione Informazioni sulla configurazione della stazione Seleziona Configura la Stazione Imposta il tuo nominativo nella apposita casella. Compila le caselle relative alla posizione (Lat,Long) se non si intende usare Xastir con un GPS. Se la posizione non disponibile possibile individuare la posizione sulla mappa e copiare i dati. Latitudine e longitudine potranno essere rilevati nella seconda casella partendo da destra, nella parte bassa della finestra principale. Se si intende utilizzare un GPS si pu saltare questa sezione e configurare il GPS in un secondo momento. Il simbolo o il gruppo della stazione possono essere cambiati in qualsiasi momento, per fare questo si faccia riferimento alla guida ai simboli. Indicare ora i dati tecnici della stazione: questi dati sono interessanti ma non necessari al corretto funzionamento del programma. Utilizzare il seguente codice per indicare la potenza che pi si avvicina a quella della vostra stazione: Codice 0 1 2 3 4 5 6 7 8 9 Potenza (watts) 0 1 4 9 16 25 36 49 64 81 Esempio: Se si sta trasmettendo con 36 watt, indicare "6". Lo stesso discorso vale per l'altezza, ma bisogna indicare l'altitudine e non l'altezza dell'antenna sul terreno. Codice 0 1 2 3 4 5 6 7 8 9 Altitudine (piedi)10 20 40 80 160 320 640 1280 2560 5120 Esempio: se l'altitudine della stazione 1280 piedi, il codice da usare sar "7". Per impostare il guadagno scrivere semplicemente il valore dello stesso espresso in dB, nella apposita casella. La direzione ha bisogno di un codice che esprime la direzione dell'antenna espressa in gradi dal Nord. Codice 0 1 2 3 4 5 6 7 8 9 Direzione(gradi) * 45 90 135 180 225 270 315 360 Nessuna Esempio: Se la vostra antenna omnidirezionale, impostare "0". Se la direzionalit verso nord, impostare "8". Inserire un commento, non necessario al programma, ma utile agli altri operatori. L'ambiguit della posizione permette di trasmettere quanto precisa la posizione fornita dalla nostra stazione. Una impostazione con ambiguit nulla permetter di comunicare alle altre stazioni esattamente la posizione che abbiamo impostato o che arriva dal GPS. Le altre scelte posizioneranno la stazione nel raggio indicato dal codice impostato. Selezionando OK, verranno applicati tutti i cambiamenti effettuati, mentre il tasto Annulla manterr le opzioni correnti. HELP-INDEX>Configurazione delle Unit di Misura Configurazione delle Unit di Misura L'impostazione originale del programma per il sistema metrico, mm, cm, Km/ora ecc. Per selezionare il sistema di misura anglosassone (pollici,piedi,miglia/ora) selezionare Configura, Unit, quindi il sistema che si vuole usare. L'opzione attiva quella marcata dal grigio. HELP-INDEX>Configurazione delle Operazioni Base Configurazione delle Operazioni Base Selezionare Configura e quindi Predefinito Questa scheda imposta una configurazione standard. Le vecchie stazioni saranno visualizzate con un'icona fantasma. Il "tempo lettura GPS" imposter l'intervallo di tempo per acquisire nuovi dati dal GPS. Questa opzione disponibile per le stazioni dotate di HSP o di un cavo condiviso con il proprio TNC. L'opzione "Trasmissioni Stazione" imposta con quali packet la stazione trasmetter i propri dati. L'opzione "Trasmetti codici WX", se selezionato, mander anche un pacchetto di dati provenienti dalla stazione meteo.Questa opzione utile per i tipi di stazioni meteo che trasmettono i dati gi in formato ASCII come le Peet Bros. Le opzioni Gateway permetteranno di impostare la stazione come un gateway tra internet e la rete radio. Questa opzione va usata con cautela, come radioamatore ognuno di noi responsabile per i dati che trasmette, e quindi anche per quelli che provengono da internet e vengono trasmessi per radio in una simile configurazione. HELP-INDEX>Configurazione Interfacce Configurazione Interfacce Selezionare Configura e quindi Interfacce. Dovrebbe apparire una scheda che indica le "Interfacce installate". Questa scheda vi permetter di aggiungere, cancellare, e modificare le propriet delle varie periferiche che possono essere utilizzate con Xastir. Le opzioni sono: TNC Seriale TNC Seriale con GPS tramite un cavo HSP GPS Seriale WX Seriale Server Internet TNC AX25 GPS in rete (via gpsd) WX in rete Per aggiungere una periferica, selezionare aggiungi. Apparir la scheda "Scegli il tipo di interfaccia". Seleziona il tipo di interfaccia che vuoi aggiungere. Appariranno i parametri di quella periferica. Fornire le impostazioni richieste e selezionare "ok" Per eliminare una periferica, selezionarla e in seguito cliccare sul bottone Elimina. Per modificare le propriet di una periferica, seleziona la periferica e quindi il bottone "Propriet". La scheda con i parametri della periferica appariranno e potranno essere modificati a piacere. Per rendere effettive le impostazioni schiacciare il bottone OK dopo aver fatto le modifiche. HELP-INDEX>Configurazione di TNC Seriali Configurazione di TNC Seriali CONFIGURAZIONE DI UN TNC SERIALE Questa sezione tratta l'impostazione di un TNC Seriale o di un TNC seriale con un cavo HSP per il collegamento del GPS. Se si ha il cavo HSP, che permette di condividere la porta del TNC con quella del GPS, la configurazione da selezionare sar "TNC con GPS". Il cavo HSP un cavo speciale che pu non essere compatibile con tutte le combinazioni computer/TNC/GPS possibili. Se si usa questa configurazione, il TNC e il GPS devono avere una impostazione dei parametri di comunicazione che in genere prevede: 4800 bps, 8 bit di dati, nessuna parit, 1 bit di stop. Opzioni della Porta TNC: Selezionando "Attivare all'avvio" si indica a Xastir di caricare questa periferica automaticamente all'avvio del programma. Selezionando "Permetti la Trasmissione", ordina a Xastir che ogni dato inviato all'interfaccia pu essere trasmesso. La porta del TNC la porta Unix alla quale collegato il TNC. In genere sono chiamate /dev/ttyS0 (Dos com1), /dev/ttyS1 (Dos com2) Ora impostare la velocit e il tipo di comunicazione in "Impostazioni porta", e i parametri in "Stile porta". Uno stile di porta 8N1 indica 8 bit di dati, Nessuna parit e 1 bit di stop. 7E1 indica 7 bit di dati, parit e 1 bit di stop. 7O1 indica 7 bit di dati, parit dispari, e 1 bit di stop. Questi parametri DEVONO essere comuni sia al TNC che al GPS. Scegliere ora la corretta impostazione per il Gateway di questa interfaccia. Potresti avere diversi TNC e questa opzione pu essere diversa per ogni TNC. Se non intendi attivare le funzionalit di gateway lascia l'opzione "Disabilitato". Inserisci ora fino a tre percorsi UNPROTO. Xastir assume la parte XX VIA del percorso UNPROTO. possibile impostare tre percorsi differenti in modo da avere alternative nel caso le condizioni non siano buone. Se uno dei percorsi occupato allora Xastir passer al successivo ad ogni trasmissione e cos via. Se sei in una condizione di stazioni locali, semplicemente un WIDE2-2 pu essere una buona scelta. Se stai usando poca potenza e/o sei distante dal digipeater allora WIDE1-1,WIDE2-2 potrebbe essere la scelta giusta. Se conosci il nominativo del tuo pi vicino digipeater allora si potr usare NOMINATIVO_DIGI,WIDE2-2. La maggior parte di voi avr bisogno di un solo percorso. Se ci si trova in un area remota e il segnale difficilmente ascoltabile dalle altre stazioni allora potrebbe essere necessario aggiungere dei percorsi. Una buona norma quella di chiedere al gruppo di radioamatori locali quale il miglio percorso per i pacchetti in quella data area. File di inizializzazione e di spegnimento del TNC. Questi campi specificano i nomi di file presenti nelle cartella /usr/local/share/xastir/config. Ognuno di questi file di test contiene i comandi che si vogliono mandare al TNC all'avvio del programma e al termine dello stesso. CONFIGURAZIONE DEL TNC AX.25 Questa sezione descrive l'aggiunta e la modifica di interfacce TNC AX.25. Per interfacce AX.25 si intendono tutte quelle periferiche che usano i driver AX.25 di Linux. Questo driver a livello di kernel e periferiche come i Baycom o soundmodem possono essere usati come TNC. Queste periferiche devono essere rese disponibili (funzionanti) al programma prima del suo avvio. Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Permetti la Trasmissione", si permetter che i dati vengano trasmessi per radio. Scegliere ora la corretta impostazione per il Gateway di questa interfaccia. Potresti avere diversi TNC AX.25 o TNC Seriali e questa opzione pu essere diversa per ogni TNC. Se non si intende attivare le funzionalit di gateway lascia l'opzione "Disabilitato". Impostare il nome della periferica AX.25 come specificato dal file axports. Inserisci ora fino a tre percorsi UNPROTO. Xastir assume la parte XX VIA del percorso UNPROTO. possibile impostare tre percorsi differenti in modo da avere alternative nel caso le condizioni non siano buone. Se uno dei percorsi occupato allora Xastir passer al successivo ad ogni trasmissione e cos via. Se sei in una condizione di stazioni locali, semplicemente un WIDE2-2 pu essere una buona scelta. Se stai usando poca potenza e/o sei distante dal digipeater allora WIDE1-1,WIDE2-2 potrebbe essere la scelta giusta. Se conosci il nominativo del tuo pi vicino digipeater allora si potr usare NOMINATIVO_DIGI,WIDE2-2. La maggior parte di voi avr bisogno di un solo percorso. Se ci si trova in un'area remota e il segnale difficilmente ascoltabile dalle altre stazioni allora potrebbe essere necessario aggiungere dei percorsi. Una buona norma quella di chiedere al gruppo di radioamatori locali quale il miglio percorso per i pacchetti in quella data area. NOTA: Per usare le periferiche AX.25 con Xastir bisogna avere i privilegi di root. Se si vuole far eseguire Xastir da un utente qualsiasi, bisogner cambiare il suid del programma Xastir. Il comando seguente eseguito da root potr servire allo scopo: chmod a+s /usr/local/bin/xastir Come qualsiasi programma che venga eseguito in questa modalit, questo da considerarsi un rischio di sicurezza, visto che il programma ancora non stato sperimentato per reagire a tentativi di intrusione. Configurazione del GPS Configurazione GPS Seriali Imposta la porta seriale che usata dal vostro GPS. Valori comuni sono /dev/ttyS0 (dos com1) e /dev/ttyS1 (dos com2). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Ora seleziona la velocit di trasmissione espressa in bps e i parametri della porta sotto il menu "stile". Uno stile di porta 8N1 significa 8 but di dati, nessuna parit e 1 bit di stop. 7E1 indica 7 bits di dati, parit pari e 1 stop bit. 701 indica 7 bit di dati, parit dispari e 1 stop bit. Questi parametri devono essere gli stessi che usa il GPS. La maggior parte dei GPS usa 4800 bps 8N1. HELP-INDEX>Configurare un GPS in rete Configurazione di un GPS in rete. Questa opzione permette di condividere i dati provenienti dal GPS con pi programmi, e con pi computer in rete. Xastir pu ottenere i dati dal GPS attraverso il demone gpsd che permette, attraverso diverse connessioni, di condividere i dati del GPS con altrettante applicazioni. Impostare il nome dell'host (o l'indirizzo IP) e il numero della porta che gpsd utilizza per le connessioni (di solito la 5678). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Riconnetti su Errore", indicher ad Xastir di riconnettersi una volta che il flusso di dati si per qualche motivo interrotto. HELP-INDEX>Configurare il Server Internet Configurazione del Server Internet I server internet permettono di ricevere ed inviare dati a tutto il mondo attraverso internet. Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Permetti la Trasmissione", indicher che Xastir potr trasmettere via radio tutti i dati. Inserisci il nome dell'host (o l'indirizzo IP) e il numero della porta del server internet che vuoi connettere. Inserisci un codice di accesso valido per attivare la connessione, che permetter ai tuoi dati di essere trasmessi attraverso Internet. Se non hai un codice di accesso puoi spedire un mail a fgiannan@earthlink.net con tutti i tuoi dati e informazioni radio, per ricevere il codice. Selezionare Riconnetti in caso di errore, che indica a Xastir di riconnettersi nel caso la comunicazione sia interrotta. HELP-INDEX>Configurare una Stazione Meteo Configurare una stazione meteo Configurare una stazione meteo Seriale. Impostare la porta seriale alla quale connessa l'unit Meteo. Valori comuni sono /dev/ttyS0 (COM1) o /dev/ttyS1 (COM2). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Ora bisogna selezionare la velocit della porta in bps sotto Configurazione della Porta, e i parametri sotto 'Stile di Porta'. Lo 'Stile della Porta' 8N1 indica 8 bit di dati, nessuna parit e 1 bit di stop. 7E1 indica 7 bit di dati, parit e 1 bit di stop. 7O1 usato per 7 bit di dati, parit, un bit di stop. Questi parametri devono essere gli stessi della porta dell'apparecchio meteo. L'opzione 'Tipi di dati permette di aggiornare per quale tipo di comunicazione seriale il programma dovr cercare. La funzione di autoriconoscimento (auto-detect) cercher per primi dei dati in formato binario come quelli della stazione meteo Radio Shack WX-200. Nel caso non vengano rilevati dati binari allora Xastir cercher per dati ASCII (utilizzati dalla stazione Peer Bros.). Configurare una stazione Meteo in Rete Xastir pu usare dati meteo reperendoli da server come il wx200d. wx200d permette pi connessioni, permettendo di condividere i dati meteo con pi programmi o computer. Inserisci il nome dell'host (o l'indirizzo IP) e il numero della porta del server Meteo che si vuole connettere . Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Riconnetti se sconnesso", indicher a Xastir di riconnettersi in caso di errore. Come prima, selezionando il "Tipo di dati" si escluder l'auto-riconoscimento. HELP-INDEX>Configurzione allarmi Audio Configurazione Suoni Selezionare Configurazione, e quindi Suoni. Per usare questa opzione bisogna avere una scheda sonora e un programma che esegua i file con estensione .wav. Il "Comando per eseguire i suoni" il programma (e relative opzioni) che si vuole usare per ascoltare i suoni che vengono da Xastir. I campi conterranno il nome del file da eseguire, i campi sotto le opzioni imposteranno i parametri per le opzioni. Le possibili scelte sono: -Esegui un suono quando viene rilevata una nuova stazione. -Esegui un suono quando viene ricevuto un nuovo messaggio. -Esegui un suono quando arrivano dati da una stazione ad una distanza Min/Max come segnalato dall'utente. -Esegui un suono quando viene rilevata una stazione (via TNC) con una distanza min/max impostata nei limiti di apertura di banda.. HELP-INDEX>Configurazione delle unit di misura (Inglese/Metrico) Configurazione delle unit di misura (Inglese/Metrico) Questo seleziona che in che unit le grandezze verranno visualizzate dal programma. Il programma si configura automaticamente sul sistema metrico ma possibile cambiare questa possibilit. HELP-INDEX>Barra di stato inferiore Barra di stato inferiore Nella parte inferiore della finestra principale sono disponibili diversi messaggi di controllo. I messaggi di controllo generale sono visualizzati nella paste sinistra. Nella seconda casella da sinistra visualizzata la posizione sulla mappa del mouse in lat/lon. La terza casella visualizza il numero di stazioni ricevute e presenti nel database. La quarta casella visualizza il livello di zoom e visualizzer Tr se sulla stazione selezionata attivata la funzione di inseguimento. L'ultima casella visualizza lo stato di funzionamento delle periferiche, che sono visualizzate nell'ordine di inserimento da 0 a 9. Il controllo di stato delle interfacce diviso in tre aree, la parte alta indica il tipo di periferica, in mezzo indicato lo stato di flusso di dati e nella parte bassa indicato lo stato operazionale della periferica, blu per i vari TNC, verde per i GPS, giallo per per i servizi Internet, arancio per le periferiche Meteo. Nella parte centrale il flusso di dati entrante indicato con una freccia a sinistra per dati uscenti e a destra per dati entranti. Nella parte inferiore il verde indica che l'interfaccia collegata e funziona correttamente, il rosso che l'interfaccia collegata ma in uno stato di errore, l'assenza di colore indica che l'interfaccia non collegata. HELP-INDEX>Spostare la mappa e opzioni. Spostare la mappa e Opzioni Il movimento della mappa molto semplice e la velocit di visualizzazione della stessa dipendente dal tipo di sistema in uso e dalla quantit di dettagli visualizzata. Tutti i movimenti e ingrandimenti sono possibili cliccando il tasto sinistro del mouse (tenendolo premuto) sulla mappa. Questa azione visualizzer un menu di Opzioni. Tutte le funzioni di Zoom sono riferite al punto della mappa dove stato cliccato il bottone sinistro del mouse. Il menu degli zoom mostrer ulteriori opzioni: livelli di zoom da 1 a 3 sono per aree locali mentre livelli da 4 a 6 sono per aree maggiori, quindi pi il numero piccolo e pi l'area visualizzata stretta. Dal menu delle opzioni si pu anche spostare la vista della mappa con la funzione Pan, che provocher uno spostamento del centro della mappa. Le "informazioni della stazione" cerca per la stazione pi vicina al punto selezionato dal click del mouse. Se pi stazioni sono presenti apparir una finestra di selezione che permetter di indicare di quale stazione veramente si ha bisogno di informazioni. HELP-INDEX>Map Options and Map Chooser Opzioni della Mappa e Scelta della Mappa Opzioni della Mappa e Scelta della mappa Opzioni della Mappa: Mappe Automatiche (Attiva/Disattiva) Quando attivato, qualsiasi mappa trovata nella directory delle mappe verr visualizzata se nella sua area ricade la visualizzazione corrente. Questa funzione cercher in tutte le sottocartelle della directory delle mappe. Se pi mappe sono disponibili allora verranno sovrapposte, in questo caso un computer poco veloce pu produrre una visualizzazione lenta. Tuttavia possibile disattivare questa funzione e selezionare manualmente la mappa da visualizzare. Griglia (Attiva/Disattiva) Quando attiva, questa funzione visualizza una griglia ogni 10 gradi. Se si effettua uno zoom in avanti la risoluzione della griglia passer ad 1 grado. Livelli della Mappa (Attiva/Disattiva) Quando attivata, questa funzione permette di filtrare i dati di mappe su grandi aree. Questa opzione funziona solo con le mappe Tiger Line maps reperibili presso http://aprs.rutgers.edu. Ci non velocizzer il caricamento delle mappe ma produrr una visualizzazione di dettagli appropriata alla scala di visualizzazione. Colore in Aree Chiuse (Attiva/Disattiva) Questa opzione controlla il colore di riempimento delle mappe vettoriali. In alcuni casi pu essere necessario eliminare il riempimento di un'area per permettere la visualizzazione dei livelli sottostanti. Le mappe sono caricate in ordine alfabetico e quindi i livelli rispetteranno tale ordine. Scelta della mappa. Questa funzione visualizza tutte le mappe disponibili. Si potr selezionare pi di una mappa e poi premere OK per confermare la selezione. Il bottone Cancella chiude la finestra di dialogo della scelta delle mappe. Nota: Xastir utilizza il Datum WGS 1984 per le mappe. HELP-INDEX>File di mappe, Dos, Windows, Pixmaps e WX Counties File di mappe, Dos, Windows, Pixmaps e WX Counties Tipi di Mappa Xastir funziona con vari tipi di mappa. Tutte le mappe per il programma APRS[TM] Dos,Windows,Mac sono supportate. Dalla versione 0.3.2 possibile caricare anche mappe in formato Pixmap. possibile anche caricare le mappe di supporto per gli Allarmi Meteo Statunitensi. Dove posizionare le mappe Qualsiasi mappa Dos, Windows/Mac o Pixmap deve essere messa nella directory /usr/local/share/xastir/maps. Si possono creare sottocartelle per oridare il contenuto. Per esempio si pu creare una cartella ITALIA per mettere tutte le mappe che comprendono il territorio italiano, oppure si possono dividere le mappe per tipo: Pixmap e Dos. Esempio /usr/local/share/xastir/maps/ /italia/nord /italia/centro /italia/sud /dos/italia/ /dos/germania/ /pixmaps/italia/ /pixmaps/germania/ Le mappe Pixmap sono una combinazione di due file, un file binario grafico pixmap (.xpm) e un file di dati di locazione (.geo). Il file .xpm grafico in formato .xpm standard modificabile con qualsiasi programma di grafica che supporti questo formato. Il file di dati .geo permette di posizionare la mappa nel mondo. Ecco un esempio di file .geo: world1.geo FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Questo semplice file ha 4 componenti. La prima riga indica il file grafico a cui sono riferiti i dati che deve essere nella stessa directory del file di dati. La seconda linea imposta un commento alla mappa. Ogni linea che inizia con un # (cancelletto) indica un commento che non verr letto dal programma. Le ultime due linee connettono un pixel di coordinate x,y ad un punto della terra con coordinate lat/long. Due punti sono necessari e dovrebbero essere presi in alto a sinistra e in basso a destra dell'immagine. Per usare la mappa Pixmap, selezionare la scelta di mappa e in seguito il file .geo Mappe di Allerta Meteo USA Tutte le mappe di Allerta meteo USA dovrebbero essere posizionate in /usr/local/share/xastir/Counties. Dovranno poi essere create delle sottocartelle per lo stato USA a cui appartiene la mappa chiamate con l'abbreviazione di due lettere dello stato. /usr/local/share/xastir/Counties /CO/ /CO/COPARK.map /CO/CODOUGLA.map /CO/COJEFFER.map /CO/COZ001.map /CO/COZ002.map /CO/COZ003.map /NJ/ /NJ/NJOCEAN.map /NJ/NJBERGEN.map /NJ/NJMONMOU.map /NJ/NJZ001.map /NJ/NJZ002.map /NJ/NJZ003.map Ecco due siti dove possibile avere questo tipo di mappe: ftp://aprs.rutgers.edu/pub/hamradio/APRS/NWSCounties/ http://home.att.net/~kg5qd1/Maps.html HELP-INDEX>Informazioni stazione - Ricerca nel database FCC e RAC Informazioni stazione - Ricerca nel database FCC e RAC Informazioni Stazione mostrer tutti i dati acquisiti da Xastir per quel determinato nominativo. Il bottone Annulla Inseguimento toglier tutti i percorsi che sono stati memorizzati nello schermo. Il bottone Spedisci Messaggio aprir una finestra per spedire un messaggio. Se si installato il database FCC o RAC si pu fare una ricerca dei dati della stazione. I file di databse RAC e FCC devono essere posizionati in /usr/local/share/xastir/fcc. Questa funzione aggiunger l'indirizzo della stazione alle informazioni ricevute via radio. Per usare il database FCC bisogna scaricarlo (40Mb) da: ftp://ftp.fcc.gov/pub/XFS_AlphaTest/amateur/appl.zip o la nuova versione da: ftp://ftp.fcc.gov/pub/Bureaus/Wireless/Databases/uls/complete/l_amat.zip (The only file needed form this 40Meg zip is the EN.dat file) **** NOTA: per usare la nuova versione, il database deve essere prima ordinato!!! **** Assicurarsi di avere spazio disco libero (100Mb) Per ordinare il file eseguire i seguenti comandi: sort +4 -t \| EN.dat >EN.dat.sorted rm EN.dat mv EN.dat.sorted EN.dat Il database RAC si pu scaricare da: ftp://ftp.rac.ca/pub/cdncaldb.zip Xastir creer degli indici per ogni database, se un nuovo callsign immesso nel database allora Xastir creer dei nuovi indici e render subito disponibile il nuovo callsign. I prefissi speciali NON sono inclusi nei database. HELP-INDEX>Opzioni di Visualizzazione Opzioni di visualizzazione Queste opzioni permettono di visualizzare i dati delle stazioni attorno all'icona che indica la posizione della stazione sulla mappa. Altitudine (on/off) Quando attivo, una linea blu di dati appare sopra al nominativo, ad indicare l'altitudine della stazione nell'ultima posizione ricevuta. Direzione (on/off) Quando attivo, una linea verde di dati apparir sotto al nominativo. Questa indica la direzione in gradi del movimento della stazione l'ultima volta che stata ascoltata. Velocit Speed (on/off) Quando attiva, una linea di dati rossi indica la velocit della stazione l'ultima volta che stata ricevuta. Distanza/direzione (on/off) Quando attivata, due linee di dati verranno visualizzate alla sinistra dell'icona della stazione. La linea superiore indica la distanza dalla propria stazione, mentre la linea inferiore la direzione dalla propria stazione. Tracce della Stazione (on/off) Quando attiva, qualsiasi stazione in movimento lascer una traccia della posizione precedente fino ad un numero di 100 posizioni. Quando i dati della stazione diventano vecchi e l'icona della stazione diventa trasparente, la traccia indicata con un tratteggio. Potenza/Guadagno (on/off) Quando attiva, visualizza i cerchi di potenza e guadagno. Insegui stazione Questa funzione visualizza una finestra di dialogo simile a quella di localizzazione. Si pu inserire un nominativo o parte di esso e quindi selezionare "Insegui ora!" per centrare lo schermo su quella stazione e mantenerlo centrato per ogni successivo spostamento. Selezionando "Elimina Inseguimento" si eliminer la funzione. Il bottone "Annulla" nasconder la finestra senza apportare cambiamenti. Informazioni Meteo (on/off) Quando selezionato, verranno visualizzate le ultime informazioni meteo (temperature,velocit del vento/direzione/gust,umidit). HELP-INDEX>Messaggi Messaggi Spedire Messaggi e Apri Gruppo Queste funzioni sono molto simili. "Spedisci messaggio a" spedir un messaggio solo ad una stazione. I messaggi di gruppo sono pi generali. (ndt: la funzione messaggi di gruppo al momento non completamente funzionante) Ognuna di queste finestre visualizza una scheda di messaggio, una linea per il nominativo/nome gruppo e vari bottoni. Una volta inserito il nominativo della stazione, tutti i messaggi ricevuti da essa verranno visualizzati. Se non ci sono messaggi allora una nuova finestra permetter di inserire un nuovo messaggi da spedire. La lunghezza massima del messaggio di 250 caratteri. "Spedisci ora!" invier il messaggio al destinatario. Il bottone "Spedisci ora!" rimarr grigio fino a quando il messaggio non sar correttamente inviato. Qualsiasi messaggio ricevuto sar ordinato secondo la linea # e messo nella finestra dei messaggi. Se si nella funzione Gruppo, la lista dei messaggi visualizzer anche il nominativo del mittente. "Nuovo nominativo" visualizzer i vecchi messaggi della stazione oppure permetter la comunicazione con un'altra stazione. Il bottone "Cancella Messaggi" eliminer tutti i messaggi. Elimina i messaggi in uscita. Questo eliminer tutti i messaggi che sono stati spediti. Risposta automatica Questa funzione attiva la risposta automatica ai messaggi in entrata. Imposta risposta automatica Render possibile impostare il messaggio di risposta automatico. HELP-INDEX>Eliminare i percorsi dallo schermo Eliminare i percorsi dallo schermo Selezionare File e quindi "Elimina Percorsi" per eliminare tutti i percorsi delle dallo schermo e dal database interno. HELP-INDEX>Ripulire lo schermo dai simboli di stazioni Ripulire lo schermo dai simboli di stazioni Selezionare File e quindi "Elimina tutte le Stazioni". Questo eliminer tutti dati delle stazioni ricevute fino a quel momento eccetto la vostra. HELP-INDEX>Rispondere ad un log Rispondere ad un log Selezionare "Apri file log" e selezionare un file di log creato dal TNC o dalla rete con la funzione sotto le opzioni di rete. La stazione user il file di log come se fosse direttamente connessa al TNC. HELP-INDEX>Localizzare una Stazione Localizzare una Stazione Selezionare Vista e quindi "Localizza Stazione" per fare apparire una finestra di dialogo che permette di inserire un nominativo (completo, non case sensitive). Se si vuole cercare un nominativo parziale allora bisogna deselezionare "Nome esatto". Selezionando "Maius/Minus Esatti" verranno osservati anche i criteri di Maiuscole/minuscole. Selezionando "Localizza Ora!" il Display verr centrato sulla stazione cercata al livello di zoom corrente. "Annulla" chiuder la finestra di dialogo. HELP-INDEX>Creare ed usare i Salti alla Stazione Creare ed usare i Salti alla Stazione Selezionare Visualizza e quindi "Vai alla Stazione" per visualizzare una finestra di dialogo. La prima volta che si usa questa funzione la finestra di dialogo sar vuota. Si pu creare una nuova vista selezionando "Nuova posizione", inserire il nome e quindi Aggiungi. Per usare le posizioni registrate baster selezionare la posizione e quindi il tasto "Vai!" per centrare la posizione registrata. E' possibile eliminare una posizione selezionandola e selezionando "Elimina". HELP-INDEX>Inseguimento di una stazione Inseguimento di una stazione Selezionare Visualizza e quindi Insegui stazione. Inserire il nominativo da inseguire (tutto o parte di esso) e quindi selezionare "Insegui Ora!". Appena la stazione si muove, essa viene centrata nello schermo. Per disattivare questa funzione bisogna selezionare "Annulla Inseguimento". HELP-INDEX>Tabella dei simboli Tabella dei Simboli Simbolo Gruppo / Gruppo \ ! Triangolo w/! Triangolo w/! " Nuvola Nera Nuvola da Pioggia # Digi DIGI $ Telefono Simbolo $ % DX DX & GATEWAY-HF GATE ' Piccolo Aereo Incidente Aereo ( Nuvola Nuvola ) TBD * Fiocco di neve Fiocco di neve + Croce rossa , L inversa - Casa con antenna Omnidirezionale . Piccola x / Punto rosso 0 0 in un quadrato Cerchio 1 1 in un quadrato 2 2 in un quadrato 3 3 in un quadrato 4 4 in un quadrato 5 5 in un quadrato 6 6 in un quadrato 7 7 in un quadrato 8 8 in un quadrato 9 9 in un quadrato GAS : Fuoco ? ; Tenda Tenda < Motocicletta Banderuola = Locomotiva > Auto Auto ? POS Antenna ? in un quadrato @ URAGANO/TEMPESTA URAGANO/TEMPESTA A Pronto Soccorso Quadrato B BBS Neve a vento C Canoa D D in un cerchio E E in un cerchio Fumogeno F F in un cerchio G Antenna Grid Square ? H Hotel/Letto I TCP/IP ? J J in un cerchio Fulmine K Scuola Casa L Faro Faro M Mac N NTS ? O Pallone Aerostatico P Auto Polizia Rx Q Cerchio con Cerchietti Cerchio con Cerchietti R RV Ristorante S Shuttle Satellite T Temporale (cloud/bolt) Temporale (cloud/bolt) U Scuolabus Sole V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Elicottero Y Barca a vela Z Windows [ Corridore Bagno \ Triangolo DF ] Packet Mail Box ^ Grande Aereo Grande Aereo _ Stazione meteo WS-Digi ` Antenna parabolica a Ambulanza b Bicicletta Nuvola a vento c antenna DX d Caserma Pompieri Antenna DX e Cavallo Nuvola a Cirro f Mezzo Pompieri FC Cloud g aliante Banderuola (2) h Ospedale HAM i Isola Isola j Jeep Jeep k Camion Camion l Puntino Puntino m MIC Pietra Miliare n N Small Triangle o EOC Punto con cerchietti p Cagnolino Punto con cerchietti q GS Antenna GS Antenna r Traliccio Antenna Traliccio s Nave Nave t TS ? u 18 Wheel Truck v Van Punto con cerchietti w H20 Inondazione x X Windows Punto Rosso y House w/Yagi Casa con Yagi z X Windows { NEBBIA NEBBIA | Linea Nera Linea Nera } TCP TCP ~ Barca a vela Barca a vela Xastir-Release-2.2.2/help/help-Portuguese.dat000066400000000000000000004242041501463444000210660ustar00rootroot00000000000000HELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: http://www.xastir.org http://github.com/Xastir/Xastir There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See http://www.xastir.org to subscribe. For more information on the GNU License look at: http://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X-windows Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html". A great deal of information on APRS(tm) can be found in the APRSdos documentation written by Bob Bruninga. An additional source of information is the APRS(tm) specification, available from http://www.tapr.org . HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA. See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.ew.usna.edu/~bruninga/aprs.html "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degreees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have recieved one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: http://web.usna.navy.mil/~bruninga/dfing.html and the APRSdos documentation for details on these useful techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In hundredth of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In hundredth of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (http://wxsvr.net/) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects [CAD object support has moved from the right click menu to Map/Draw CAD Objects]. CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normaly) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Find Address This option brings up a search dialog where you can enter an address. It will center on the map if the address is found. The path to the geo-coder file is saved between calls. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with ImageMagick support, and does not apply to geoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions in the README.MAPS file. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the currently available vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported, as well as PocketAPRS format maps and GNIS (Geographic Names Information System) label files. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with ImageMagick support, enabling support for many graphic formats as maps (see "http://www.imagemagick.org/www/formats.html"). Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. Details of locations to obtain many of the above types of maps are found in the file README.MAPS Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in README.MAPS. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with ImageMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/ImageMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (ImageMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. ImageMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use ImageMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. ImageMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: TOPORAMA-250k Canadian 1:250k scale topo maps, downloaded from findu.com. "CanadaTopo250k.geo" is automatically installed in the maps directory. TOPORAMA-50k Canadian 1:50k scale topo maps, downloaded from findu.com. "CanadaTopo50k.geo" is automatically installed in the maps directory. WMSSERVER Allows use of Web Map Services (WMS). An example "WMSRadar.geo" is automatically installed in the maps directory. geoTIFF maps are a combination of two files as well: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS geoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. GNIS (Geographic Names Information System) data is a collection of names of locations, or geographic features. These labels behave like map labels in Dos/WinAPRS maps. As you zoom in, more labels will appear, assuming you've selected the GNIS file as a map and have enabled Map Labels in the Maps menu. If you have some of them in the xastir/GNIS directory, you can also search for map labels within Xastir. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in README.MAPS. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the README.MAPS file. Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: ImageMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the ImageMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapblast2geo.pl This script creates .geo files for Mapblast pixel maps. It includes usage information. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. split_gnis.bash This will take a GNIS data-point file (typically for a whole state, 8+MB), break it down into smaller chunks (typically for a county, 30-200k) it will also throw away the trailing spaces and s at EOL. split_gnis.pl This is a Perl version of the above script. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases [MySQL,Postgis] (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxilliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found in the APRS(tm) Reference which you could get from http://www.tapr.org Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>What was new in Xastir 1.0 Over the past year, Xastir has been under active development, and this new release is the culmination of those efforts. Development has been run by Chuck Byam, who agreed to take over for Frank Giannandrea. Many other individuals have contributed to this project, and are listed in the AUTHORS file. The Xastir package now uses GNU autoconf to build makefiles and select features based on the libraries and software one has installed. No more editing makefiles as in previous releases! Starting Xastir 1.0, one probably won't immediately notice any major changes. The familiar interface of previous Xastir versions has been retained for the most part. The great majority of the changes are improvements in efficiency under the hood: * Startup time for the program has been improved. * Memory usage has greatly improved, with dynamic allocation of separate station, trail, and weather data on an as-needed basis. No longer will memory be wasted on stationary stations for trail data, nor will non-weather stations waste memory for weather information. With these modifications, Xastir can even be connected to the internet link comfortably on a 16MB machine. * Improvements have been made to avoid having to reload maps from disk at every minor change; Weather alerts and changes to the display and tracking options no longer cause the maps to reload, rather the trails and symbols are redrawn alone. * Improvements have been made to various dialog boxes that re-drew often, to redraw less often, to allow them to be usable on slower systems. This is also true of tracking a station, with the map redrawing only if the station approaches the edge of the screen. Thanks to these changes, Xastir is perfectly usable on slower Pentium(tm) machines. Native GeoTIFF support is now included, and will be compiled into one's copy of Xastir if they have the GeoTIFF libraries installed on their system. These map files are of very high quality, and are especially useful in search and rescue operations. Maps on this format are available from the USGS, and commercially on CD-ROM. Xastir understands how to convert from the NAD-27 datum to the new WGS-84 datum, so maps of both format can be read accurately. New shortcut buttons have been added to the map selection dialog to enable one to pick all maps of a specific type. Support for the Festival Speech Synthesis System is now available to announce new stations and band openings. The old system of alert sounds has been retained as well. Xastir now supports adding and deleting objects. Finally, Xastir users are able to manage resources with this useful feature. Objects are helpful for coordinating events, directing travelers, and doing search and rescue work. The County Warning Area maps that display weather alerts are no longer painted onto the maps below, but are shaded onto the maps. While this does make the colors unpredictable, it is now possible to see the road-maps below the alert! A new and useful feature is the change in the orientation of a symbol based on the direction in which it is moving. Even without a trail, a quick glance can tell you a mobile station's bearing. There are several more new options in the display menu, enabling one to decide more precisely what is displayed and what isn't. Panning and control over the map has been enhanced: There are now arrow buttons visible at the top of the screen to pan the map. The map can also be panned with the arrow keys, and the zoom can be adjusted with the page up and page down keys. There are new option in the click menu, to center the map where you clicked or to place an object where you clicked. The panning options in this menu have been removed in favor of the new controls at the top of the screen. Support for altnet has been added, enabling one to have a private APRS(tm) network for special events, search and rescue, storm chasing, or whenever else the user doesn't want to be bothered by the hundreds of APRS(tm) stations around. There are numerous small changes, both visible and invisible to the user. The interface control dialog now has a "Start all" and "Stop all" option, to save the user the time of performing these actions for each interface. The station setup dialog now shows you your symbol, so you don't have to exit the dialog to see which symbol you chose. Several buffer overflows that caused unpredictable behavior and/or crashes have been fixed. And many minor improvements have been made to the source code to ensure that it compiles correctly on various systems. Enjoy the new Xastir! HELP-INDEX>What was new in Xastir 1.1 What was new in Xastir 1.1 This new release, Xastir 1.1, adds significant new features and enhancements to the user interface. Unlike 1.0, the interface changes will take some getting used to, but the flexibility and versatility of the enhanced interface will more than make up for the troubles. Among the improvements to the user interface: * Keyboard shortcuts for menus and dialogs, menu reorganization, and mouse behavior changes. * The ability to move objects or measure distance with the mouse, using the appropriate check-boxes in the toolbar. * A scale has been added to allow one to judge distance on a map. * Map labels for windows-style APRS(tm) maps are rotated to match the marked map features. * The user interface for dealing with objects has been entirely redesigned. * Station info boxes can be set to automatically update. * Tear-off menus. Allow you to keep a menu on the screen and play with different options. Tear off a menu by clicking on the dashed-line portion. Map support has been greatly enhanced, with PocketAPRS, ESRI Shapefiles, GNIS labels and many graphics formats with ImageMagick. Additionally, support for downloading graphical maps from web-servers has been added, allowing Xastir to use online radar, Tiger, and Terraserver maps. Xastir 1.1 supports much more of the APRS(tm) protocol than its predecessor: * It can add, modify, move and view area objects, signpost objects, and items. These features are invaluable for event coordination and search and rescue use. Objects and items are also periodically retransmitted. * Support for displaying position ambiguity squares, pre-calculated radio ranges, Maidenhead grid squares, and weather objects. These features aren't extremely common, but do come up occasionally. * Support for the APRS(tm) radio direction finding features. These features are useful for anything from tracking jammers to locating lost hikers. Xastir supports both Omni and Beam reports. Other notable improvements: * Xastir can now search for a specified location or landmark using GNIS data. * Track logs can now be exported to file. * Maps can be printed if certain tools and libraries are present. * Support for retrieving historical track data from findu.com. * Xastir now compiles and runs on Mac OS X, Solaris and FreeBSD with only minimal changes; see README for details. * Several major bugs found in 1.0 have been corrected, including the problems loading DOS maps and the problems with the weather reporting. Other minor bugs and memory leaks have been fixed. And several more errors have been corrected in the parsing routines, so Xastir should remain stable no matter what is thrown at it! HELP-INDEX>What was new in Xastir 1.2 What was new in Xastir 1.2 The latest Xastir release adds numerous new capabilities, keeping Xastir a benchmark for APRS(tm) programs on any operating system. Xastir's hardware support has been enhanced, with * Support for Serial KISS TNCs * Support for Serial TNCs with GPS on the AUX port * Support for using AGWPE as a TNC * Support for Dallas One-Wire weather station (see http://melhuish.info/simon/projects/oww/) * Support for more weather stations via the wx200d daemon (WX-200/WM-918/ WMR-918/WMR-968) * Support for the different sized rain gauges of the Peet Brothers weather stations. Additionally, several bugs in the weather reporting code were corrected, and support for setting the system clock based on the GPS was added. There have been many additions and improvements to the Xastir user interface: The most notable is the addition of dead-reckoning. This means that stations that are moving will continue to move on your screen in the direction and at the speed speed that they last reported. The estimated location can be shown with any combination of a ghosted icon, a dashed line from the last position, or an arc of expected possible distance and angle. Also very notable are the improvements to the Map Chooser. Maps can now be selected a directory at a time, or individually. And the new map properties dialog allows individual control of map layering, map color filling, and consideration for auto-maps. Additionally, with extent caching under the hood, auto-maps regains much of its formal usefulness even with many maps installed! Bulletins pop up on screen, and emergency beacons cause an alert with the locate station dialog on hand. These changes are helpful in emergencies and event coordination. Xastir can now be set to use one of several coordinate systems, including UTM, dd.ddddd, dd mm.mmm, and dd mm ss.s. This is helpful for coordinating with other groups using a different system. The online Tiger maps can now be enabled from the map menu, and options can be adjusted to request maps with just the data you want displayed. The stations menu has been reorganized, allowing more intuitive filtering of stations shown and of accompanying data. Other smaller interface changes include: * The density of the grid-lines can be adjusted with the +, =, and - keys. * Objects and item lists have been added to the view menu. * Station maidenhead grid squares are now shown in station info and the coordinate calculator. * There is a check-box "Track me" to enable easily tracking your own station * The length of trails downloaded from findu.com can now be specified. * Xastir can now ID via voice IDs or Screen IDs, by editing the configuration file. This is intended for configurations when the Xastir screen is seen remotely via fast-scan TV. * Timestamps are written to log files every 30 seconds of operation, to keep a record of when data was heard. * The status bar can display the course/distance to your station when enabled in the file|configure menu. * Range scales are now shown opposite the map scale. This is an attempt to standardize various APRS(tm) client approaches to zoom levels. New additions under-the-hood: * Tracked proximity alarms. * Export waypoints within proximity boundaries. Your GPS can show you the locations of APRS(tm) stations as waypoints on the GPS map screen. * Export trail as ESRI Shapefile. New feature if you have Shapelib compiled in. Station Info->Store Track button also creates a Shapefile map of the station's track now. The weather reporting features have been improved, with the addition of optional wind barbs to weather stations and decoding of storm wind radius data. Weather alert shading is now done with pixmap stipples showing the type of alert. Further information on an alert is available over the internet from the WXSVR by simply double-clicking the alert in the weather alerts list. Weather alerts now use the newer ESRI Shapefile-format maps. Xastir's map support has been improved with enhancements to the ESRI Shapefile code to handle point-type ESRI Shapefiles. Additionally, speed improvements have been made in the ImageMagick graphical map loading, and many color-correction features have been added. As mentioned above, the Map Chooser has been greatly improved, and weather alerts use ESRI Shapefile-format maps. Under the hood, Xastir has had several major improvements: The messaging system has been largely rewritten, and the annoying timed updates to dialogs no longer occur. The new messaging system allows multiple messages to be queued, and implements reply-ack's for speed. Xastir also attempts to specify a reasonable path for the message based on received messages. This improves speed and congestion control. The messaging GUI has been largely untouched, and remains high on the list of future improvements. The build process has been significantly improved; Xastir is now able to be built on numerous operating systems with few manual interventions. Xastir now supports GPSMan/gpsmanshp, allowing the importing of waypoints, tracks, and routes from several types of GPS receivers. This allows you to create ESRI Shapefile-format maps out of GPS data. Xastir now implements SmartBeaconing(tm), which greatly improves trail quality and reduces unneeded channel usage. See the "Configure SmartBeaconing" help topic. IGating support has also improved, with the ability to configure a specific RF path for IGated packets, and the addition of a 29 second anti-dupe queue to reduce unnecessary redundancy on the RF channel. Map extents and filenames are now cached, so maps will not be loaded from disk unless they are on screen. This is a major improvement for map types that did not specify this information. Additionally, auto-maps uses this information, making it usable even with many maps installed. Objects controlled by Xastir are now stored in a file, so a restart of Xastir will not cause them to be lost. Additionally, Xastir now supports the compressed format for objects and items, which can help reduce RF channel congestion. It also gives you better location accuracy of the placed objects. See the help topic "Configure Default Operation". Xastir now drops root privileges when not needed if run setuid root. Please read the information about this in INSTALL; this change provides only limited protection. Xastir now supports using a private colormap with the command-line argument "-i". This is recommended for systems running in 8-bit color mode. Additionally, several more buffer overruns and other errors were corrected in Xastir's data parser, and numerous other bugs have been fixed. Enjoy the new Xastir! HELP-INDEX>What's new in Xastir 1.3 What's new in Xastir 1.3 This latest Xastir release greatly improves on the efficiency and usability of Xastir, and adds many helpful and often-requested new features. .geo files can now have REFRESH tags, to specify how often the file is reloaded. This is useful for weather radars and other dynamic images. .geo files can also have a TRANSPARENT tag to make a certain color transparent, and a CROP tag to specify a specific region to display. Some Opentrac packets are now decoded and displayed. See http://opentrac.org/ for more details. The default main Xastir directory is now /usr/local/share/xastir; please see the upgrade notes in README for migration information. This more closely mirrors the behavior of other applications. If you're installing from a binary package (rpm/deb/etc), the default install location may be /usr/share/xastir. Xastir efficiency has been greatly improved. Changes in data structures and timing values have made this Xastir release the most efficient yet. Additionally, map redraw sequences are interruptible, so map panning speed has been improved. dbfawk support - Experimental support for configurable shapefile metadata, in an awk-like language. See README.MAPS for more details; this must be turned on with a specific switch to the configure command. GDAL/OGR support - Experimental support for GDAL and loading of native Tiger data (.RT1 files). This is automatically enabled if the GDAL library is found. Support for UTM w/special zones and MGRS coordinate systems. Cad drawing mode allows one to draw regions on your screen using the center mouse button. This feature is not yet complete, but is functional. User interface changes: * Several of the menus have been reorganized to have a hierarchical design. * Additionally, a few colors have been modified for better visibility. * The map label font and style are more configurable * The cursor changes to let one know if they're in move object or measure mode. * If the coordinate system is set to UTM, and "Map Grid" is selected, an UTM grid is displayed. Snapshot mode now generates a .geo file, allowing the image to later be used as a map. Tiger maps have been moved back the chooser, as was the pre-1.2 behavior. This is more consistent. Xastir-Release-2.2.2/help/help-Spanish.dat000066400000000000000000002507061501463444000203350ustar00rootroot00000000000000HELP-INDEX>LAME PRIMERO - Licencia LAME PRIMERO - Licencia !!! NOTA: Este Documento se actualiz en Fecha 04/09/02 !! Para la informacin ms actualizada por favor lea el archivo README.1ST en el directorio de Xastir. Recuerde que este programa es usado por la comunidad HAM, en los EE.UU la FCC le restringe de transmitir sobre RF si usted no es un HAM con licencia. Usuarios autorizados en otros pases fuera de los EE.UU. Deben buscar sus restricciones gubernamentales locales. LICENCIA: XASTIR, Estacin de Aficionado de Rastreo y Reportes de Informacin. Copyright (C) 1999-2000 Frank Giannandrea Copyright (C) 2000-2023 The Xastir Group Este programa es software libre; usted puedes redistribuirlo y/o modificarlo bajo los trminos del GNU Licencia Pblica General como publicado por la Fundacin del Software Libre; cualquier versin 2 de la Licencia, o (a su opcin) cualquier versin ms atrazada. pero SIN NINGUNA GARANTIA; an sin la garanta implcita de COMERCIABILIDAD o APTITUD PARA UN PROPOSITO PARTICULAR. Vea el (GNU) Licencia Pblica General para ms detalles. Usted debes de haber recibido una copia del GNU Licencia Pblica General junto con este programa; si no, escriba al Software Libre Fundacin, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, EE.UU.. Ms informacin sobre el programa puede encontrarse en: http://www.xastir.org/ http://github.com/Xastir/Xastir Hay algunos Forum de discusiones disponibles que son especficamente sobre Xastir. Usted puedes subscribirse en uno o en ambos de ellos para recibir las ltimas informaciones y novedades sobre el desarrollo de Xastir. Visite esta direccin para subscribirse en http://www.xastir.org/. Para ms informacin sobre la Licencia GNU busque en: http://www.gnu.org/ HELP-INDEX>Bienvenido! y Notas de los Autores Bienvenido! y Notas de los Autores XASTIR, Significa, X-ventanas Estacin de Aficionado de Rastreo y Reportes de Informacin. El significado en ingls es como sigue: XASTIR, or (X)windows (A)mateur (S)tation (T)racking and (I)nformation (R)eporting. Es un APRS(tm) como programa que es Fuente Abierta y libre para usarlo y pasarlo a otros. Actualmente este programa est en desarrollo y no debe verse como un producto finalizado! Su ayuda ser necesaria para hacer de este un mejor programa. Si usted tienes habilidades programando y/o puede escribir documentacin, su ayuda puede ser necesaria! Yo tengo muchas ideas pero el tiempo muy corto. As que si usted piensas que usted puedes anexar algo al esfuerzo djemelo saber! 73, Frank Giannandrea fgiannan@eazy.net APRS[tm] es una Marca de fbrica de Bob Bruninga, su pgina est en "http://web.usna.navy.mil/~bruninga/aprs.html" Por favor note que mucha de la informacin sobre APRS(tm) puede encontrarse en la documentacin de APRSdos escrita por Bob Bruninga. Una adicional fuente de informacin es el APRS(tm) especificacin, disponible en http://www.tapr.org HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Iniciando a Xastir por primera vez Iniciando a Xastir por primera vez Cuando Xastir se inicie por primera vez, usted debes ejecutarlo en una ventana terminal asi que cualquier mensaje de advertencia o error puedan verse. En la mayora de los sistemas una ruta es configurada para correr el programa en /usr/local/bin y todo lo que usted necesitas hacer es tipear "xastir" en la lnea de comando. En sistemas que no tienen este tipo de ruta instalado "/usr/local/bin/xastir" para empezar el programa. Usted tambin puedes poner la opcin del Idioma en este momento. Para poner el idioma o cambiar el idioma actual, use sta lnea: xastir -l Los Idomas Actuales son: Alemn (German) Espaol (Spanish) Francs (French) Holands (Dutch) Ingls (English) Italiano (Italian) ElmerFudd (English) MuppetsSwedishChef (English) OldeEnglish (English) PigLatin (English) PirateEnglish (English) Si Usted quieres correr el Xastir en espaol use sta lnea: Ej: xastir -lSpanish o xastir -l Spanish Esta opcin ser guardada en el archivo de configuracin de usuario para que la prxima vez que Xastir se ejecute corra con el idioma Espaol. En nueva instalacin xastir tendr como valor predefinido el idioma ingls a menos que usted uses sta opcin de lnea de comando. NOTA: En mens, se seleccionan artculos que son encanecido, como en las opciones del ON/OFF, si 'ON' es seleccionado se opacar o se pondr transparente (encanecido). HELP-INDEX>Configurando la informacin de la Estacin Configure la Informacin de la Estacin Pulse el botn del ratn en Archivo luego Configurar despus en Estacin llene la casilla con su Indicativo de Radioaficionado. llene su posicin de la estacin si usted no ests usando Xastir con una unidad de GPS. Si usted no la conoce, usted puedes localizar su posicin general en el mapa con Xastir y puedes usar la posicin dada por colocar el puntero del ratn sobre el mapa. Esta posicin ser visible en la barra del fondo de Xastir cuadro 2 de la izquierda. Si usted tienes un GPS usted puedes saltar esta opcin. Los smbol/grupo de la estacin pueden configurarse aqu. Pulse seleccionar grficamente y escoja un smbolo, o manualmente rellene los campos. Una descripcin de texto de cada uno de los smbolos pueden encontrarse en la "Tabla de smbolo" tema de ayuda. Las cubiertas son cumplidas seleccionando un smbolo de la tabla alternada, y poniendo el campo de la tabla a el carcter que usted desea recubrir encima del smbolo. Letras maysculas y los nmeros pueden ser recubierto. El APRS(tm) especificacin slo permite cubiertas sobre smbolos especficos; Xastir no forza esto, pero algunos otros programas pueden. Note que no todos los smbolos se han llevado a cabo en el selector grfico todava, y algunos de ellos no estn por el APRS(tm) especificacin todava. Luego, entre en los datos para la potencia/altura/ganancia de su estacin. Esta es una informacin til pero no se requiere; absolutamente seleccione "Desactive PHG" desactivarlo. Estas opciones presentan una representacin granular de su estacin. Seleccione la combinacin de valores cerca a la descripcin de su estacin. Otra opcin sera especificar el RNG en el campo de comentario en millas en lugar de usar PHG. Vea el APRS(tm) especificacin para detalles. Por favor use altura sobre el promedio del terreno para el valor de altura. No use el promedio de altura sobre el nivel del mar o altura sobre tierra. Para el uso de Ganancia la ganancia de su antena en dBi. (CORRIGEME: dBd? la especificacin no es clara, yo pienso que est implicando dBi porque dice "en ausencia de cualquier datos, las estaciones son asumida a estar corriendo 10w a un 3dB omni en 20pies. Una antena omni tpica es slo 3dBi.....) Para Altura, use el HAAT (altura sobre el promedio del terreno) de su estacin, NO la altura sobre el nivel del mar o altura sobre geo-id. Nota: La ganancia puesta es realmente pensada para las antenas verticales; la ganancia puesta para una antena direcional debera ser por debajo de la ganancia hacia delante de una antena direcional. Esto es porque con la direccionabilidad puesta, el crculo de PHG es compensado slo a travs de 1/3rd de su tamao hacia la direccin especificada. Poniendo la Ganancia ms alta agrandar el crculo entero no-realisticamente, en lugar del aumentado direccionalmente. Haba charla hace varios aos sobre el enmendando las especificaciones para mejorar trato con antenas direccional, pero nada fue cambiado. Entrar un comentario, no requerido pero agregar visin en su estacin. Una cosa comn para entrar aqu es su direccin de e-mail preferida. Que ser transmitido a lo largo con su postula. La ambigedad de la posicin permitir usted controlar que tan exacto usted transmite su posicin. Si usted no pone nada, xastir permitir a su estacin transmitir la exacta posicin que usted ha entrado o ha recibido de un GPS. Las otras opciones lo pondrn en alguna parte en el rango de la opcin que usted seleccion. Note que esto puede tirar estaciones dciles a alguna no-especificacin para un bucle. Findu.com no entiende la ambigedad de posicin. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" conservars las actuales configuraciones. HELP-INDEX>Configurar Operacin Predefinida Configurar Operacin Predefinida Pulse el botn en Archivo despus en Configurar luego en Predefinidos Esta pgina prepara algunos valores por defecto normales para el funcionamiento del programa. Viejas estaciones se desplegarn con un icono fantasma, y el sendero correspondiente se fragmentar. El primer juego de botones de barra especifica el intervalo de desdoblamiento. El segundo juego de botones que especifica cuando una estacin ser removida de la pantalla. Las estaciones tambin son removida del banco de datos interno en el doble este tiempo, as si usted lo pusiera durante 6 horas, se anularn estaciones del banco de datos a las 12 horas. El tercer juego de botones especifica qu a menudo la identificacin de su estacin ser transmitido. Para las estaciones fijas una recomendacin buena es cada 30 minutos, y definitivamente ninguno menos de 10 minutos. Las estaciones mviles pueden desear una ms rpida proporcin. Este intervalo tambin se usa para mandar objetos y artculos. Pruebe mantener este intervalo algo razonable, como transmitir hacia un largo camino, cada 30 segundo realmente subir mucho el tiempo areo. GPS Tiempo pondr el intervalo de tiempo mirar el GPS por nuevos datos. Esto es disponible para estaciones que usan un cable compartido HSP con su TNC. La Opcin Trasmite Estacin fija el tipo de paquete que su estacin transmitir sus datos como. Transmite datos Raw WX si seleccionado tambin enviar un paquete que contiene Datos raw de una Estacin Meteorolgica. Esto es til en los tipos de ASCII de estaciones WX, como la Peet Bros. Estacin WX. Las Opciones de IGate prepararn su estacin como un portal de Internet-RF. Esta opcin podra ser usada con cuatela, Como un HAM usted es responsable por el data que viene va el Internet y es transmitido hacia el Puerto de RF. Usted tambin necesitar escoger una opcin del igate en cada interface para que el igate funcione. Si usted quiere tener su igate enve NWS alarmas WX hacia el RF, usted debe crear un archivo ~/.xastir/data/nws-stations.txt listando cada llamada o estacin de NWS (como "PHISVR") que le gustara transmitir va RF. "Transmitir datos de WX RAW", si seleccionado, tambin enviar un paquete que contiene crudo (raw) Datos de estacin meteorolgica. Esto es til en los tipos de ASCII de estaciones WX, como la Peet Bros. estacin meteorolgica. "Los datos de posicin comprimida pueden ser transmitida"?, si es seleccionado, transmitir en el ms nuevo formato comprimido. Este formato reducir la cantidad de datos en el aire, por eso aumentando la capacidad de la red APRS(tm). La mxima precisin de la posicin transmitida tambin es ms alta. Algunos programas ms viejos, incluyendo las recientes versiones de WinAPRS, no decodificar este formato todava. Findu.com tambin podran tener problema con el. Activar Red Alternada ? esta opcin se usa para desplegar grupos de estaciones que muestran en el unproto en el campo '>To' la versin del software como el Xastir que muestra la versin en el unproto como esto: HI8GN>APX090. Usted tambin puede seleccionar Altnet y puede escoger una llamada del altnet de este dilogo. Altnet le permite tener un privado APRS(tm) red entre las estaciones que tambin tenga altnet configurado, y tiene la misma llamada del altnet entrada. Si cambiamos el valor por defecto que es XASTIR por ejemplo por APX110 desplegar toda las estaciones que tengan versiones de APX11x donde valor de 'x' puede ser desde 0-9. HELP-INDEX>Configurando las Alarmas de Audio Configurando las alarmas de Audio Para usar esta opcin usted debes tener una tarjeta de sonido y un programa que reproduzcan los archivos wav. El programa reproductor de Audio debe tener comando el cual usted quieres ejecutar para tocar el audio archivo (y cualquier opcin en la lnea de comando). Los campos tendrn el nombre del archivo a reproducir, campos bajo la opcin pondr parmetros para la opcin. Las opciones Actuales son: Reproducir mensaje al encontrar una nueva estacin. Reproducir mensaje al recibir un nuevo mensaje. Reproducir mensaje de datos recibidos de una estacin dentro de la distancia min/max de su proximidad. Reproducir mensaje de datos recibidos de una estacin (va TNC) con la distancia de min/max de su banda abrierta. HELP-INDEX>Configurar el Sintetizador de Voz Configurar el Sintetizador de Voz Para usar esta opcin del sintetizador de voz usted debes tener una tarjeta de sonido configurada para poder reproducir sonido. Tambin usted necesita tener instalado y corriendo al Servidor Festival ms el Speech_tools con su biblioteca de soporte para el Sistema Festival de Voz Sntetizada y asi poder escuchar el sintetizador de voz anunciar nuevas estaciones y aperturas de banda proximidad de una estacin. El sistema de alarmas de sonidos ha sido tambin retenido. Con el Sintetizador de Voz adaptado por Curt Mills (we7u) ajuste las casillas en las cuales usted quieres ejecutar el sintetizador para las alarmas (y cualquier opcin en la lnea de comando). Los campos tendrn el nombre del archivo a reproducir, campos bajo la opcin pondr parmetros para la opcin. Las opciones Actuales son: Anunciar un mensaje al encontrar una nueva estacin. Anunciar un mensaje al recibir un nuevo mensaje. Anunciar un mensaje al recibir el cuerpo un nuevo mensaje. Anunciar un mensaje de datos recibidos de una estacin dentro de la distancia min/max de su proximidad. Anunciar un mensaje de datos recibidos de una estacin (va TNC o INET) con la distancia de min/max de su banda abierta. Anunciar un mensaje al recibir una nueva alerta sobre el tiempo climatolgico. Info sobre Festival puede ser obtenida desde: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configurando las Unidades de Medida Configure Unidades de Medida La seleccin predefinida es para el Sistema Mtrico, mm, cm, KPH, etc. Seleccionar Ingls, pulgadas, pies, MPH, etc. Pulse el botn de Configurar, luego en Unidades, despus la unidad de medida que usted quieres usar. Recuerde encanecida opciones son selecciona actualmente. HELP-INDEX>Salvar Configuracin Ahora! Salvar Configuracin Ahora! Este botn salvar todas la configuracin actual al archivo de configuracin. Note que cuando Xastir est cerrado, tambin salva configuracin al archivo de configuracin. HELP-INDEX>Barra de Estado de fondo Barra de Estado de fondo En el fondo de la ventana varios mensajes de estado estn disponibles: En la primera parte en la barra de estados general los mensajes son desplegados. La segunda parte se muestra la posicin lat/long actual moviendo el ratn sobre el mapa. En la tercera parte es usada para mostrar cuntas estaciones estn en el banco de datos. La cuarta parte de la barra desplegar el nivel de enfoque actual y desplegar "Tr" si el rastreo de estacin est encendida (on). El ltima rea desplegar el estado de dispositivo para cada interfz. Cada una desplegar en orden primero hasta el ltimo o de 0 a 9. El estado de la interface est separado en tres reas, tipo de dispositivo cima, datos de centro fluyendo, y interface de fondo estado operacional. El tipo de dispositivo mostrar qu interfaces se configuraron. El color mostrar qu tipo de dispositivo de la interface se configur. Azul es para los varios dispositivos TNC; Verde mostrar los dispositivos de GPS; Amarillo para los Servidores de Internet; Naranja para las interfaces de WX. El centro mostrar que los datos fluyen en rx (flecha que apunta a l a izquierda) o los datos fluyen fuera tx (flecha que apunta a la derecha) para eso interface. Una caja verde al fondo mostrar si esa interface es activa. Una caja roja mostrar si la interface es activa pero en una condicin de error. Por otra parte nada mostrar si la interface no est activa. Las ltimas dos partes mostrarn el estado del tnc y de la red. Una "=>" indicar si el dato est siendo enviado, y una "<=" si el dato est entrando desde la interfaz. HELP-INDEX>Moviendo el Mapa y el Men de Opciones Moviendo el Mapa y el Men de Opciones Movimiento en el mapa es muy simple, la facilidad y rapidez de movimiento son dependientes de la velocidad de su procesador y la cantidad de detalle que usted carga. Subiendo verticalmente: Subiendo verticalmente puede ser logrado por pulsar el botn derecho de ratn sobre el mapa (y sosteniendo el botn abajo). Est o plantear un men de opciones, con opciones para hacer subir verticalmente o fuera a un solo nivel, o para cambiar a uno de l os niveles del enfoque prefijado. Todas las funciones de enfoque desde el men de opciones harn acercarse o alejarse al punto en el mapa donde usted puls el botn del ratn correcto. El nivel de enfoque tiene una men en cascada. Niveles 1-64 son par a las reas muy locales y niveles 256 y superior es para reas grandes. El nmero ms bajo del nivel, la rea ms local. Una funcin de enfoque ms rpida es empujar y sostener el botn del ratn izquierdo, arrstrelo por el rea de inters y permitida vaya. El mapa har subir verticalmente aproximadamente a el tamao del cuadrado usted apenas descrito con el ratn la funcin de arrastre. El programa usa el componente vertical para decidir en el nivel de enfoque, y el componentes verticales y horizontales para computar el nuevo centro del mapa. El "movimiento" y "medida" que deben desactivarse checkboxes de la bara de herramienta de este rasgo para trabajar. El mapa tambin puede acercarse con el teclado las llaves de PageUp/PageDown. El acercar en este caso guarda el mismo centro del mapa. Paneando/Centrando: El mapa puede centrarse a una situacin especfica por pulsar el botn izquierdo del ratn. Pulsando el botn los enfoques del botn medio aleja con un factor de 2, centrando donde usted puls el botn. Paneando tambin es cumplido usando el men de opciones, o usando la flecha botones en la tope de la pantalla. La posicin del mapa cambiar una porcin de pantalla. Bastantes datos de pantalla anterior deben estar disponibles reorientarlo . El mapa tambin puede ser paneado con las llaves de flecha del teclado. Ms Sobre el Men de Opciones: La seleccin de "Estacin Info" en el men de opciones buscar la estacin cerca a donde usted puls el botn derecho del ratn. Si ms de una estacin est cerca de esa posicin un "escogedor de Estacin" de lista aparecer, entonces usted puede escoger los datos de qu estacin que usted quiere ver. Si slo una estacin es vista entonces el indicador del ratn es cerrad o y los datos de esa estacin se desplegarn inmediatamente. Note que expiradas estaciones todava tienen sus datos guardados en el banco de datos de Xastir, y si uno sabe la situacin anterior de una estacin, uno todava puede ver su info de esta manera. Tambin es posible desplegar estaciones viejas encendiendo el "el Despliegue de Datos Expirados" opcin en el men de las estaciones. CORRIGEME: Si no es completamente verdad. Esto slo despliega algunos de los datos que desaparecen como estaciones fantasma, Velocidad/altitud, etc., Para informacin de Objeto y Artculo, por favor vea el tema de ayuda "Objetos y Artculos" HELP-INDEX>Objetos y Artculos Objetos y Artculos La opcin de crear Objeto/Artculo en el botn derecho pulsado el men traear un dilogo con la posicin de basado objeto en donde usted puls el botn del ratn. Usted puede rellenar los detalles, y agregar un objeto/artculo desde este men. La opcin de modificar Objeto/Artculo le traer un dilogo de modificacin de objeto. Es similar al dilogo de creacin de objeto, excepto por la actual informacin de objeto que ya estn publicada, y el nombre del objeto y unas de las pocas otras opciones que no pueden ser cambiada. Los objetos son retransmitido dentro de la proporcin de posicin de la estacin reportada, configurada en Archivo|Configurar|P redefinidos, y cesar la retransmisin despus doblar el tiempo de despliegue de la estacin, tambin configurada all. "muerta" los objetos tambin son retransmitido de esta manera, hasta que ellos expiren desde la cola. Generalmente se usan los objetos para movimiento o cosas inconstantes como tormentas, mientras que los artculos generalmente son usando para las cosas ms inanimadas, como agua, estaciones. Cualquiera puede moverse con el ratn si el "Movimiento" el checkbox en la barra de botones se habilita. Note que los artculos no pueden ser descifrados por uno cuantos programas APRS(tm) . Las rea de objetos son tiles para una variedad de funcionamientos en lo que usted quiere dibujar o resaltar una rea de inters en el mapa. Ellos tambin pueden ser personalizados para dibujar rastros/caminos/fronteras, sitios de vijilancia para mal el tiempo, las pistas de aterrizaje, permetros, de una rea de bsque da o de un evento de servicio pblico, reas de dao, reas para quedarse fuera de, edificios que no estn en el mapa, la tabla checker/chess para juego por dinero en APRS(tm).: -) Note que las rea de objetos no son llevada a cabo en todas las versiones de programas APRS(tm), y algunos de los detalles de cmo ellos se despliegan tambin pueden ser diferente en otros programas. Nombre ste es el nombre del objeto o artculo. Puede depender de hasta 9 carcteres. Cuando modifica un objeto, este no puede ser cambiado. Para renombrar un objeto usted debe anular el original y entonces crear un nuevo objeto. Note que si usted selecciona Signpost/Area Object/DF Objeto que este campo y quizs otros sern aclarado. Entre en el nombre DESPUS que usted ha seleccionado el tipo de objeto que volver. Poste indicador Este hace al objeto un poste indicador de objeto. Estas seales pueden ser 3 carcteres, visible en un poste indicador a la locacin cuando el enfoque es acercado. (CORRIGEME: Nosotros no hacemos el despliegue de los postes indicadores todava de esta manera). Objeto del rea Esto hace un objeto del rea al objeto, y habilita los mandos de objeto de rea descrito debajo. Objeto DF ste es un informe de contrada-direccin. Habilitndolo le permite escoger reporte Omni o direccional, y le permite poner en el especifico para cada uno. Vea: http://web.usna.navy.mil/~bruninga/dfing.html y la documentacin de APRSdos para los detalles en estas tcnicas tiles. (CORRIGEME: la seccin Separada en las tcnicas de DFing?) Smbolo Estacin Usted puede seleccionar un smbolo para el objeto. Pulse seleccionar para escoger grficamente, o ver la seccin tabla de ayuda de smbolo para las descripciones de cada smbolo. Note que no todos los smbolos se han llevado a cabo todava en el escogedor de grficos, y algunos no estn por el APRS(tm) especificacin. Tambin note esa rea de objeto, poste indicador de objetos, y los objetos d e DF tienen smbolos fijos especiales y por consiguiente no pueden ser seleccionado aqu. Localizacin La localizacin del objeto se especifica aqu. Si usted seleccionara "Crear Objeto/Artculo" pulsando el botn derecho del men, la locacin que usted pulsado se llenar . Si usted moviera un objeto con el ratn, la nueva posicin estar en esos campos. Usted tambin puede teclear en una posici n, por ejemplo usted puede estar poniendo un objeto de un informe de voz sobre el aire. Opciones genricas Usted puede especificar la velocidad, direccin, y altitud de objetos aqu. Algunos tipos de objetos no pueden tener una velocidad o direccin en tales casos los campos son desgrisado . Objeto del poste indicador Si el objeto es un objeto de poste indicador, usted puede especificar de 1 a 3 carcter de mensaje que aparece en la seal aqu. Note que Xastir no despliega los objetos de poste indicador a propiamente todava. Objeto rea Se usan Objetos de rea para resaltar partes especficas del mapas, o para dibujar excepcionalmente detalle dentro de los mapas . Color luminoso. Use la versin ms luminosa de los colores permitidos. Colorido El rea debe llenarse, no slo perfilado. Esto puede ser til para excluir una rea de una bsqueda u otro evento. Tipo de objeto Escoge desde las formas geomtricas permitidas. Color del objeto Escoge el color en el que el objeto se desplegar. Esto tambin es afectado por el "Color Luminoso" la opcin anteriormente. El objeto Compensado En centsima de un grado latitud. Un detalle infortunado de la especificacin, y duro de calcular fcilmente. Basta decir que usted puede cambiar el tamao del objeto una vez usted lo ponga. El Desplazamiento izquierdo del objeto excepto / En centsima de un grado latitud. Vea anteriormente. Objeto corredor ste es el ancho de una lnea de rea de objeto. Util para las pistas de aterrizaje, tiempo watchboxes, describiendo una rea de inters o una rea de exclusin, etc., (CORRIGEME: Escriba esta parte! (el rea objeto) La especificacin es incierta a m, el cdigo, es incierto a m, pero en el futuro yo lo deducir todos!) Siempre anule sus objetos y artculos cuando usted halla terminado con ellos! No les permita simplemente expirar desde su escondite, como ellos pueden colgarse alrededor de las pantallas de otras personas por un periodo extendido. HELP-INDEX>Men Visualizador Opciones del Men de Visualizar El men de Visualizar presenta varias maneras de ver datos en Xastir. Boletines ste es el APRS(tm) tabla de anuncios, donde importantes anuncios son puesto. Si usted se conecta con la interfz del internet, es una buena idea para poner el rango del campo a unas cientas millas, para ignorar postes de otras porciones del mundo. "0" es el rango del campo, significa el mundo entero. Pulse el botn "Cambio de rango" pulse para hacer cambios a este campo eficaz. Xastir actualmente no soporta el envo de boletines. Datos de paquete entrantes Esto despliega los datos entrantes en su TNC o interfz del internet. Los botones radio debajo selecciona si usted quiere ver slo datos de TNC, slo datos del internet, o ambos. Estaciones mviles sta es una lista de estaciones que se estn moviendo. Las estaciones califican para esta lista si ellas se han movido (ms de una posicin recibida para ellas), el smbolo de la estacin no es considerada. Informacin mostrada incluyendo curso, velocidad, altitud, posicin, nmero de paquetes recibido, nmero de satlites de GPS visibles, curso, de su estacin, y distancia de su estacin. Todas las Estaciones Esta opcin despliega una tabla de todas las estaciones ordenada alfabticamente. Incluyendo el nmero de paquetes odo, el tiempo que la estacin fue oda ltima vez, el camino ms reciente paquete tomado, el PHG, y el comentario de la estacin. Estaciones locales Esta opcin despliega slo estaciones que se oyen va su TNC. Incluye el nmero de paquetes odo, el tiempo que la estacin fue oda ltima vez, el camino ms reciente paquete tomado, el PHG, y el comentario de la estacin. Ultimas Estaciones Esta opcin despliega una tabla de todas las estaciones ordenada recientemente oda a menor recientemente escuchada. Incluye el nmero de paquetes odo, el tiempo, la estacin fue oda ltima vez, el camino que el ms reciente paquete tom, el PHG, y el comentario de la estacin. Estacin WX Esta opcin despliega una tabla de todo el APRS(tm) estaciones del tiempo y sus datos. El datos incluyen curso del viento, velocidad del viento, velocidad de rfaga dle viento, temperatura, humedad, presin baromt rica, lluvia en la ltima hora, lluvia medianoche subsecuentemente, y lluvia en las ltimas 24 horas. Estacin Meteorolgica Propia Despliega sus datos del tiempo si usted tiene una estacin del tiempo y la ha configurado Xastir para accederla. Alerta del Tiempo Los despliegues alarmas recibidas, incluso las banderas de alertas, la alerta fuente/tipo, destino alerta, expiracin, mensaje, y efectuada situacin. Esto datos se usa por el resalto de condado, y no es particularmente humanamente-leble. Usted generalmente puede deducir el estado y condado para la mayora de las alarmas. Trfico de mensaje Muestras todo el trfico de mensaje mientras la ventana est abierta. Incluye la fuente, destino, interfz, y mensaje. La opcin de rango puede limitar este despliegue a las estaciones cercanas, mucho como el mando del rango en boletines. Un rango de 0 causas todos los mensajes a ser desplegados. SobreHora Muestras la cantidad de tiempo pasado subsecuentemente que Xastir fue iniciado. HELP-INDEX>Mapas Opciones y Seleccionar Mapas Mapas Opciones y Seleccionar Mapas Mapas Opciones: Auto mapas (on/off) Cuando cualquier mapa es encontrado, en el directorio de mapas (o cualquier directorio bajo l) ser desplegado, si el cae dentro de la regin de despliegue actual. Usted puedes agregar cualquier nmero de niveles de directorios bajo el directorio del mapa principal para sus mapas. El Auto mapa pasar por todos ellos y hallar que mapa (o parte) debe desplegarse. Todos los Mapas se unirn en el rea de visin. Si usted tienes una cantidad grandes de mapas, mapas muy detallados o una computadora muy lenta, esto puede ser mostrado bastante lento. Cuando esta opcin est apagada, se desplegarn mapas seleccionados con el selector de Mapas. Rejillas sobre Mapa (on/off) Cuando est en 'ON', esta opcin desplegar una lnea de reja cada 10 grados. Niveles de mapas (on/off) Cuando est en 'ON', esta opcin intentar filtrar fuera los datos cuando el nivel de enfoque muesta grandes reas. Esto no trabajar con todos los mapas pero trabajar con los mapas generados de 'Tiger line maps' en el sitio de aprs.rutgers.edu. Areas rellena en colores (on/off) Esta opcion controla el relleno del vector del mapa. En ciertos casos, usted podria querer enliminar el relleno para ver el mapa bajo el tope de mapas. Los mapas son cargados en orden alfabertico por tipo, asi que renombrando mapas es un segundo pero la via es menos elegante archivar la vista deseada. Seleccionar Mapas Esta se presentar con una lista de todos los archivos en su directorio de mapas. Cualquier mapa que usted desearas incluirlo en los datos desplegados, simplemente tiene que pulsar el botn del ratn sobre el nombre. Esto resaltar el nombre del mapa, Usted puedes seleccionar cualquier nmero de mapas. Pulsando en el botn "Aceptar" se desplegarn los mapas seleccionados. Oprimiendo el Botn de "Cancelar" abandonara cualquier cambio. Tambien hay botones de atajo para seleccionar todos de un cierto tipo de mapa, o de-seleccionar todos los mapas de una vez. Una nota sobre mapas: Muchos de los actuales mapas de vectores disponibles para los EE.UU. fueron creado en NAD 1927 datum, mientras Xastir y otros programas de APRS usan el WGS 1984 datum. Si es enfocado hacia una rea pequea en el mapa la variacin del datum puede ser muy notable. Los mapas topo USGS tienen sus datum corregido por Xastir como ellos son desplegados, asi que la posiciones generalmente sern ms exacta con los mapas topo. HELP-INDEX>Archivos Mapas, Dos, Windows, Pixmaps, geoTIFF y Condados WX Archivos mapas, Dos, Windows, Pixmaps, geoTIFF y Condados WX Tipos de mapas Xastir trabajar con varios tipos archivos de mapas. Todo el Dos, Windows/MacAPRS[TM] son archivos de Mapas que son soportados. Un nuevo formato de Pixmap se ha agregado en versin 0.3.2. Xastir tambin soportar mapas para las Alertas de condados WX. El ltimo formato de mapa soportado es geoTIFF, tales mapas como son USGS DRG topo mapas. Locaciones de Mapas Cualquier Dos, Windows/Mac o archivo Pixmap y geoTIFF, deben guardarse en el Directorio de /usr/local/share/xastir/maps en su computadora. Usted puedes crear cualquier nmeros de directorios bajo este directorio para ayudar a separar sus datos. Por ejemplo usted puedes querer crear un directorio de USA. y despus uno por cada estado bajo el Directorio de USA. O tiene un directorio separado para DOS o Pixmaps y geoTIFF. /usr/local/share/xastir/maps/ /usa/ /usa/CO/ /usa/NJ/ /dos/CO/ /dos/NJ/ /pixmaps/CO/ /pixmaps/NJ/ Pixmaps realmente son una combinacin de dos archivos, un archivo de dato con un, pixmap (.xpm), grfico y un archivo de locacin (.geo). El archivo .xpm es una estructura de grfico normal, con una imagen de cualquier tipo. Usted puedes usar XView para convertir gif, jpg, y tif imgenes en este formato. El archivo geo es un archivo de dato que atar la imagen a una locacin en el mundo. Aqu est un ejemplo de mi archivo world1.geo ARCHIVO world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Este es un archivo simple, con 4 componentes bsicos. La primera lnea especifica este archivo data .geo es usado, este archivo debe estar en el mismo directorio como el archivo de .geo. La segunda lnea muestra un comentario; cualquier lnea con el carcter como un "#" ser ignorado. Las ltimas dos lneas son para conectar un pixel en la posicin x,y en la imagen a una posicin lat y long en la mundo. Dos puntos unidos son necesitado y debe estar cerca de la esquina izquierda superior y la esquina derecha ms abajo de la imagen. Usar archivo pixmap con xastir, use el selector de mapa y seleccione el archivo .geo para incluir la imagen en la vista del mapa actual. Por razones de velocidad, otras lneas de opciones pueden ser anexada en el archivo .geo. Aqu algunos ejemplos del formato modificado: ARCHIVO Agnes_Mountain.xpm.gz # # X Y Lon Lat # ---- ---- ------------- ----------- TIEPOINT 0 0 -121.00120491 48.37481943 TIEPOINT 1337 1999 -120.87619806 48.24982052 # #EDGES BOTTOM TOP LEFT RIGHT EDGES 48.24982052 48.37481943 -121.00120491 -120.87619806 La lnea EDGES especifica el min/max bordes del mapa. El mencionado mapa arriba es inclinado ligeramente, el cual es el porqu los nmeros no corresponden a la esquina 'tiepoints' exactamente. Xastir usar esa informacin saltar el mapa si no encaja en la vista actual. Mapas geoTIFF son una combinacin de dos archivos tambin: un archivo .tif y un .fgd. El archivo .tif es el actual data mapa. El archivo .fgd necesita solamente tener cuatro lneas como estas: 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir usa esas cuatro lneas en su calculaciones para determinar los puntos de la esquina del mapa, y si o no el mapa vuelve al actual punto de vista (asi que el puede decidir si saltarlo). Si su data mapa es un mapa topo USGS, el archivo .fgd podra ser ledamente disponible a usted. Una forma anexada en Xastir es la abilidad hacer traslaciones datum desde NAD 1927 a WGS 84 datum, el cual hace el mapa topo USGS mucho ms posicionalmente exacto sobre la pantalla en Xastir. Mapas Condado WX Todos los mapas Condado WX deben guardarse en el directorio de /usr/local/share/xastir/Counties. Hay formatos diferentes para los mapas, pero de cualquier modo este directorio tendr directorios (usted podras necesitar crearlos) bajo este para cada estado (2 abreviaciones de letras). /usr/local/share/xastir/Counties /CO/ /CO/COPARK.map /CO/CODOUGLA.map /CO/COJEFFER.map /CO/COZ001.map /CO/COZ002.map /CO/COZ003.map /NJ/ /NJ/NJOCEAN.map /NJ/NJBERGEN.map /NJ/NJMONMOU.map /NJ/NJZ001.map /NJ/NJZ002.map /NJ/NJZ003.map Aqui estan dos lugares en el Internet donde usted puedes obtener esos mapas: ftp://aprs.rutgers.edu/pub/hamradio/APRS/NWSCounties/ http://home.att.net/~kg5qd1/Maps.html Como los mensajes NWS son recibidos, diferentes areas obtendrn un tintado hacia las reas designadas. Ellas son coloreadas para especificar diferentes tipos de alertas. Los colores originales fueron: Cian para el asesor, amarillo para alerta del tiempo, rojo para advertencia, naranja para alerta cancelada, azul real para pruebas, y verde para niveles de indeterminadas alarmas. Con la ltima versin de Xastir los colores pueden ser diferentes debido a un cambio mayor: Las reas que ahora son tintadas en lugar de relleno de color, y la dependencia en el tintado debajo los colores. Este cambio fue hecho asi que los mapas estando debajo de esto pueden mantenerse visible debajo en las reas de alertas del tiempo. Las alertas del tiempo podran ser fijada en on/off va el men del mapa tambin. HELP-INDEX>Configurar Interfaces Configurar Interfaces Pulse el botn en Configurar luego en Interfaces Un dilogo de "Interfaces Instalados" debe aparecer. Este dilogo le permitirs a usted Agregar, Anular, y modificar las Propiedades en varios dispositivos que usted puedes querer usar con Xastir. Las opciones actuales son: TNC va el Puerto Serial TNC va un Puerto Serial con (GPS ms cable HSP) GPS va un Puerto Serial Estacin Meteorolgica va Puerto Serial Conexin a un Servidor en Internet TNC va la Uilidades del AX.25 GPS Enlazado va el Servidor gpsd Estacin Meteorolgica Enlazada a una RED TNC va un Puerto Serial con (GPS ms AUX puerto) Para agregar un dispositivo, pulse el botn de agregar. Un dilogo "Elegir Tipo de Interfaz" aparecer. Pulse el botn en el tipo de dispositivo que le gustara agregar. Luego pulse el botn de Agregar en el dilogo "Elegir Tipo de Interfaz". Las propiedades para ese dispositivo aparecer. Rellene la informacin pedida y pulse el botn en Aceptar, anular el dispositivo, pulse el botn en el dispositivo usted deseas anular y entonces pulse el botn Anular. Para modificar las propiedades de un dispositivo, pulse el botn en el dispositivo usted deseas modificar, luego pulse sobre el botn de propiedades. Las propiedades para ese dispositivo aparecer. Cambie la informacin que usted quieres y pulsar el botn en Aceptar. HELP-INDEX>Configurando el Serial sobre un TNC Configurando el Serial sobre un TNC SERIAL TNC CONFIGURACION Pulse el botn "Configurar" luego en "Interfaces" despus en "Agregar" despus en "Serial TNC" luego "Agregar" y por ltimo en "Puerto TNC" Si usted tienes un TNC y planea usarlo con XASTIR seleccione "Puerto TNC". El valor por defecto no, es seleccionado. Ahora entre en el puerto que el TNC est, es decir /dev/ttyS0 para com1 Seleccione los valores del puerto que se acoplan a su TNCs velocidad del puerto. Entre en tres rutas de UNPROTO. Xastir asumir los XX VIA la parte de la ruta de UNPROTO. Hay tres Rutas permitidas para que su seal sea escuchada si las condiciones son mala. Si cualquiera de stos es llenado en XASTIR ciclar a travs de uno de ellos a cada intervalo de transmision. Si usted ests local, slo un WIDE2-2 puede ser una buena opcin. Si usted ests usando baja potencia y/o ests distante de un digi entonces WIDE1-1,WIDE2-2 puede trabajar mejor. O si usted conoces el indicativo de su digi ms cercano que usted puedes usar XXXCALL,WIDE2-2. La mayora de ustedes necesitarn slo una ruta. Si usted ests en una rea remota y su seal es difcil de conseguirla usted puedes necesitar ms. Verifique con un grupo local y pregntele que ruta puede ser mejor para su rea. Algunas areas usan el flujo de protocolos ms eficientes, en tales caso usted podra usar WIDE3-3 o WIDE1-1,WIDE3-3. Los archivos de Inicio y Salida del TNC. Estos campos especifican a nombre de archivo qie es localizado en el directorio /usr/local/share/xastir/config. Cada archivo es un archivo de texto estandar conteniendo algunos comandos que usted le gustaria enviarle a su TNC a la vez que el dispositivo es activado (Archivo de Inicio - Startup file) o de deshabilitar (shut down). Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardar la configuracion actual. HELP-INDEX>Opciones del TNC Opciones del TNC Permitir Transmisin (on/off) Esto controla la transmisin de datos a travs del TNC. Usted puedes querer Simplemente escuchar en RF o si usted no es un HAM y no debes transmitir. Con Esta opcin (el cual est apagado por defecto) usted puedes controlar transmisin de cualquier datos va RF. Bitcora (log) del TNC (on/off) Si est en 'ON', un archivo de log (Bitcora) se crear en el directorio logs. El archivo se llamar tnc.log y se aadir con toda la informacin oda va RF. Transmitir Ahora! Este transmitir su position/info de su estacion cuando usted pulses el botn en esta seleccin. No transmitir si la opcin "Serial TNC" no est seleccionada (en la seccin Configurar/Interfaces/Agregar/Serial TNC/Adregar/Puerto TNC) o si la opcin arriba mencionada permitir transmisin est fijada en off. HELP-INDEX>Configurar TNC via Serial c/GPS en HSP cable o AUX puerto Configurar TNC via Serial c/GPS en HSP cable o AUX puerto Esos tipos de interfaces hbridos implementan las opciones de ambos serial TNCs y GPSs. Por favor consulte la configuracin de ayuda para ambos serial TNCs y serial GPSs para ms detalles de informacin sobre la configuracin de esos dispositivos. HELP-INDEX>Configurando el AX.25 TNC Configurando el AX.25 TNC AX.25 TNC CONFIGURACION Esta seccin cubre agregando o modificando AX.25 TNC dispositivos. AX.25 dispositivos pueden sea cualquier dispositivo que use controladores AX.25 en Linux. ste es un controlador de nivel del ncleo (kernel), y el dispositivo como un Baycom o una tarjeta de sonido como mdem puede usarse como un TNC. Estos dispositivos deben ser configurado y correrlo antes de que Xastir pueda usarlos. Seleccionando Activar en Inicio, le dir a Xastir que busque este dispositivo y fije las comunicaciones con l cuando el programa de su primer inicio. Seleccionando Permite Transmitir, le dir a Xastir que cualquier salida de datos de RF puede ser enviado a este dispositivo para la transmisin. Escoja la operacin correcta de IGate para este dispositivo. Usted puedes tener varios dispositivos TNC, y esta opcin puede ser diferente por cada dispositivo. Si usted no ests ejecutando un IGate usted puedes dejar sta opcin predefinida de "Desactivar todo el trfico". Entre el nombre del Dispositivo AX.25 que usted especific en el archivo del axports para este dispositivo. Entre en tres rutas de UNPROTO. Xastir asumir el XX VIA parte de la ruta del UNPROTO. Hay tres rutas permitidas para que su seal sea escuchada si las condiciones son mala. Si cualquiera de sas son llenada en XASTIR ciclar a travs de uno de ellos en cada momento de la transmisin. Si usted es local, slo un WIDE2-2 puede ser una buena opcin. Si usted ests usando baja potencia y/o ests distante de un digi entonces WIDE1-1,WIDE2-2 pueden trabajar mejor. O si usted sabes el indicativo de su digi ms cercano a usted puedes usar XXXCALL,WIDE2-2. La mayora de ustedes necesitarn slo una ruta. Si usted ests en una rea remota y su seal es difcil de conseguir usted puedes necesitar ms. Verifique con un grupo local y pregntele qu ruta puede ser mejor para su rea. Algunas areas usan el flujo de protocolos ms eficientes, en tales caso usted podra usar WIDE3-3 o WIDE1-1,WIDE3-3. NOTA: Para usar dispositivos AX.25 con Xastir usted necesitars ejecutar el programa como "raz" ("root"). Si usted quieres ejecutar Xastir como otro usuario usted necesitars fijar el suid en ON en el archivo de programa de xastir. El orden siguiente como raz debe fijar esto para usted. chmod a+s /usr/local/bin/xastir. como con cualquier programa que este corriendo de esta forma, por favor note que esto puede ser considerado como una seguridad de riesgo, como el programa no ha sido probado para explotar. Uselo en este modo en un multi-usuarios en su propio riesgo! HELP-INDEX>Cmo uso yo mi GPS con Xastir? Usando UN GPS con Xastir Para usar una unidad de GPS con Xastir usted tienes tres opciones, un GPS Conectado a una red o a un serial GPS, o a un serial GPS con un TNC y cable HSP. GPS conectado a una red: La ventaja de usar un GPS conectado a una red es que usted puedes compartir el GPS con otros programas. Xastir usa un programa llamado gpsd para hacer una connexin a una red. Este programa entrega datos de GPS normales en un scalo de conexin de redes. Algunas versiones tambin permiten correccin de GPS va un servidor de Internet. Una vez que usted tengas bajado e Instalado el gpsd en su mquina (u otra mquina), usted puedes fijar el Xastir para conectar a l creando una interfaz. Pulse el botn en "Configurar" y despus en "Interfaces". Cuando el dilogo de Interfaces aparezca Pulse el botn de "Agregar". Un nuevo dilogo aparecer con los tipos de Interfaces, Elegir en "Enlazado GPS (via el gpsd)", y luego pulse el botn en Agregar. Hay 4 opciones a elegir. Primero entre el nombre del servidor del programa gpsd que est ejecutando. Si est en el mismo computador que Xastir entonces entre localhost. Luego entre en el puerto que usted puso el programa gpsd para escuchar. Si usted seleccionas "Activar en Inicio", Xastir tratar de conectar al programa gpsd tan pronto se inicia y tan pronto usted hagas click en el botn "Aceptar". La ltima opcin, si seleccionado, intentar hacer la reconexin al gpsd si un fallo fu encontrado. Serial GPS: Un serial GPS es cualquier unidad de GPS normal que conecte al puerto serial y transmita datos en el NMEA normal. Permitir a Xastir a usar este tipo de GPS pulse el botn de "Configurar" luego en "Interfaces". Cuando el dilogo de Interfaces aparezca pulse el botn de "Agregar". Un dilogo con los tipos de Interfaces aparecer, Pulse sobre el "Serial GPS" y despus en el botn Agregar. Unas pocas opciones para fijar. Primero entre el puerto serial en donde el dispositivo est conectado (como "/dev/ttyS1 (COM2)"). Prximo si usted seleccionas "Activar en Inicio", Xastir intentar inicializar el "serial GPS" cuando l se inicie y cuando usted pulses el botn "Aceptar". Las prximas opciones pondrn la velocidad del puerto serial y modo. Para la mayora de las unidades de GPS los valores predefinidos estn bien. Pero Chequee usted el manual del GPS slo en caso de dudas. HSP TNC/GPS: Mire en "Cmo uso yo mi TNC con Xastir?" HELP-INDEX>Configurando el Puerto/GPS Configurando el Puerto/GPS Pulse el botn en "Configurar" luego en "Interfaces" luego en "Agregar" elija "Serial GPS" luego "Agregar" despus ajuste los parmetros del Puerto/GPS. Para usar una posicin "Serial GPS" en el puerto serial, pulse el botn en Posicin Serial GPS. Este puerto puede especificarse en la Posicin "Slo el puerto de GPS". Usted puedes usar un dispositivo serial como /dev/ttyS1 (COM2). Si usted tienes un cable de HSP que le permitas compartir el Serial TNC con una unidad GPS usted puedes seleccionar "Serial TNC c/GPS ms (Cable HSP). ste es un cable especial y el mo no trabaja en todas las combinaciones de computadores/GPS/TNC. Ahora usted puedes escoger un GPS muestreo y TNC relacin, Recuerde usarlo con precaucin aqui, que sean amigables por sus estaciones cercanas. Activar el uso de los datos de GPS seleccione el "Uso Posicin GPS?" opcin. Con esta seleccin hecha la unidad de GPS pondr al da su posicin. Si esto no se selecciona la posicin actual vendr desde la locacin en configuracin informacin de la Estacin. Cuando active los datos de GPS tambin pondrs al da la posicin en configuracin de informacin de la Estacin. Cuando use el GPS sus paquetes cambian, usted obtendrs una estacin mvil con curso y velocidad an cuando la suya no est moviendose (yo puedo cambiar esto despus a una opcin). El tiempo del GPS le permitir seleccionar proporciones de la relacin de muestra para el GPS y sobre pasar el tiempo del paquete normal por transmitir su estacin. Si usted ests estacionado entonces use 10 minutos. Si usted ests haciendo algn especial/rastreo etc.. use la seleccin que encajarn mejor los datos que usted necesitas. Por favor no haga sobre transmisin, si usted no lo necesitas hacer. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardars las configuraciones actuales. HELP-INDEX>Cmo uso yo mi TNC con Xastir? Usando UN TNC con Xastir Para usar un TNC con Xastir usted tienes tres opciones, un "serial TNC" o un "Serial TNC c/GPS ms (cable HSP)" o un TNC Conectado a una red "AX.25 TNC". AX.25 o un TNC en una red: Este tipo de tnc le permitir compartir el TNC con otros programas. Al usarlo usted debes tener la librera AX.25 , y el HamRadio soporte instalado en el ncleo (kernel) de su Linux OS. Ellos son un poco ms difciles de configurar para usarlo pero hay muy buenas opciones y ventajas en su uso. Usando el soporte del "AX.25 TNC", usted tienes varios dispositivos que usted puedes usar con Xastir. Algunos de ellos son serial TNC que usan AX.25, tarjetas de sonidos como TNC's, Baycom, etc. SERIAL TNC: SERIAL TNC con (GPS ms cable HSP): HELP-INDEX>Configurando la conexin de Internet Configurando la conexin de Internet La conexion a los Servicios de Internet le permite a usted enviar y recibir datos desde y hacia todo el mundo. Para configurar el Internet usted necesitars conocer un host y un nmero de puerto. El host predefinido es www.aprs.net y el puerto es 10151. Usted puedes escoger otros pero este debe trabajar. Una Palabra de paso vlida le permitir a su estacin transmitir por el Internet. Permitir a su estacin salir de una I-Gate y conseguir retransmitir va RF. Para conseguir un cdigo de paso usted necesitars contactar con Frank, email fgiannan@earthlink.net, Enviarle su nombre, Indicativo, etc. Una vez l verifique su estado como un HAM l puede enviarle su cdigo. Usted puedes mantenerse recibiendo y transmitiendo datos va el Internet aunque usted no tengas un passcode. Pero sin el cdigo de paso sus datos no sern directamente retransmitido va RF. Cualquiera que est conectado al Internet directamente conseguir su mensaje. Host1 y Host2 son servidores opcionales que sern contactado si el servidor primario est fuera. Cada servidor ser intentado dos veces, siguiendo al prximo si la conexin fracasa. Si usted quieres que XASTIR reconecte despus de una conexin perdida en el net entonces seleccione la opcin "Reconecte en fracaso de la RED?" en la que por defecto est en ON. Las ltimas opciones son para preparar su estacin para ser un IGate. Esto permite a su estacin con su cdigo de paso simplemente actuar como una puerta (gateway), pero en lugar de otra banda sus datos atravesarn el Internet. Esta opcin no debe ser tomada ligeramente. Primero usted debes coordinar con otros en su rea para que usted puedas agregar verdadera informacin que puede estar perdiendo. Usted tambin debes avisar a Steve sobre esto. Esta versin puede enviar informacin recibida desde su TNC hacia el Internet y transmitir cualquier mensaje procedente de Internet a travs de su estacin via RF. Enviar slo datos va RF si usted tienes el opcin seleccionada de transmisin de mensajes. Slo estaciones que usted has odo (va RF) en las ltimas horas tendrn mensajes enviados a ellos en sta va. Note tambin usted es responsable por los datos transmitidos por su estacin asi que tenga cuidado con esta opcin (otros pueden enviarle mensajes que usted no quieres transmitir). Si usted quieres ver que su I-Gate esta haciendo encienda la opcin Log I-Gate de transacciones. esto construir un archivo de igate.log en su "logs" los directorios mostrarn todos los datos pasados de RF local hacia la red con lnea que tiene "IGATE-RF->NET": y conteniendo todo los datos. Tambin mostrar todo el trfico entrante desde la red con "NET->RF-IGATE:". Note aqu usted no vers la completa salida de paquetes, como su estacin y ruta son asumida. Solamente mostrar el data como un mensaje de tercera persona. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardars los cambios actuales. APRS[tm] es una Marca de fbrica de Bob Bruninga, su pgina est en "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>Opciones de RED Opciones de RED Permitir Transmisin (on/off) Esto controla la transmisin de datos a travs del Internet. El valor por defecto es apagado. Con esto en (off) apagado ningn dato ser enviado al Internet. Bitcora de Internet (on/off) Si esto est en 'ON', un archivo log se crear en el directorio logs. El archivo se llamar net.log y se aadir con toda la informacin oda va el Internet. Transmitir Ahora! Esto transmitir su position/info de la estacin cuando usted pulses el botn en esta seleccin. No transmitir si la opcin est apagada en Permitir transmisin. HELP-INDEX>Configurando una Estacin Meteorolgica sobre un Puerto Serial. Configurando una Estacin Meteorolgica sobre un Puerto Serial. Configurar el puerto serial para su estacin Meteorolgica. A los valores comunes de /dev/ttyS0 (COM1) o /dev/ttyS1 (COM2) pueden ser usado. Seleccionado "Activar en Inicio" le dirs a Xastir buscar este dispositivo y fijar comunicanciones con el cuando el programa se inicie primero. Ahora fije el bps bajo el puerto de configuracin, y los parmetros bajo el puerto estilo. El seteo del puerto estilo 8N1, es usado para 8 bitios de datos, No paridad y 1 bitio de parada (stop bit). 7E1 es usado para 7 bitios de datos, even paridad y 1 bitio de parada. 7O1 es usado para 7 bitios de datos, odd paridad y 1 bitio de parada. Esos parmetros deben de machar con su estacin Meteorolgica. El tipo de opcin de data le perimitir sobrepasar que tipo de serial data el progrma ver. La forma de auto-deteccin primero buscar datos del tiempo en un modo binario como lo usa el Radio Shack WX-200. Si no dato binario es encontrado, Xastir buscar un tipo ASCII de estacin Meteorolgica (como la Peet Bros.) HELP-INDEX>Configurando una Estacin Meteorlgica en la RED Configurando una Estacin Meteorlgica en la RED Xastir puede usar servicios de dato de una estacin Meteorolgica tales como la wx200d. La wx200d le permitirs varias conexiones de redes, asi compartiendo el informe del tiempo con varios programas o computadores. Entre el nombre del host (o la direccin numrica IP) y el nmero del puerto de la estacin Meteorolgica servidora que usted quieres contactar. Seleccionado "Activar en Inicio" le dirs a Xastir buscar este dispositivo y fijar comunicanciones con el cuando el programa se inicie primero. Seleccionado "Reconectar en fallo de la RED" le dir a Xastir tratar de reconectar cuando el data conexin haya fracasado. Como antes el tipo de data sobrepasar el auto-deteccin. HELP-INDEX>Dilogo info estacin - bsqueda FCC y RAC Dilogo info estacin - bsqueda FCC y RAC Info estacin desplegar cualquier dato descifrado por Xastir. Actualmente dos o tres botones aparecen aqu adems del botn Cerrar. Los botones de Anular Rastro anularn cualquier lnea de rastro para esa estacin que es actualmente guardada o en el despliegue de mapa. Enve mensaje abrir la ventana de mensaje y le permitir enviar a mensje a esta estacin. El llenar en el indicativo por usted. Si el banco de datos de FCC se instala, un botn de Bsqueda en el Banco de datos FCC aparecer en este Dilogo. Si el RAC (RadioAficionados de Canad) banco de datos se instala, un botn de bsqueda RAC Banco de datos aparecer para indicativo que empiezan con una "V". El archivo FCC y RAC deben colocarse en el directorio /usr/local/share/xastir/fcc, y el caso es importante! Usted puedes usar este botn para agregar los nombres de estaciones y dirjase al Dilogo de Estacin Info. Para usar la bsqueda de FCC bajelo de aqui: ftp://ftp.fcc.gov/pub/XFS_AlphaTest/amateur/appl.zip o el Nuevo banco de datos en: ftp://ftp.fcc.gov/pub/Bureaus/Wireless/Databases/uls/complete/l_amat.zip (El nico archivo necesitado forma este 40Meg zip es el archivo EN.dat) * * * * NOTA para usar el NUEVO archivo base de datos debe ordenarse primero!!! * * * * Asegrese que usted tienes espacio en el disco suficiente para esto como el archivo es GRANDE! Para ordenar el archivo: sort +4 -t \ | EN.dat >EN.dat.ordenado rm EN.dat mv EN.dat.ordenado EN.dat Para usar la bsqueda de RAC bjelo de: ftp://ftp.rac.ca/pub/cdncaldb.zip Xastir crear archivos ndice por cada archivo del banco de datos en el inicio. Si un archivo de indicativo es eliminado mientras Xastir est corriendo, crear o reconstruir el ndice en la prxima bsqueda. No se manejan prefijos especiales. HELP-INDEX>Opciones de Despliegue Opciones de Despliegue Estas opciones le permitirn desplegar datos sobre la estacin alrededor del cono de las estaciones en el mapa. Indicativo (on/off) Cuando est en 'ON', todo los indicativos de las estaciones se desplegarn. Si este esta en 'OFF' los indicativos no se desplegarn sobre el mapa. Para viejas estaciones el smbolo es dibujado como fantasma y en su orientacin estandar. Corespondiendo al arrastre que son subrayado ms que slido y todo el data excepto el indicativo desaparece de la pantalla. Callsign (on/off) Determines if the callsign is displayed on the right side of the symbol. Altura (on/off) Cuando est en 'ON', una lnea azul de datos aparecer sobre el indicativo. Este desplegar la ltima altitud conocida de la estacin. Curso (on/off) Cuando est en 'ON', una lnea verde de dato aparecer debajo del indicativo. Esto desplegar el ltimo curso conocido (en grados) de la estacin que est en movimiento. Velocidad (on/off) Cuando est en 'ON', una lnea roja aparecer debajo del indicativo (o curso). Esto despliegar la ltima velocidad conocida de la estacin que est en movimiento. Dist/curso (on/off) Cuando est en 'ON', se desplegarn dos lneas de informacin en el lado izquierdo del cono de la estacin. La lnea de arriba tendr la distancia de su estacin hacia esta estacin. La lnea de abajo tendr el curso desde su estacin hacia esta estacin. Rastros de estaciones (on/off) Cuando est en 'ON', cualquier estacin en movimiento arrastrar una lnea coloreada con las ltimas 100+ localizaciones. Cuando la estacin se pone vieja el cono es opaco la lnea de rastro se volver intermitente en lugar de la lnea contnua. Estacin Potencia/Ganancia (on/off) Cuando est en 'ON', se desplegarn Crculos de Poder/Ganancia. Sobrepasando los crculos indicado que las estaciones estn tericamente con simple rango uno del otro. Esto es aproximandaemnte exacto, especialmente in reas de terreno variable. Rastreo Estacin Traer una caja abierta similar a la opcin localizar estacin. Usted puedes entrar todos o parte del indicativo. Al seleccionar "Rastrear Ahora!" El despliegue saltar a la posicin de la estacin (si es encuentrada). Cuando nuevos datos para esa estacin son encuentrados el despliegar el rastro a lo largo de esa estacin. El botn "Borrar Rastro" limpiar todo el rastro. El botn de "Cancelar" terminar sin cambios realizados. Informe del Tiempo (on/off) Cuando est en 'ON', los ltimos datos del tiempo (velocidad/curso/rfaga,Humedad,temperatura,viento) son desplegados. Smbolos (on/off) Determina si los smbolos podran ser dibujado en el mapa. Rotar Smbolos (on/off) Si 'ON', algunos smbolos deberan cambiar su orientacin y mostrar la direccin en la cual una estacin mvil se est moviendo. HELP-INDEX>Mensajes Mensajes Enviar mensaje a y Mensajes De grupo abierto stos son muy similares. El "Enviar mensaje a" enviar sus mensajes a una estacin y recibir slo forma de datos de la estacin. Los mensajes de grupo son ms en general usted puedes recibir cualquier mensaje para el grupo y usted enviars sus mensajes a ese nombre de grupo. Los mensajes de grupo no pueden trabajar mejor por el momento hay varios problemas que necesitan ser solucionado. Sin embargo, volviendo atrs al uso de estas pantallas. Cada una de estas pantallas contienen una caja de mensaje, una lnea de llamada, una lnea de mensaje, y varios botones. Usted debes primero entrar la llamada del grupo o estacin que usted quieres avisar. Una vez que eso se hace cualquier nuevo mensaje que ha entrado de esa estacin hacia usted sers desplegado. Si la estacin est envindole informacin y ninguna ventana de mensaje est abierta l abrir automticamente a una nueva ventana (hasta 10) con esos indicativos de estaciones para usted. Usted puedes ahora entrar un mensaje en la lnea de mensaje. El mensaje puede ser ms largo que la lnea de mensaje, y la mxima salida es aproximadamente 250+ carcteres. Una vez su mensaje es entrado, pulsando el botn "Enviar Ahora!" mandar su mensaje. El botn "Enviar Ahora!" se pondr opaco hasta que su mensaje sea completamente Reconocido. Cualquier mensaje que usted recibas ser ordenado por la lnea # y ser puesto en la ventana de mensaje. Si usted ests en un modo de grupo cada lnea desplegar el indicativo de donde el mensaje se envi seguido por el propio mensaje. Los mensajes de grupos actuales son ordenados por llamada y despus la lnea #. Cuando usted hayas enviado el mensaje pulsando el botn de "Cerrar" cerrar la ventana. Dos otros botones son tambin disponible. El botn "Nuevo Indicativo" le permitir mirar datos viejos que una estacin ha enviado. Teclee el indicativo y pulse en este botn, cualquier informacin vieja ser desplegada. Usted tambin puedes usar este botn para cambiar el indicativo de la estacin con la que usted ests hablando. Entre el nuevo indicativo y pulse el botn. El botn de "Borrar Mensajes" limpiar cualquier mensaje desplegado en la ventana de mensajes. Borrar todos los mensajes salientes Esto limpiar todo los mensajes no-conocidos que usted has enviado. Auto Contestacin de Msj Esto encender una contestacin automtica cuando un mensaje entrante se recibe. Fijar Mensaje en contestacin Automtica Esto fijar un mensaje que se enviar en ausencia automticamente. HELP-INDEX>Limpiando el despliegue de lnea de rastros Limpiando el despliegue de lnea de rastros Pulse el botn en "Archivo" y despus "Borrar Todo rastro". Esto limpiar todo el dato de la lnea de rastreo del banco de datos de la estacin y actualiza la pantalla. HELP-INDEX>Limpiando el despliegue de estaciones Limpiando el despliegue de estaciones Pulse el botn en "Archivo" y luego el botn "Borrar Toda las Estaciones". Esto limpiar todo los datos del banco de datos de las estaciones excepto la suya. HELP-INDEX>Reenviando un log (Bitcora) Reenviando una Bitcora Pulse el botn en "Archivo" y despus en "Abrir Bitcora" una ventana de seleccin de archivo se desplegar. Usted puedes usarlo hojear su unidad de disco duro y seleccionar cualquier archivo que contenga un TNC datos raw como aqullos creados por el TNC y opciones de red. Su estacin todava funcionar de la misma manera, recibiendo y transmitiendo. Y debe haber una palabra de advertencia aqu, si su dato contiene una sessin de mensaje y usted tienes su estacin lista para transmitir, responder al archivo como si el dato fu recibido sobre el TNC o Internet. HELP-INDEX>Localizando una Estacin Localizando una Estacin Pulse el botn sobre "Visualizador" luego en, "Localizar Estacin" o sobre el botn de "Desplegar" luego en "Estacin Rastreo" una ventana se abrir. Usted puedes ahora entrar una estacin o parte de una estacin. Por defecto buscar un macheo exacto (llamada completa, no parcial) y no es caso sensible. Si usted ests buscando un macheo parcial, "Macheo Exacto" podra no ser seleccionado. Realmente usted puedes usar esto para localizar una estacin o un objeto. Qu es donde nosotros venimos a la opcin "Macheo Sensible". Yo he notado que algunos objetos estn en caso mixto o minscula. Con "Macheo Sensible" seleccionado, el localizador buscar mayscula y minscula cuando usted la entr. Si "Macheo Sensible" no se selecciona, el localizador asumir cualquier caso que usted teclees es mayscula y investigar en eso. Pulsando el botn "Localizar Ahora!" centrar la primera estacin encontrada en el centro de su pantalla al nivel del enfoque actual. Pulsando el botn "Cancelar" cerrar la ventana. HELP-INDEX>Creando y usando Salto a Localizaciones Creando y usando Salto a Localizaciones Pulse el botn "Visualizador", luego en "Saltar a la posicin" una ventana aparecer. Si sta es la primera vez usted has usado este dilogo no tendrs ninguna entrada en l. Agregar una posicin en la lista de posicin vaya al rea del mapa principal y enfoque el nivel que usted quieres usar. Entre un nico nombre en el rea "Nombre de Nueva localizacin", luego pulse el botn agregar. Su entrada se agregar a la lista (en orden alfabtico). Usted puedes agregar tantas locacin de mapas que usted quieras de esta manera. Para usar uno de la posicin pulsar el botn en el nombre de la posicin y pulsar el botn "IR!", el mapa principal entonces mostrar esa posicin. Usted puedes anular una posicin similarmente pulsando el botn sobre el nombre de la posicin y luego el botn "Anular". HELP-INDEX>Rastreando una Estacin Rastreando una Estacin Pulse sobre el botn de "Desplegar" luego en "Rastreo Estacin". Entre en el indicativo para rastrear (todos o parte) luego pulse el botn "Rastrear Ahora!". Como la estacin lo mueve ser centrado en la ventana del mapa principal. Dejar de rastrear esta estacin pulsar el botn "Anular Rastro". HELP-INDEX>Trfico de mensajes Trfico de todos los mensajes Pulse sobre la opcin de "Trfico de Mensajes" luego un dilogo se abrir e iniciar el Monitoreo de todas las estaciones alrededor del mundo, en chat o enviando mensaje de prueba etc. HELP-INDEX>Imprimiendo Imprimiendo la Pantalla del Mapa Xastir puede imprimir el rea de dibujo en cualquier blanco y negro o color. Hace esto primero descargando la imagen a un archivo XPixmap en disco, entonces usando una herramienta externa para convertirlo al posdata, balancearlo, rotarlo, prevista, entonces la impresin . Usted debe tener su sistema que configure la impresin para manejar posdata (normalmente esto requiere Ghostscript y un filtro de impresin instalados, as como lp o lpr imprime spoolers). Usted tambin debe tener las herramientas siguientes instaladas para esta capacidad: Herramientas de ImageMagick (especficamente "convertido"), "Ghostscript", Conjuntos de caracteres de Ghostscript, y "gv". Una vez todos esos paquetes son instalando y funcional, usted debe una "gv" ventana sobre salte brevemente despus que usted le diga a Xastir crear un archivo de impresin. De all usted puede ver la imagen impresa, y si aceptable, diga a "gv" imprimirlo. Note que algunas veces cambiando a un blanco el fondo predefinido para los mapas se recomienda, dependiendo de qu mapas usted tienen visualizable. Esto puede ahorrar le grandemente la tinta. HELP-INDEX>Creando Captura Instantnea Automticamente Creando Captura Instantnea Automticamente Xastir tiene la capacidad para crear captura instantnea automticamente en pantalla del mapa recurriendo al algo bsico. Este periodo de tiempo es actualmente fijado por cinco minutos. Asumiendo que usted tiene "convertir" de la herramienta de ImageMagick instalado, Xastir crear un archivo de formato XPM en /var/tmp, entonces lo converte, al archivo de PNG /var/tmp/xastir_snap.png. Este archivo es til para ponerlo en pginas web para mostrar una imagen viva de lo que est en su pantalla de Xastir. Habilite este rasgo va el "Archivo->Activar PNG Instantnea". HELP-INDEX>Tabla de Smbolo Eso son los smbolos que usted puedes selecionar para su estacin bajo la "Informacin de la Estacin" men de configuracin. La lista actual puede ser encontrada en el APRS Referencia en el cual usted puedes obtenerlo desde http://www.tapr.org/ Tabla de smbolo Smbolo Grupo/ Grupo/ ! Tringulo w/! Tringulo w/! " Lluvia Nube Lluvia Nube # Digi DIGI $ Smbolo telefnico $ Smbolo % DX DX & GATE-HF GATE ' Avin pequeo Avin Cado ( Nube nube ) TBD * NIEVE Hojuela NIEVE Hojuela + Cruz roja , Inverso L - w/omni casa . X pequea / Punto rojo 0 0 en una caja Crculo 1 1 en una caja 2 2 en una caja 3 3 en una caja 4 4 en una caja 5 5 en una caja 6 6 en una caja 7 7 en una caja 8 8 en una caja 9 9 en un GAS de la caja : Bombero ? ; Tienda tienda < motocicleta Bandern = Mquina de tren > Automvil automvil ? Antena POS ? en una caja @ HURRICAN/TORMENTA HURRICAN/TORMENTA A Primero auxilio Caja B BBS Blowing Nieve C Canoa D D en un crculo E E en un circulo Pila de Humo F F en un crculo G Reja Antena Cuadrada ? H Hotel/Cama I TCP/IP ? J J en un crculo descarga K Escuela L Casa Iluminada Casa Iluminada M Mac N NTS ? O Globo P Carro de Patrulla Rx Q Circle con Crculos Crculo con Crculos R RV Restaurante S Transbordador Satlite T Tormenta (cloud/bolt) Tormenta (cloud/bolt) U Autobs escolar Sol V VOR TAC VOR TAC Smbolo W Servicio del Tiempo Nacional NWS-Digi X Helicptero Y Velero Z Windows [ corredor WC \ DF Tringulo ] Packet Mail Box ^ Avin grande Avin Grande _ Estacin Meteorolgica WS-Digi ` Plato de satlite a Ambulancia b Bicicleta vuela nube c antena de DX d depto de bombero. Antena de DX e Caballo Aguanieve nube f Camin de bombero FC Nube g planeador Bandern (2) h Hospital HAM i Isla Isla j Jeep Jeep k Camin Camin l Punto pequeo Punto pequeo m MIC Milla Poste n N Tringulo Pequeo o EOC Punto en Crculos p Cachorro Punto en Crculos q GS Antena Antena de GS r Antena Torre Antena Torre s Bote Barco t TS ? u 18 Rueda de Camin v Carro de mudanzas Punto en Crculos w H20 Diluvio x X Windows Punto Rojo y Casa w/Yagi Casa w/yagi z X Windows { NIEBLA NIEBLA | Lnea Negra Lnea negra } TCP TCP ~ Velero Velero Xastir-Release-2.2.2/placeholder000066400000000000000000000001251501463444000165510ustar00rootroot00000000000000 This file was needed in order to the directory created. Delete this file at will. Xastir-Release-2.2.2/scripts/000077500000000000000000000000001501463444000160355ustar00rootroot00000000000000Xastir-Release-2.2.2/scripts/.vimrc000066400000000000000000000014331501463444000171570ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/scripts/BUILDRPMS000077500000000000000000000127251501463444000173330ustar00rootroot00000000000000#!/bin/sh # This is an example script used by one of the developers to ease # the workload. It's not intended to be used by the general # userbase. It's included with the Xastir sources so that it # doesn't get lost if the developer should suddenly drop out of # sight. # Run this as root from the xastir source directory (top-level). # It runs some # of the below commands as "archer", others as "root". # When the build is complete it copies the RPM files to the Wetnet server. # Run these commands as "root". # echo echo echo "***********************************" echo "***** Cleaning up Directories *****" echo "***********************************" rm -rf /usr/src/packages/SOURCES/xastir* rm -rf /usr/src/packages/RPMS/x86_64/xastir* rm -rf /usr/src/packages/SRPMS/xastir* # Run these commands as "archer". # echo "Davis..." su -c " cd Davis; ./bootstrap.sh; ./configure; make clean" archer echo "LaCrosse..." su -c " cd LaCrosse; ./bootstrap.sh; ./configure; make clean" archer # These are just to get the configure and spec files in shape. # Configure options don't matter yet here. echo echo echo "********************************************" echo "***** Setting up CONFIG and SPEC files *****" echo "********************************************" su -c " cd Davis; ./bootstrap.sh; ./configure; make clean" archer su -c " cd LaCrosse; ./bootstrap.sh; ./configure; make clean" archer # # NOTE: CPPFLAGS below is for OpenSUSE specifically: Remove it if building RPMs for other Linux OS'es. su -c " ./bootstrap.sh; ./configure CPPFLAGS='-I/usr/include/libgeotiff'; make clean; make dist" archer # Run these commands as "root": # cp xastir-*.tar.gz /usr/src/packages/SOURCES/. # Run these commands as "root": # # Build minimum system (only ImageMagick and internal Shapelib # included), binary package only. Rename this file so that the # following rpmbuild doesn't overwrite it. echo echo echo "*******************************************" echo "***** Creating MINIMUM binary package *****" echo "*******************************************" (cd /usr/src/packages/SOURCES; tar xzf xastir-*.tar.gz; rpmbuild -bb --clean xastir-2.0.8/xastir-min.spec) mv /usr/src/packages/RPMS/x86_64/xastir-2.0.8-1.x86_64.rpm /usr/src/packages/RPMS/x86_64/xastir-2.0.8-min.x86_64.rpm # # # Build maximum system (all optional libraries included), binary and # source packages. echo echo echo "***************************************************************" echo "***** Creating MAXIMUM binary package plus source package *****" echo "***************************************************************" (cd /usr/src/packages/SOURCES; tar xzf xastir-*.tar.gz; rpmbuild -ba --clean xastir-2.0.8/xastir.spec) mv /usr/src/packages/RPMS/x86_64/xastir-2.0.8-1.x86_64.rpm /usr/src/packages/RPMS/x86_64/xastir-2.0.8-max.x86_64.rpm # Run these commands as "root": # # Create a local yum repository in the correct format: mkdir /usr/tmp/repo /usr/tmp/repo/x86_64 /usr/tmp/repo/src cp /usr/src/packages/RPMS/x86_64/* /usr/tmp/repo/x86_64 cp /usr/src/packages/SRPMS/* /usr/tmp/repo/src # # Create repo (cd /usr/tmp/repo/x86_64; createrepo .) (cd /usr/tmp/repo/src; createrepo .) # # Create a .tgz of the repo (cd /usr/tmp/repo; tar czvf xastir-repo.tgz *) # Run these commands as "archer": # echo echo echo "**************************************************************" echo "***** Copying packages to Wetnet and setting permissions *****" echo "**************************************************************" #su -c " cd /usr/bin; scp /usr/src/packages/RPMS/x86_64/xastir-2.0.5-max.x86_64.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/." archer #su -c " cd /usr/bin; scp /usr/src/packages/RPMS/x86_64/xastir-2.0.5-min.x86_64.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/." archer #su -c " cd /usr/bin; scp /usr/src/packages/SRPMS/xastir-2.0.5-1.src.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/." archer #su -c " cd /usr/bin; ssh -l we7u wetnet.net 'chmod 644 /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/*.rpm'" archer #su -c " cd /usr/bin; ssh -l we7u wetnet.net 'chmod 644 /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/*.rpm'" archer # # Copy the tgz of the repo up to Wetnet: su -c " cd /usr/bin; scp /usr/tmp/repo/xastir-repo.tgz we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/." archer # # Remove the repodata files so we don't get multiples: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'rm -rf /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/repodata /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/repodata'" archer # # Untar the repo. Will merge the files in with our other repo files: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'cd /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM; tar xzvf xastir-repo.tgz'" archer # # Remove tgz file: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'rm /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/xastir-repo.tgz'" archer echo echo echo "***********************************" echo "***** Cleaning up build files *****" echo "***********************************" rm -rf /usr/src/packages/SOURCES/xastir* #rm -rf /usr/src/packages/RPMS/x86_64/xastir* #rm -rf /usr/src/packages/SRPMS/xastir* #rm -rf /usr/tmp/repo # NOTE: Will have to set priority of the new repository to 100 (default is 99) in order to override the OpenSuSE-distributed version of Xastir tends to be older. Xastir-Release-2.2.2/scripts/Coordinate.pm000066400000000000000000002073721501463444000204750ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # Coordinate.pm: Perl module for: # # 1) Creating and manipulating Coordinate objects, # 2) Translating coordinates between UTM and Latitude/Longitude, # 3) Translating coordinates between ~231 different datums, # 4) Formatting coordinates into decimal degrees, degrees/minutes, # and degrees/minutes/seconds. # # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # Reference ellipsoids derived from Peter H. Dana's website- # New: http://www.Colorado.EDU/geography/gcraft/notes/datum/elist.html # # Old: http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html # Department of Geography, University of Texas at Austin # Internet: pdana@mail.utexas.edu # 3/22/95 # # # Reference datums derived from Peter H. Dana's website- # http://www.Colorado.EDU/geography/gcraft/notes/datum/datum.html#GeoDat # # # UTM<->LAT/LON translations were originally written in C++ by # Chuck Gantz- chuck.gantz@globalstar.com. Permission received # by Chuck Gantz via e-mail to release it under the GPL license. # Re-coded into Perl by Curt Mills. # # Datum translations were originally written in C by # John F. Waers - jfwaers@csn.net. His code was released to # the public domain. Re-coded into Perl by Curt Mills. # # # TODO: # ----- # Please note that I didn't pay a lot of attention to # keeping the "double" notation in the form of higher # precision floating point routines. This means that # the Perl5 code won't be as accurate as the original # C-code. It doesn't matter for my purposes. If # anyone converts to Math::BigFloat for higher precision, # please send me the changes. As it is I did a # quick check and found a difference of only 1.4 meters # between my Perl results and the results from a web-based # datum-shift calculator on the 'net. -- Curt. # # Should probably add return values for each method. Check # for error conditions and return 0 if problem. # # Add method to tell distance in meters of datum shift (verbose flag?) # # Get rid of print statements unless verbose or debug mode. # # POD documentation. # #------------------------------------------------------------------------------------------------ package CoordinateFormat; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # Conversions between decimal degrees, degrees/decimal minutes, and # degrees/minutes/seconds. These are methods which all work on # "CoordinateFormat" objects. # # These routines probably need a bit of work yet. It'd be nice # to be able to specify field widths. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{RAW} = shift if @_; # Input string $self->{FORMATTED} = shift if @_; # Output string, formatted } sub raw # Set'er/Get'er for input string { my $self = shift; $self->{RAW} = shift if @_; return $self->{RAW}; } sub formatted # Set'er/Get'er for formatted string { my $self = shift; $self->{FORMATTED} = shift if @_; return $self->{FORMATTED}; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # # Degrees and Decimal Minutes # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub degrees_minutes { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $degrees = $minutes = $seconds = $input; $degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/; $seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/; $minutes = $minutes + ($seconds / 60.0); $self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $degrees = int ($input); $minutes = ($input - $degrees) * 60.0; $self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) ); return( $self->formatted() ); } else { print "degrees_minutes() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } # # Degrees/Minutes/Seconds # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub degrees_minutes_seconds { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $degrees = $minutes = $input; $degrees =~ s/(\d+)\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+\.*\d*)/$1/; $seconds = $minutes; $minutes = int ($minutes); $seconds = ($seconds - $minutes) * 60.0; $self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $degrees = int ($input); $minutes = int ( ($input - $degrees) * 60.0 ); $seconds = ( ( ($input - $degrees) * 60.0) - $minutes) * 60.0; $self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) ); return( $self->formatted() ); } else { print "degrees_minutes_seconds() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } # # Decimal Degrees # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub decimal_degrees { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $degrees = $minutes = $seconds = $input; $degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/; $seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/; $self->formatted( sprintf( "%02.8f", $degrees + ($minutes/60.0) + ($seconds/(60.0 * 60.0) ) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $degrees = $minutes = $input; $degrees =~ s/(\d+)\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+\.*\d*)/$1/; $self->formatted( sprintf( "%02.8f", $degrees + ($minutes / 60.0) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } else { print "decimal_degrees() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } #------------------------------------------------------------------------------------------------ package Ellipsoid; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # Ellipsoid: Equatorial_Radius is the ellipsoid semimajor axis (a) # Polar_Radius is the ellipsoid semiminor axis (b). # First_Ecc_Squared is the first eccentricity squared, defined as: 2f - (f^2) # Inverse_flattening (1/f) is the inverse of ellipsoid flattening 'f' # Flattening (f) is defined as: (a-b)/a. # # This object is used to create the Ellipsoid_Table object below, # containing all of the parameters to describe the various # ellipsoids that we need for datum and UTM<->Lat/Lon translations. # # Equatorial_Radius and First_Ecc_Squared are used by the UTM<->Lat/Lon code. # Equatorial_Radius and Inverse_flattening are used by the datum_shift code. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } # # Notice that we compute first_ecc_squared, flattening, and polar_radius # from the other parameters. # sub _init { my $self = shift; my $f; my $b; my $inverse_f; $self->{NAME} = shift if @_; # Name of ellipsoid $a = $self->{EQUATORIAL_RADIUS} = shift if @_; # Semi-major axis, meters $inverse_f = $self->{INVERSE_FLATTENING} = shift if @_; # Inverse of the ellipsoid flattening 'f' if ($inverse_f) { $f = 1.0 / $inverse_f; $self->{FLATTENING} = $f; # Store the flattening value as well $self->{FIRST_ECC_SQUARED} = (2 * $f) - ($f**2); # Compute First Eccentricity Squared from 'f' if ($a) { # f = (a-b)/a # f = a/a - b/a # f = 1 - b/a # b/a + f = 1 # b/a = 1 - f # b = (1-f)a # $b = (1.0 - $f) * $a; $self->{POLAR_RADIUS} = $b; } } } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub name { my $self = shift; $self->{NAME} = shift if @_; return $self->{NAME}; } sub equatorial_radius { my $self = shift; $self->{EQUATORIAL_RADIUS} = shift if @_; return $self->{EQUATORIAL_RADIUS}; } # # Note that you can override the computed POLAR_RADIUS value # by using this method to store a new value in the hash. # sub polar_radius { my $self = shift; $self->{POLAR_RADIUS} = shift if @_; return $self->{POLAR_RADIUS}; } # # Note that you can override the computed FIRST_ECC_SQUARED value # by using this method to store a new value in the hash. # sub first_ecc_squared { my $self = shift; $self->{FIRST_ECC_SQUARED} = shift if @_; return $self->{FIRST_ECC_SQUARED}; } # # Note that you can override the computed FLATTENING value # by using this method to store a new value in the hash. # sub flattening { my $self = shift; $self->{FLATTENING} = shift if @_; return $self->{FLATTENING}; } sub inverse_flattening { my $self = shift; $self->{INVERSE_FLATTENING} = shift if @_; return $self->{INVERSE_FLATTENING}; } #----------------------------------------------------------------------------------------------- package EllipsoidTable; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # I could have created this table as a hash of anonymous arrays, which might have been # faster/more efficient. Oh well. # # All of the methods here are class methods. There isn't even a way to make an # EllipsoidTable object given here. This class is merely a large collection # of Ellipsoid objects, collected in the %_ellipsoid hash. # my %_ellipsoid; # Class data # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # Note that this method is really useless. The name is the same as the # hash key used in the %_ellipsoid hash. Redundant. # sub name { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->name(); } sub equatorial_radius # (a) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->equatorial_radius(); } sub polar_radius # (b) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->polar_radius(); } sub first_ecc_squared # (ecc) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->first_ecc_squared(); } sub flattening # (f) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->flattening(); } sub inverse_flattening # (1/f) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->inverse_flattening(); } # # This method allows printing out each defined Ellipsoid. # sub enumerate { my $self = shift; print "\nEllipsoid\t\tEquatorial Radius (a)\tPolar Radius (b)\tFirst Eccentricity^2\tFlattening (f)\t\t1/f\n"; print "---------\t\t---------------------\t----------------\t--------------------\t--------------\t\t---\n"; foreach my $key (sort keys %_ellipsoid) { printf("%23s,\t%s,\t%s,\t%s,\t%s,\t%s\n", $key, $self->equatorial_radius($key), $self->polar_radius($key), $self->first_ecc_squared($key), $self->flattening($key), $self->inverse_flattening($key) ); } return(1); } # # Auto-run code # # Fill in the hash containing Ellipsoid objects (fill in the Class data) # # Name, Equatorial_Radius (a), Inverse_Flattening (1/f). # # Name: Reference Ellipsoid Name # Equatorial_Radius: (a) = Semi-Major Axis (WGS-84 value = 6378137.0 meters) # Polar_radius: (b) = Semi-Minor Axis (WGS-84 value = 6356752.3142 meters) # Flattening: f = (a-b)/a (WGS-84 value = 0.00335281066475) # First_Eccentricity_Squared: ecc = 2f - (f^2) (WGS-84 value = 0.00669437999013) # Inverse_flattening: Reciprocal Flattening (1/f) (WGS-84 value = 298.257223563) # # We can calculate Polar_Radius (b), Flattening (f), and First_Eccentricity_Squared (ecc) # from the values for Equatorial_Radius (a) and Inverse_flattening (1/f), so the table # includes only the latter two parameters. # #print "Creating ellipsoid data\n"; # Equatorial # Name Name Radius Inverse_flattening $_ellipsoid{"Airy"} = Ellipsoid->new( "Airy", 6377563.396, 299.324964600 ); $_ellipsoid{"Modified Airy"} = Ellipsoid->new( "Modified Airy", 6377340.189, 299.324964600 ); $_ellipsoid{"Australian National"} = Ellipsoid->new( "Australian National", 6378160.000, 298.250000000 ); $_ellipsoid{"Bessel 1841"} = Ellipsoid->new( "Bessel 1841", 6377397.155, 299.152812800 ); $_ellipsoid{"Bessel 1841 (Namibia)"} = Ellipsoid->new( "Bessel 1841 (Namibia)", 6377483.865, 299.152812800 ); $_ellipsoid{"Clarke 1866"} = Ellipsoid->new( "Clarke 1866", 6378206.400, 294.978698200 ); $_ellipsoid{"Clarke 1880"} = Ellipsoid->new( "Clarke 1880", 6378249.145, 293.465000000 ); $_ellipsoid{"Everest (India 1830)"} = Ellipsoid->new( "Everest (India 1830)", 6377276.345, 300.801700000 ); $_ellipsoid{"Everest (Sabah Sarawak)"} = Ellipsoid->new( "Everest (Sabah Sarawak)",6377298.556, 300.801700000 ); $_ellipsoid{"Everest (India 1956)"} = Ellipsoid->new( "Everest (India 1956)", 6377301.243, 300.801700000 ); $_ellipsoid{"Everest (Malaysia 1969)"} = Ellipsoid->new( "Everest (Malaysia 1969)",6377295.664, 300.801700000 ); $_ellipsoid{"Everest (Malay. & Sing)"} = Ellipsoid->new( "Everest (Malay. & Sing)",6377304.063, 300.801700000 ); $_ellipsoid{"Everest 1948"} = Ellipsoid->new( "Everest 1948", 6377304.063, 300.801700000 ); $_ellipsoid{"Everest (Pakistan)"} = Ellipsoid->new( "Everest (Pakistan)", 6377309.613, 300.801700000 ); $_ellipsoid{"Fischer 1960 (Mercury)"} = Ellipsoid->new( "Fischer 1960 (Mercury)", 6378166.000, 298.300000000 ); $_ellipsoid{"Fischer 1968"} = Ellipsoid->new( "Fischer 1968", 6378150.000, 298.300000000 ); $_ellipsoid{"Modified Fischer 1960"} = Ellipsoid->new( "Modified Fischer 1960", 6378155.000, 298.300000000 ); $_ellipsoid{"GRS 1967"} = Ellipsoid->new( "GRS 1967", 6378160.000, 298.247167427 ); $_ellipsoid{"GRS 1980"} = Ellipsoid->new( "GRS 1980", 6378137.000, 298.257222101 ); $_ellipsoid{"Helmert 1906"} = Ellipsoid->new( "Helmert 1906", 6378200.000, 298.300000000 ); $_ellipsoid{"Hough 1960"} = Ellipsoid->new( "Hough 1960", 6378270.000, 297.000000000 ); $_ellipsoid{"Indonesian 1974"} = Ellipsoid->new( "Indonesian 1974", 6378160.000, 298.247000000 ); $_ellipsoid{"International 1924"} = Ellipsoid->new( "International 1924", 6378388.000, 297.000000000 ); $_ellipsoid{"Krassovsky 1940"} = Ellipsoid->new( "Krassovsky 1940", 6378245.000, 298.300000000 ); $_ellipsoid{"South American 1969"} = Ellipsoid->new( "South American 1969", 6378160.000, 298.250000000 ); $_ellipsoid{"WGS 60"} = Ellipsoid->new( "WGS 60", 6378165.000, 298.300000000 ); $_ellipsoid{"WGS 66"} = Ellipsoid->new( "WGS 66", 6378145.000, 298.250000000 ); $_ellipsoid{"WGS 72"} = Ellipsoid->new( "WGS 72", 6378135.000, 298.260000000 ); $_ellipsoid{"WGS 84"} = Ellipsoid->new( "WGS 84", 6378137.000, 298.257223563 ); #------------------------------------------------------------------------------------------------ package Datum; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # These are the objects and methods used to create the DatumTable in the next package. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{NAME} = shift if @_; $self->{ELLIPSOID} = shift if @_; $self->{DX} = shift if @_; $self->{DY} = shift if @_; $self->{DZ} = shift if @_; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # # This is mostly a useless method. We store the name here, but it # is also present as the hash key in the %_datum hash. Redundant. # sub name # Name of datum { my $self = shift; $self->{NAME} = shift if @_; return $self->{NAME}; } sub ellipsoid # Name of ellipsoid used in datum { my $self = shift; $self->{ELLIPSOID} = shift if @_; return $self->{ELLIPSOID}; } sub dx # X-offset from WGS84 ellipsoid center { my $self = shift; $self->{DX} = shift if @_; return $self->{DX}; } sub dy # Y-offset from WGS84 ellipsoid center { my $self = shift; $self->{DY} = shift if @_; return $self->{DY}; } sub dz # Z-offset from WGS84 ellipsoid center { my $self = shift; $self->{DZ} = shift if @_; return $self->{DZ}; } #------------------------------------------------------------------------------------------------ package DatumTable; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # I could have created this table as a hash of anonymous arrays, which might have been # faster/more efficient. Oh well. # # All of the methods here are class methods. There isn't even a way to make a # DatumTable object given here. This class is merely a large collection # of Datum objects, collected in the %_datum hash. # my %_datum; # Class data # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub name # Name of datum { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->name(); } sub ellipsoid # Name of ellipsoid used in datum { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->ellipsoid(); } sub dx # X-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dx(); } sub dy # Y-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dy(); } sub dz # Z-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dz(); } # # This method allows printing out each defined Datum. # sub enumerate { my $self = shift; print "\nDatum\t\t\t\t\t\t\t\tEllipsoid\tDx\tDy\tDz\n"; print "-----\t\t\t\t\t\t\t\t---------\t--\t--\t--\n"; foreach my $key (sort keys %_datum) { printf("%s\n\t\t\t\t\t\t%23s,\t%s,\t%s,\t%s\n", $key, $self->ellipsoid($key), $self->dx($key), $self->dy($key), $self->dz($key) ); } return(1); } # # Auto-run code # # Fill in the Class data. # # This code fills in the %_datum hash which has entries consisting of Datum objects. # # From the original C code: # # "Dx, Dy, Dz: ellipsoid center with respect to WGS 84 ellipsoid center # x axis is the prime meridian # y axis is 90 degrees east longitude # z axis is the axis of rotation of the ellipsoid" # # Most of the current data is from Peter Dana's website. # This increased the number of datums to around 231. -- Curt. # # # NOTE: Consider adding a field for "region of use". # # # Name Name Ellipsoid Dx Dy Dz $_datum{"Adindan (Burkina Faso)"} = Datum->new( "Adindan (Burkina Faso)", "Clarke 1880", -118, -14, 218 ); $_datum{"Adindan (Cameroon)"} = Datum->new( "Adindan (Cameroon)", "Clarke 1880", -134, -2, 210 ); $_datum{"Adindan (Ethiopia)"} = Datum->new( "Adindan (Ethiopia)", "Clarke 1880", -165, -11, 206 ); $_datum{"Adindan (Mali)"} = Datum->new( "Adindan (Mali)", "Clarke 1880", -123, -20, 220 ); $_datum{"Adindan (MEAN for Ethiopia/Sudan)"} = Datum->new( "Adindan (MEAN for Ethiopia/Sudan)", "Clarke 1880", -166, -15, 204 ); $_datum{"Adindan (Senegal)"} = Datum->new( "Adindan (Senegal)", "Clarke 1880", -128, -18, 224 ); $_datum{"Adindan (Sudan)"} = Datum->new( "Adindan (Sudan)", "Clarke 1880", -161, -14, 205 ); $_datum{"Afgooye"} = Datum->new( "Afgooye", "Krassovsky 1940", -43, -163, 45 ); $_datum{"Ain el Abd 1970 (Bahrain)"} = Datum->new( "Ain el Abd 1970 (Bahrain)", "International 1924", -150, -250, -1 ); $_datum{"Ain el Abd 1970 (Saudi Arabia)"} = Datum->new( "Ain el Abd 1970 (Saudi Arabia)", "International 1924", -143, -236, 7 ); $_datum{"American Samoa 1962"} = Datum->new( "American Samoa 1962", "Clarke 1866", -115, 118, 426 ); $_datum{"Anna 1 Astro 1965"} = Datum->new( "Anna 1 Astro 1965", "Australian National", -491, -22, 435 ); $_datum{"Antigua Island Astro 1943"} = Datum->new( "Antigua Island Astro 1943", "Clarke 1880", -270, 13, 62 ); $_datum{"Arc 1950 (Botswana)"} = Datum->new( "Arc 1950 (Botswana)", "Clarke 1880", -138, -105, -289 ); $_datum{"Arc 1950 (Burundi)"} = Datum->new( "Arc 1950 (Burundi)", "Clarke 1880", -153, -5, -292 ); $_datum{"Arc 1950 (Lesotho)"} = Datum->new( "Arc 1950 (Lesotho)", "Clarke 1880", -125, -108, -295 ); $_datum{"Arc 1950 (Malawi)"} = Datum->new( "Arc 1950 (Malawi)", "Clarke 1880", -161, -73, -317 ); $_datum{"Arc 1950 (MEAN)"} = Datum->new( "Arc 1950 (MEAN)", "Clarke 1880", -143, -90, -294 ); $_datum{"Arc 1950 (Swaziland)"} = Datum->new( "Arc 1950", "Clarke 1880", -134, -105, -295 ); $_datum{"Arc 1950 (Zaire)"} = Datum->new( "Arc 1950", "Clarke 1880", -169, -19, -278 ); $_datum{"Arc 1950 (Zambia)"} = Datum->new( "Arc 1950", "Clarke 1880", -147, -74, -283 ); $_datum{"Arc 1950 (Zimbabwe)"} = Datum->new( "Arc 1950", "Clarke 1880", -142, -96, -293 ); $_datum{"Arc 1960 (MEAN)"} = Datum->new( "Arc 1960 (MEAN)", "Clarke 1880", -160, -6, -302 ); $_datum{"Arc 1960 (Kenya)"} = Datum->new( "Arc 1960 (Kenya)", "Clarke 1880", -157, -2, -299 ); $_datum{"Arc 1960 (Tanzania)"} = Datum->new( "Arc 1960 (Tanzania)", "Clarke 1880", -175, -23, -303 ); $_datum{"Ascension Island 1958"} = Datum->new( "Ascension Island 1958", "International 1924", -205, 107, 53 ); $_datum{"Astro B4 Sorol Atoll"} = Datum->new( "Astro B4 Sorol Atoll", "International 1924", 114, -116, -333 ); $_datum{"Astro Beacon E 1945"} = Datum->new( "Astro Beacon E 1945", "International 1924", 145, 75, -272 ); $_datum{"Astro DOS 71/4"} = Datum->new( "Astro DOS 71/4", "International 1924", -320, 550, -494 ); $_datum{"Astro Tern Island (FRIG) 1961"} = Datum->new( "Astro Tern Island (FRIG) 1961", "International 1924", 114, -116, -333 ); $_datum{"Astronomical Station 1952"} = Datum->new( "Astronomical Station 1952", "International 1924", 124, -234, -25 ); $_datum{"Australian Geodetic 1966"} = Datum->new( "Australian Geodetic 1966", "Australian National", -133, -48, 148 ); $_datum{"Australian Geodetic 1984"} = Datum->new( "Australian Geodetic 1984", "Australian National", -134, -48, 149 ); $_datum{"Ayabelle Lighthouse"} = Datum->new( "Ayabelle Lighthouse", "Clarke 1880", -79, -129, 145 ); $_datum{"Bellevue (IGN)"} = Datum->new( "Bellevue (IGN)", "International 1924", -127, -769, 472 ); $_datum{"Bermuda 1957"} = Datum->new( "Bermuda 1957", "Clarke 1866", -73, 213, 296 ); $_datum{"Bogota Observatory"} = Datum->new( "Bogota Observatory", "International 1924", 307, 304, -318 ); $_datum{"Bukit Rimpah"} = Datum->new( "Bukit Rimpah", "Bessel 1841", -384, 664, -48 ); $_datum{"Camp Area Astro"} = Datum->new( "Camp Area Astro", "International 1924", -104, -129, 239 ); $_datum{"Campo Inchauspe"} = Datum->new( "Campo Inchauspe", "International 1924", -148, 136, 90 ); $_datum{"Canton Astro 1966"} = Datum->new( "Canton Astro 1966", "International 1924", 298, -304, -375 ); $_datum{"Cape"} = Datum->new( "Cape", "Clarke 1880", -136, -108, -292 ); $_datum{"Cape Canaveral"} = Datum->new( "Cape Canaveral", "Clarke 1866", -2, 151, 181 ); $_datum{"Carthage"} = Datum->new( "Carthage", "Clarke 1880", -263, 6, 431 ); $_datum{"CH-1903"} = Datum->new( "CH-1903", "Bessel 1841", 674, 15, 405); $_datum{"Chatham Island Astro 1971"} = Datum->new( "Chatham Island Astro 1971", "International 1924", 175, -38, 113); $_datum{"Chua Astro"} = Datum->new( "Chua Astro", "International 1924", -134, 229, -29 ); $_datum{"Corrego Alegre"} = Datum->new( "Corrego Alegre", "International 1924", -206, 172, -6 ); $_datum{"Dabola"} = Datum->new( "Dabola", "Clarke 1880", -83, 37, 124 ); $_datum{"Deception Island"} = Datum->new( "Deception Island", "Clarke 1880", 260, 12, -147 ); $_datum{"Djakarta (Batavia)"} = Datum->new( "Djakarta (Batavia)", "Bessel 1841", -377, 681, -50 ); $_datum{"DOS 1968"} = Datum->new( "DOS 1968", "International 1924", 230, -199, -752 ); $_datum{"Easter Island 1967"} = Datum->new( "Easter Island 1967", "International 1924", 211, 147, 111 ); $_datum{"Estonia 1937"} = Datum->new( "Estonia 1937", "Bessel 1841", 374, 150, 588 ); $_datum{"European 1950 (Cyprus)"} = Datum->new( "European 1950 (Cyprus)", "International 1924", -104, -101, -140 ); $_datum{"European 1950 (Egypt)"} = Datum->new( "European 1950 (Egypt)", "International 1924", -130, -117, -151 ); $_datum{"European 1950 (England/Channel Is/Scotland/Shetland Is)"} = Datum->new( "European 1950 (England/Channel Is/Scotland/Shetland Is)", "International 1924", -86, -96, -120 ); $_datum{"European 1950 (England/Ireland/Scotland/Shetland Is)"} = Datum->new( "European 1950 (England/Ireland/Scotland/Shetland Is)", "International 1924", -86, -96, -120 ); $_datum{"European 1950 (Finland/Norway)"} = Datum->new( "European 1950 (Finland/Norway)", "International 1924", -87, -95, -120 ); $_datum{"European 1950 (Greece)"} = Datum->new( "European 1950 (Greece)", "International 1924", -84, -95, -130 ); $_datum{"European 1950 (Iran)"} = Datum->new( "European 1950 (Iran)", "International 1924", -117, -132, -164 ); $_datum{"European 1950 (Italy:Sardinia)"} = Datum->new( "European 1950 (Italy:Sardinia)", "International 1924", -97, -103, -120 ); $_datum{"European 1950 (Italy:Sicily)"} = Datum->new( "European 1950 (Italy:Sicily)", "International 1924", -97, -88, -135 ); $_datum{"European 1950 (Malta)"} = Datum->new( "European 1950 (Malta)", "International 1924", -107, -88, -149 ); $_datum{"European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)"} = Datum->new( "European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)", "International 1924", -87, -98, -121 ); $_datum{"European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)"} = Datum->new( "European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)", "International 1924", -87, -96, -120 ); $_datum{"European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)"} = Datum->new( "European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)", "International 1924", -103, -106, -141 ); $_datum{"European 1950 (Portugal/Spain)"} = Datum->new( "European 1950 (Portugal/Spain)", "International 1924", -84, -107, -120 ); $_datum{"European 1950 (Tunisia)"} = Datum->new( "European 1950 (Tunisia)", "International 1924", -112, -77, -145 ); $_datum{"European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)"} = Datum->new( "European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)", "International 1924", -86, -98, -119 ); $_datum{"Finland Hayford"} = Datum->new( "Finland Hayford", "International 1924", -78, -231, -97 ); $_datum{"Fort Thomas"} = Datum->new( "Fort Thomas", "Clarke 1880", -7, 215, 225 ); $_datum{"Gandajika Base 1970"} = Datum->new( "Gandajika Base 1970", "International 1924", -133, -321, 50 ); $_datum{"Geodetic Datum 1949"} = Datum->new( "Geodetic Datum 1949", "International 1924", 84, -22, 209 ); $_datum{"Graciosa Base SW 1948"} = Datum->new( "Graciosa Base SW 1948", "International 1924", -104, 167, -38 ); $_datum{"Guam 1963"} = Datum->new( "Guam 1963", "Clarke 1866", -100, -248, 259 ); $_datum{"Gunung Segara"} = Datum->new( "Gunung Segara", "Bessel 1841", -403, 684, 41 ); $_datum{"GUX 1 Astro"} = Datum->new( "GUX 1 Astro", "International 1924", 252, -209, -751 ); $_datum{"Herat North"} = Datum->new( "Herat North", "International 1924", -333, -222, 114 ); $_datum{"Hermannskogel Datum (Namibia)"} = Datum->new( "Hermannskogel Datum (Namibia)", "Bessel 1841", 653, -212, 449 ); $_datum{"Hjorsey 1955"} = Datum->new( "Hjorsey 1955", "International 1924", -73, 46, -86 ); $_datum{"Hong Kong 1963"} = Datum->new( "Hong Kong 1963", "International 1924", -156, -271, -189 ); $_datum{"Hu-Tzu-Shan"} = Datum->new( "Hu-Tzu-Shan", "International 1924", -637, -549, -203 ); $_datum{"Indian (Bangladesh)"} = Datum->new( "Indian (Bangladesh)", "Everest (India 1830)", 282, 726, 254 ); $_datum{"Indian (India/Nepal)"} = Datum->new( "Indian (India/Nepal)", "Everest (India 1956)", 295, 736, 257 ); $_datum{"Indian (Pakistan)"} = Datum->new( "Indian (Pakistan)", "Everest (Pakistan)", 283, 682, 231 ); $_datum{"Indian 1954 (Thailand)"} = Datum->new( "Indian 1954 (Thailand)", "Everest (India 1830)", 217, 823, 299 ); $_datum{"Indian 1960 (Vietnam:Con Son Is)"} = Datum->new( "Indian 1960 (Vietnam:Con Son Is)", "Everest (India 1830)", 182, 915, 344 ); $_datum{"Indian 1960 (Vietnam:Near 160N)"} = Datum->new( "Indian 1960 (Vietnam:Near 160N)", "Everest (India 1830)", 198, 881, 317 ); $_datum{"Indian 1975 (Thailand)"} = Datum->new( "Indian 1975 (Thailand)", "Everest (India 1830)", 210, 814, 289 ); $_datum{"Indonesian 1974"} = Datum->new( "Indonesian 1974)", "Indonesian 1974)", -24, -15, 5 ); $_datum{"Ireland 1965"} = Datum->new( "Ireland 1965", "Modified Airy", 506, -122, 611 ); $_datum{"ISTS 061 Astro 1968"} = Datum->new( "ISTS 061 Astro 1968", "International 1924", -794, 119, -298 ); $_datum{"ISTS 073 Astro 1969"} = Datum->new( "ISTS 073 Astro 1969", "International 1924", 208, -435, -229 ); $_datum{"Johnston Island"} = Datum->new( "Johnston Island", "International 1924", 189, -79, -202 ); $_datum{"Kandawala"} = Datum->new( "Kandawala", "Everest (India 1830)", -97, 787, 86 ); $_datum{"Kerguelen Island 1949"} = Datum->new( "Kerguelen Island 1949", "International 1924", 145, -187, 103 ); $_datum{"Kertau 1948"} = Datum->new( "Kertau 1948", "Everest (Malay. & Sing)", -11, 851, 5 ); $_datum{"Kusaie Astro 1951"} = Datum->new( "Kusaie Astro 1951", "International 1924", 647, 1777, -1124 ); $_datum{"Korean Geodetic System"} = Datum->new( "Korean Geodetic System", "GRS 1980", 0, 0, 0 ); $_datum{"L. C. 5 Astro 1961"} = Datum->new( "L. C. 5 Astro 1961", "Clarke 1866", 42, 124, 147 ); $_datum{"Leigon"} = Datum->new( "Leigon", "Clarke 1880", -130, 29, 364 ); $_datum{"Liberia 1964"} = Datum->new( "Liberia 1964", "Clarke 1880", -90, 40, 88 ); $_datum{"Luzon (Philippines:Except Mindanao)"} = Datum->new( "Luzon (Philippines:Except Mindanao)", "Clarke 1866", -133, -77, -51 ); $_datum{"Luzon (Philippines:Mindanao)"} = Datum->new( "Luzon (Philippines:Mindanao)", "Clarke 1866", -133, -79, -72 ); $_datum{"M\'Poraloko"} = Datum->new( "M\'Poraloko", "Clarke 1880", -74, -130, 42 ); $_datum{"Mahe 1971"} = Datum->new( "Mahe 1971", "Clarke 1880", 41, -220, -134 ); $_datum{"Marco Astro"} = Datum->new( "Marco Astro", "International 1924", -289, -124, 60 ); $_datum{"Massawa"} = Datum->new( "Massawa", "Bessel 1841", 639, 405, 60 ); $_datum{"Merchich"} = Datum->new( "Merchich", "Clarke 1880", 31, 146, 47 ); $_datum{"Midway Astro 1961"} = Datum->new( "Midway Astro 1961", "International 1924", 912, -58, 1227 ); $_datum{"Minna (Cameroon)"} = Datum->new( "Minna (Cameroon)", "Clarke 1880", -81, -84, 115 ); $_datum{"Minna (Nigeria)"} = Datum->new( "Minna (Nigeria)", "Clarke 1880", -92, -93, 122 ); $_datum{"Montserrat Island Astro 1958"} = Datum->new( "Montserrat Island Astro 1958", "Clarke 1880", 174, 359, 365 ); $_datum{"Nahrwan (Oman:Masirah Is)"} = Datum->new( "Nahrwan (Oman:Masirah Is)", "Clarke 1880", -247, -148, 369 ); $_datum{"Nahrwan (Saudi Arabia)"} = Datum->new( "Nahrwan (Saudi Arabia)", "Clarke 1880", -243, -192, 477 ); $_datum{"Nahrwan (United Arab Emirates)"} = Datum->new( "Nahrwan (United Arab Emirates)", "Clarke 1880", -249, -156, 381 ); $_datum{"Naparima BWI"} = Datum->new( "Naparima BWI", "International 1924", -10, 375, 165 ); $_datum{"NAD27 Alaska:Except Aleutian Is"} = Datum->new( "NAD27 Alaska:Except Aleutian Is", "Clarke 1866", -5, 135, 172 ); $_datum{"NAD27 Alaska:Aleutian Is E of 180W"} = Datum->new( "NAD27 Alaska:Aleutian Is E of 180W", "Clarke 1866", -2, 152, 149 ); $_datum{"NAD27 Alaska:Aleutian Is W of 180W"} = Datum->new( "NAD27 Alaska:Aleutian Is W of 180W", "Clarke 1866", 2, 204, 105 ); $_datum{"NAD27 Bahamas:Except San Salvador Is"} = Datum->new( "NAD27 Bahamas:Except San Salvador Is", "Clarke 1866", -4, 154, 178 ); $_datum{"NAD27 Bahamas:San Salvador Is"} = Datum->new( "NAD27 Bahamas:San Salvador Is", "Clarke 1866", 1, 140, 165 ); $_datum{"NAD27 Canada (Alberta/B.C.)"} = Datum->new( "NAD27 Canada (Alberta/B.C.)", "Clarke 1866", -7, 162, 188 ); $_datum{"NAD27 Canada (Manitoba/Ontario)"} = Datum->new( "NAD27 Canada (Manitoba/Ontario)", "Clarke 1866", -9, 157, 184 ); $_datum{"NAD27 Canada MEAN"} = Datum->new( "NAD27 Canada MEAN", "Clarke 1866", -10, 158, 189 ); $_datum{"NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)"} = Datum->new( "NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)", "Clarke 1866", -22, 160, 190 ); $_datum{"NAD27 Canada (Northwest Territories/Saskatchewan)"} = Datum->new( "NAD27 Canada (Northwest Territories/Saskatchewan)", "Clarke 1866", 4, 159, 188 ); $_datum{"NAD27 Canada (Yukon)"} = Datum->new( "NAD27 Canada (Yukon)", "Clarke 1866", -7, 139, 181 ); $_datum{"NAD27 Canal Zone"} = Datum->new( "NAD27 Canal Zone", "Clarke 1866", 0, 125, 201 ); $_datum{"NAD27 Caribbean"} = Datum->new( "NAD27 Caribbean", "Clarke 1866", -7, 152, 178 ); $_datum{"NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands"} = Datum->new( "NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands", "Clarke 1866", -3, 142, 183 ); $_datum{"NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua"} = Datum->new( "NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua", "Clarke 1866", 0, 125, 194 ); $_datum{"NAD27 CONUS MEAN"} = Datum->new( "NAD27 CONUS MEAN", "Clarke 1866", -8, 160, 176 ); # Added for compatibility reasons. Same as above. $_datum{"NAD27 CONUS"} = Datum->new( "NAD27 CONUS", "Clarke 1866", -8, 160, 176 ); $_datum{"NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota"} = Datum->new( "NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota", "Clarke 1866", -9, 161, 179 ); $_datum{"NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri"} = Datum->new( "NAD27 CONUS W of Mississippi/Except Louisiana/Minnesota/Missouri", "Clarke 1866", -8, 159, 175 ); $_datum{"NAD27 Cuba"} = Datum->new( "NAD27 Cuba", "Clarke 1866", -9, 152, 178 ); $_datum{"NAD27 Greenland (Hayes Peninsula)"} = Datum->new( "NAD27 Greenland (Hayes Peninsula)", "Clarke 1866", 11, 114, 195 ); $_datum{"NAD27 Mexico"} = Datum->new( "NAD27 Mexico", "Clarke 1866", -12, 130, 190 ); $_datum{"NAD27 San Salvador"} = Datum->new( "NAD27 San Salvador", "Clarke 1866", 1, 140, 165 ); $_datum{"NAD83 Alaska (Except Aleutian Is)"} = Datum->new( "NAD83 Alaska (Except Aleutian Is)", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 Aleutian Is"} = Datum->new( "NAD83 Aleutian Is", "GRS 1980", -2, 0, 4 ); $_datum{"NAD83 Canada"} = Datum->new( "NAD83 Canada", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 CONUS"} = Datum->new( "NAD83 CONUS", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 Hawaii"} = Datum->new( "NAD83 Hawaii", "GRS 1980", 1, 1, -1 ); $_datum{"NAD83 Mexico/Central America"} = Datum->new( "NAD83 Mexico/Central America", "GRS 1980", 0, 0, 0 ); $_datum{"North Sahara"} = Datum->new( "North Sahara", "Clarke 1880", -186, -93, 310 ); $_datum{"Nahrwn Masirah Ilnd"} = Datum->new( "Nahrwn Masirah Ilnd", "Clarke 1880", -247, -148, 369 ); $_datum{"Nahrwn Saudi Arbia"} = Datum->new( "Nahrwn Saudi Arbia", "Clarke 1880", -231, -196, 482 ); $_datum{"Nahrwn United Arab"} = Datum->new( "Nahrwn United Arab", "Clarke 1880", -249, -156, 381 ); $_datum{"Naparima BWI"} = Datum->new( "Naparima BWI", "International 1924", -2, 374, 172 ); $_datum{"Observatorio Meteorologico 1939"} = Datum->new( "Observatorio Meteorologico 1939", "International 1924", -425, -169, 81 ); $_datum{"Old Egyptian 1907"} = Datum->new( "Old Egyptian 1907", "Helmert 1906", -130, 110, -13 ); $_datum{"Old Hawaiian Hawaii"} = Datum->new( "Old Hawaiian Hawaii", "Clarke 1866", 89, -279, -183 ); $_datum{"Old Hawaiian Kauai"} = Datum->new( "Old Hawaiian Kauai", "Clarke 1866", 45, -290, -172 ); $_datum{"Old Hawaiian Maui"} = Datum->new( "Old Hawaiian Maui", "Clarke 1866", 65, -290, -190 ); $_datum{"Old Hawaiian MEAN"} = Datum->new( "Old Hawaiian MEAN", "Clarke 1866", 61, -285, -181 ); $_datum{"Old Hawaiian Oahu"} = Datum->new( "Old Hawaiian Oahu", "Clarke 1866", 58, -283, -182 ); $_datum{"Oman"} = Datum->new( "Oman", "Clarke 1880", -346, -1, 224 ); $_datum{"Ordnance Survey Great Britain 1936 England"} = Datum->new( "Ordnance Survey Great Britain 1936 England", "Airy 1830", 371, -112, 434 ); $_datum{"Ordnance Survey Great Britain 1936 England/Isle of Man/Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 England/Isle of Man/Wales", "Airy 1830", 371, -111, 434 ); $_datum{"Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales", "Airy 1830", 375, -111, 431 ); $_datum{"Ordnance Survey Great Britain 1936 Scotland/Shetland Is"} = Datum->new( "Ordnance Survey Great Britain 1936 Scotland/Shetland Is", "Airy 1830", 384, -111, 425 ); $_datum{"Ordnance Survey Great Britain 1936 Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 Wales", "Airy 1830", 370, -108, 434 ); $_datum{"Pico De Las Nieves"} = Datum->new( "Pico De Las Nieves", "International 1924", -307, -92, 127 ); $_datum{"Pitcairn Astro 1967"} = Datum->new( "Pitcairn Astro 1967", "International 1924", 185, 165, 42 ); $_datum{"Point 58"} = Datum->new( "Point 58", "Clarke 1880", -106, -129, 165 ); $_datum{"Pointe Noire 1948"} = Datum->new( "Pointe Noire 1948", "Clarke 1880", -148, 51, -291 ); $_datum{"Porto Santo 1936"} = Datum->new( "Porto Santo 1936", "International 1924", -499, -249, 314 ); $_datum{"Provisional South American 1956 Bolivia"} = Datum->new( "Provisional South American 1956 Bolivia", "International 1924", -270, 188, -388 ); $_datum{"Provisional South American 1956 Chile Northern/Near 19S"} = Datum->new( "Provisional South American 1956 Chile Northern/Near 19S", "International 1924", -270, 183, -390 ); $_datum{"Provisional South American 1956 Chile Southern/Near 43S"} = Datum->new( "Provisional South American 1956 Chile Southern/Near 43S", "International 1924", -305, 243, -442 ); $_datum{"Provisional South American 1956 Columbia"} = Datum->new( "Provisional South American 1956 Columbia", "International 1924", -282, 169, -371 ); $_datum{"Provisional South American 1956 Ecuador"} = Datum->new( "Provisional South American 1956 Ecuador", "International 1924", -278, 171, -367 ); $_datum{"Provisional South American 1956 Guyana"} = Datum->new( "Provisional South American 1956 Guyana", "International 1924", -298, 159, -369 ); $_datum{"Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela"} = Datum->new( "Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela", "International 1924", -288, 175, -376 ); $_datum{"Provisional South American 1956 Peru"} = Datum->new( "Provisional South American 1956 Peru", "International 1924", -279, 175, -379 ); $_datum{"Provisional South American 1956 Venezuela"} = Datum->new( "Provisional South American 1956 Venezuela", "International 1924", -295, 173, -371 ); $_datum{"Provisional South Chilean 1963 Near 53S"} = Datum->new( "Provisional South Chilean 1963 Near 53S", "International 1924", 16, 196, 93 ); $_datum{"Puerto Rico/Virgin Is"} = Datum->new( "Puerto Rico/Virgin Is", "Clarke 1866", 11, 72, -101 ); $_datum{"Pulkovo 1942"} = Datum->new( "Pulkovo 1942", "Krassovsky 1940", 28, -130, -95 ); $_datum{"Qatar National"} = Datum->new( "Qatar National", "International 1924", -128, -283, 22 ); $_datum{"Qornoq"} = Datum->new( "Qornoq", "International 1924", 164, 138, -189 ); $_datum{"Reunion"} = Datum->new( "Reunion", "International 1924", 94, -948, -1262 ); $_datum{"Rome 1940"} = Datum->new( "Rome 1940", "International 1924", -225, -65, 9 ); $_datum{"RT 90"} = Datum->new( "RT 90", "Bessel 1841", 498, -36, 568 ); $_datum{"S-42 (Pulkovo 1942) Hungary"} = Datum->new( "S-42 (Pulkovo 1942) Hungary", "Krassovsky 1940", 28, -121, -77 ); $_datum{"S-42 (Pulkovo 1942) Poland"} = Datum->new( "S-42 (Pulkovo 1942) Poland", "Krassovsky 1940", 23, -124, -82 ); $_datum{"S-42 (Pulkovo 1942) Czechoslavakia"} = Datum->new( "S-42 (Pulkovo 1942) Czechoslavakia", "Krassovsky 1940", 26, -121, -78 ); $_datum{"S-42 (Pulkovo 1942) Latvia"} = Datum->new( "S-42 (Pulkovo 1942) Latvia", "Krassovsky 1940", 24, -124, -82 ); $_datum{"S-42 (Pulkovo 1942) Kazakhstan"} = Datum->new( "S-42 (Pulkovo 1942) Kazakhstan", "Krassovsky 1940", 15, -130, -84 ); $_datum{"S-42 (Pulkovo 1942) Albania"} = Datum->new( "S-42 (Pulkovo 1942) Albania", "Krassovsky 1940", 24, -130, -92 ); $_datum{"S-42 (Pulkovo 1942) Romania"} = Datum->new( "S-42 (Pulkovo 1942) Romania", "Krassovsky 1940", 28, -121, -77 ); $_datum{"S-JTSK Czechoslavakia"} = Datum->new( "S-JTSK Czechoslavakia", "Bessel 1841", 589, 76, 480 ); $_datum{"Santo (DOS) 1965"} = Datum->new( "Santo (DOS) 1965", "International 1924", 170, 42, 84 ); $_datum{"Sao Braz"} = Datum->new( "Sao Braz", "International 1924", -203, 141, 53 ); $_datum{"Sapper Hill 1943"} = Datum->new( "Sapper Hill 1943", "International 1924", -355, 21, 72 ); $_datum{"Schwarzeck"} = Datum->new( "Schwarzeck", "Bessel 1841 (Namibia)", 616, 97, -251 ); $_datum{"Selvagem Grande 1938"} = Datum->new( "Selvagem Grande 1938", "International 1924", -289, -124, 60 ); $_datum{"Sierra Leone 1960"} = Datum->new( "Sierra Leone 1960", "Clarke 1880", -88, 4, 101 ); $_datum{"South American 1969 Argentina"} = Datum->new( "South American 1969 Argentina", "South American 1969", -62, -1, -37 ); $_datum{"South American 1969 Bolivia"} = Datum->new( "South American 1969 Bolivia", "South American 1969", -61, 2, -48 ); $_datum{"South American 1969 Brazil"} = Datum->new( "South American 1969 Brazil", "South American 1969", -60, -2, -41 ); $_datum{"South American 1969 Chile"} = Datum->new( "South American 1969 Chile", "South American 1969", -75, -1, -44 ); $_datum{"South American 1969 Colombia"} = Datum->new( "South American 1969 Colombia", "South American 1969", -44, 6, -36 ); $_datum{"South American 1969 Ecuador"} = Datum->new( "South American 1969 Ecuador", "South American 1969", -48, 3, -44 ); $_datum{"South American 1969 Ecuador:Baltra/Galapagos"} = Datum->new( "South American 1969 Ecuador:Baltra/Galapagos", "South American 1969", -47, 26, -42 ); $_datum{"South American 1969 Guyana"} = Datum->new( "South American 1969 Guyana", "South American 1969", -53, 3, -47 ); $_datum{"South American 1969 MEAN"} = Datum->new( "South American 1969 MEAN", "South American 1969", -57, 1, -41 ); $_datum{"South American 1969 Paraguay"} = Datum->new( "South American 1969 Paraguay", "South American 1969", -61, 2, -33 ); $_datum{"South American 1969 Peru"} = Datum->new( "South American 1969 Peru", "South American 1969", -58, 0, -44 ); $_datum{"South American 1969 Trinidad/Tobago"} = Datum->new( "South American 1969 Trinidad/Tobago", "South American 1969", -45, 12, -33 ); $_datum{"South American 1969 Venezuela"} = Datum->new( "South American 1969 Venezuela", "South American 1969", -45, 8, -33 ); $_datum{"South Asia"} = Datum->new( "South Asia", "Modified Fischer 1960", 7, -10, -26 ); $_datum{"Southeast Base"} = Datum->new( "Southeast Base", "International 1924", -499, -249, 314 ); $_datum{"Southwest Base"} = Datum->new( "Southwest Base", "International 1924", -104, 167, -38 ); $_datum{"Tananarive Observatory 1925"} = Datum->new( "Tananarive Observatory 1925", "International 1924", -189, -242, -91 ); $_datum{"Timbalai 1948"} = Datum->new( "Timbalai 1948", "Everest (Sabah Sarawak)", -679, 669, -48 ); $_datum{"Tokyo Japan"} = Datum->new( "Tokyo Japan", "Bessel 1841", -148, 507, 685 ); $_datum{"Tokyo MEAN"} = Datum->new( "Tokyo MEAN", "Bessel 1841", -148, 507, 685 ); $_datum{"Tokyo Okinawa"} = Datum->new( "Tokyo Okinawa", "Bessel 1841", -158, 507, 676 ); $_datum{"Tokyo South Korea"} = Datum->new( "Tokyo South Korea", "Bessel 1841", -147, 506, 687 ); $_datum{"Tristan Astro 1968"} = Datum->new( "Tristan Astro 1968", "International 1924", -632, 438, -609 ); $_datum{"Viti Levu 1916"} = Datum->new( "Viti Levu 1916", "Clarke 1880", 51, 391, -36 ); $_datum{"Voirol 1960"} = Datum->new( "Voirol 1960", "Clarke 1880", -123, -206, 219 ); $_datum{"Wake Island Astro 1952"} = Datum->new( "Wake Island Astro 1952", "International 1924", 276, -57, 149 ); $_datum{"Wake-Eniwetok 1960"} = Datum->new( "Wake-Eniwetok 1960", "Hough 1960", 102, 52, -38 ); $_datum{"WGS 72"} = Datum->new( "WGS 72", "WGS 72", 0, 0, 0 ); $_datum{"WGS 84"} = Datum->new( "WGS 84", "WGS 84", 0, 0, 0 ); $_datum{"Yacare"} = Datum->new( "Yacare", "International 1924", -155, 171, 37 ); $_datum{"Zanderij"} = Datum->new( "Zanderij", "International 1924", -265, 120, -358 ); #------------------------------------------------------------------------------------------------ package Coordinate; # # Note that we export NOTHING! This module strives to be object-oriented, # therefore exporting is a bad thing. You can get to any of the public # methods by using normal method calls on an object. # $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; use Math::Trig; #use Math::BigFloat; # Allows arbitrary length floating point operations #use strict; # # Here is a Coordinate object. It contains all of the data # for describing a single point on the earth and the methods # for setting/getting these values. # # # This constructor can be used to create and initialize an object # with Latitude/Longitude/Datum fields. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{LATITUDE} = shift if @_; $self->{LONGITUDE} = shift if @_; $self->{DATUM} = shift if @_; } # # This constructor can be used to create and initialize an object # with easting/northing/zone/datum fields (UTM grid). # sub new_utm { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init_utm(@_); # Call _init with remaining args return $self; } sub _init_utm { my $self = shift; $self->{EASTING} = shift if @_; $self->{NORTHING} = shift if @_; $self->{ZONE} = shift if @_; $self->{DATUM} = shift if @_; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub latitude { my $self = shift; $self->{LATITUDE} = shift if @_; return $self->{LATITUDE}; } sub longitude { my $self = shift; $self->{LONGITUDE} = shift if @_; return $self->{LONGITUDE}; } sub formatted_latitude { my $self = shift; $self->{FORMATTED_LATITUDE} = shift if @_; return $self->{FORMATTED_LATITUDE}; } sub formatted_longitude { my $self = shift; $self->{FORMATTED_LONGITUDE} = shift if @_; return $self->{FORMATTED_LONGITUDE}; } sub easting { my $self = shift; $self->{EASTING} = shift if @_; return $self->{EASTING}; } sub northing { my $self = shift; $self->{NORTHING} = shift if @_; return $self->{NORTHING}; } sub zone { my $self = shift; $self->{ZONE} = shift if @_; return $self->{ZONE}; } sub datum { my $self = shift; $self->{DATUM} = shift if @_; return $self->{DATUM}; } # # Converts lat/lon to UTM coordinates. Equations from USGS Bulletin 1532 # (According to comments in the original C code). # # East Longitudes are positive, West are negative. # North latitudes are positive, South are negative. # Latitude and longitude are in decimal degrees. # # This method fills in the Easting/Northing/Zone fields in the object. # The Zone field will look something like: "10U" when filled in. # sub lat_lon_to_utm { my $position = shift; # Snag the pointer to the object. my $PI = 3.14159265358979323846; my $deg_2_rad = $PI / 180; my $k0 = 0.9996; # First get the datum used in the position from the object: my $datum = $position->datum(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); # Do a lookup in the $ellipsoid{} hash to find the Radius value. my $a = EllipsoidTable->equatorial_radius( $ellipsoid ); # Do a lookup in the $ellipsoid{} hash to find the Ecc value. my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid ); my $Lat = $position->latitude(); my $Long = $position->longitude(); # Make sure the longitude is between -180.00 .. 179.9 my $Long_Temp = ($Long+180)-int(($Long+180)/360)*360-180; # -180.00 .. 179.9; my $Lat_Rad = $Lat * $deg_2_rad; my $Long_Rad = $Long_Temp * $deg_2_rad; my $Zone_Number = int(($Long_Temp + 180)/6) + 1; if( $Lat >= 56.0 && $Lat < 64.0 && $Long_Temp >= 3.0 && $Long_Temp < 12.0 ) { $Zone_Number = 32; } # Special zones for Svalbard if( $Lat >= 72.0 && $Lat < 84.0 ) { if( $Long_Temp >= 0.0 && $Long_Temp < 9.0 ) { $Zone_Number = 31 } elsif( $Long_Temp >= 9.0 && $Long_Temp < 21.0 ) { $Zone_Number = 33 } elsif( $Long_Temp >= 21.0 && $Long_Temp < 33.0 ) { $Zone_Number = 35 } elsif( $Long_Temp >= 33.0 && $Long_Temp < 42.0 ) { $Zone_Number = 37 }; } my $Long_Origin = ($Zone_Number - 1)*6 - 180 + 3; # +3 puts origin in middle of zone my $Long_Origin_Rad = $Long_Origin * $deg_2_rad; # Compute the UTM Zone from the latitude and longitude # NOTE: Need to check for out-of-range here. # my $Zone_Letter = &_utm_letter_designator($Lat); #printf( "Zone_Number: %d\t\tZone_Letter: %s\n", $Zone_Number, $Zone_Letter ); my $UTM_Zone = sprintf( "%d%s", $Zone_Number, $Zone_Letter ); my $ecc_Prime_Squared = ($ecc_Squared)/(1-$ecc_Squared); my $N = $a/sqrt(1-$ecc_Squared*sin($Lat_Rad)*sin($Lat_Rad)); my $T = tan($Lat_Rad) * tan($Lat_Rad); my $C = $ecc_Prime_Squared * cos($Lat_Rad) * cos($Lat_Rad); my $A = cos($Lat_Rad) * ($Long_Rad-$Long_Origin_Rad); my $M = $a * ((1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256) * $Lat_Rad - (3 * $ecc_Squared/8 + 3 * $ecc_Squared * $ecc_Squared/32 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(2 * $Lat_Rad) + (15 * $ecc_Squared * $ecc_Squared/256 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(4 * $Lat_Rad) - (35 * $ecc_Squared * $ecc_Squared * $ecc_Squared/3072) * sin(6 * $Lat_Rad)); my $UTM_Easting = ($k0 * $N * ($A + (1 - $T + $C) * $A * $A * $A/6 + (5 - 18 * $T + $T * $T + 72 * $C - 58 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A/120) + 500000.0); my $UTM_Northing = ($k0 * ($M + $N * tan($Lat_Rad) * ($A * $A/2 + (5 - $T + 9 * $C + 4 * $C * $C) * $A * $A * $A * $A/24 + (61 - 58 * $T + $T * $T + 600 * $C - 330 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A * $A/720))); if($Lat < 0) { $UTM_Northing += 10000000.0; # 10000000 meter offset for southern hemisphere } # Write the results back to our position object $position->easting( $UTM_Easting ); $position->northing( $UTM_Northing ); $position->zone( $UTM_Zone ); return(1); } # # This routine determines the correct UTM letter designator for the given latitude. # Returns 'Z' if latitude is outside the UTM limits of 84N to 80S. # # Note that this is a normal subroutine, not an object method. It is to # be used inside this module only and is not exported. # sub _utm_letter_designator { my $Lat = shift; my $Letter_Designator; if (( 84 >= $Lat) && ($Lat >= 72)) { $Letter_Designator = 'X' } elsif (( 72 > $Lat) && ($Lat >= 64)) { $Letter_Designator = 'W' } elsif (( 64 > $Lat) && ($Lat >= 56)) { $Letter_Designator = 'V' } elsif (( 56 > $Lat) && ($Lat >= 48)) { $Letter_Designator = 'U' } elsif (( 48 > $Lat) && ($Lat >= 40)) { $Letter_Designator = 'T' } elsif (( 40 > $Lat) && ($Lat >= 32)) { $Letter_Designator = 'S' } elsif (( 32 > $Lat) && ($Lat >= 24)) { $Letter_Designator = 'R' } elsif (( 24 > $Lat) && ($Lat >= 16)) { $Letter_Designator = 'Q' } elsif (( 16 > $Lat) && ($Lat >= 8)) { $Letter_Designator = 'P' } elsif (( 8 > $Lat) && ($Lat >= 0)) { $Letter_Designator = 'N' } elsif (( 0 > $Lat) && ($Lat >= -8)) { $Letter_Designator = 'M' } elsif (( -8 > $Lat) && ($Lat >= -16)) { $Letter_Designator = 'L' } elsif ((-16 > $Lat) && ($Lat >= -24)) { $Letter_Designator = 'K' } elsif ((-24 > $Lat) && ($Lat >= -32)) { $Letter_Designator = 'J' } elsif ((-32 > $Lat) && ($Lat >= -40)) { $Letter_Designator = 'H' } elsif ((-40 > $Lat) && ($Lat >= -48)) { $Letter_Designator = 'G' } elsif ((-48 > $Lat) && ($Lat >= -56)) { $Letter_Designator = 'F' } elsif ((-56 > $Lat) && ($Lat >= -64)) { $Letter_Designator = 'E' } elsif ((-64 > $Lat) && ($Lat >= -72)) { $Letter_Designator = 'D' } elsif ((-72 > $Lat) && ($Lat >= -80)) { $Letter_Designator = 'C' } else { $Letter_Designator = 'Z' }; # An error flag: Latitude is outside UTM limits return $Letter_Designator; } # # Converts UTM coordinates to lat/lon. Equations from USGS Bulletin 1532. # East longitudes are positive, West are negative. # North latitudes are positive, South are negative. # Latitude and longitude are in decimal degrees. # Zone should look something like: "10U" before starting the conversion. # sub utm_to_lat_lon { my $position = shift; # Input is in the form of a "Coordinate" object my $PI = 3.14159265358979323846; my $rad_2_deg = 180.0 / $PI; my $k0 = 0.9996; # First get the datum used in the position from the object: my $datum = $position->datum(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); # Do a lookup in the $ellipsoid{} hash to find the Radius value. my $a = EllipsoidTable->equatorial_radius( $ellipsoid ); # Do a lookup in the $ellipsoid{} hash to find the Ecc value. my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid ); my $x = $position->easting(); my $y = $position->northing(); my $Zone_Letter = $position->zone(); my $Zone_Number = $Zone_Letter; $Zone_Number =~ s/(\d+).*/$1/; # Convert to an integer my $e1 = (1-sqrt(1-$ecc_Squared))/(1+sqrt(1-$ecc_Squared)); $Zone_Letter =~ s/\d+(\w)/$1/; # Convert UTM zone to just a letter #print "$Zone_Letter\n\n"; my $Northern_Hemisphere; # 1 for northern hemisphere, 0 for southern $x = $x - 500000.0; # Remove 500,000 meter offset for longitude $y = $y; if(($Zone_Letter ge 'N')) { $Northern_Hemisphere = 1; # 'N' or higher is in the northern hemisphere #print "Northern Hemisphere\n"; } else { $Northern_Hemisphere = 0; # Point is in southern hemisphere $y -= 10000000.0; # Remove 10,000,000 meter offset used for southern hemisphere #print "Southern Hemisphere\n"; } #print "Zone_Number: $Zone_Number\n"; my $Long_Origin = ($Zone_Number - 1) * 6 - 180 + 3; # +3 puts origin in middle of zone my $ecc_Prime_Squared = ($ecc_Squared)/(1 - $ecc_Squared); my $M = $y / $k0; my $mu = $M/($a * (1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256)); my $phi1_Rad = $mu + (3 * $e1/2 - 27 * $e1 * $e1 * $e1/32) * sin(2 * $mu) + (21 * $e1 * $e1/16 - 55 * $e1 * $e1 * $e1 * $e1/32) * sin(4 * $mu) +(151 * $e1 * $e1 * $e1/96) * sin(6 * $mu); my $phi1 = $phi1_Rad * $rad_2_deg; my $N1 = $a/sqrt(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad)); my $T1 = tan($phi1_Rad) * tan($phi1_Rad); my $C1 = $ecc_Prime_Squared * cos($phi1_Rad) * cos($phi1_Rad); my $R1 = $a * (1 - $ecc_Squared)/(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad)**1.5); my $D = $x/($N1 * $k0); $Lat = $phi1_Rad - ($N1 * tan($phi1_Rad)/$R1) * ($D * $D/2 - (5 + 3 * $T1 + 10 * $C1 - 4 * $C1 * $C1 - 9 * $ecc_Prime_Squared) * $D * $D * $D * $D/24 +(61 + 90 * $T1 + 298 * $C1 + 45 * $T1 * $T1 - 252 * $ecc_Prime_Squared - 3 * $C1 * $C1) * $D * $D * $D * $D * $D * $D/720); $Lat = $Lat * $rad_2_deg; $Long = ($D - (1 + 2 * $T1 + $C1) * $D * $D * $D/6 + (5 - 2 * $C1 + 28 * $T1 - 3 * $C1 * $C1 + 8 * $ecc_Prime_Squared + 24 * $T1 * $T1) *$D * $D * $D * $D * $D/120)/cos($phi1_Rad); $Long = $Long_Origin + $Long * $rad_2_deg; # Write the results back to our position object $position->latitude( $Lat ); $position->longitude( $Long ); return(1); } # # Function to convert latitude and longitude in decimal degrees between WGS 84 and # another datum. The arguments to this function are a Coordinate object ($position) # and a direction flag ($from_WGS84). The Datum you're translating to/from is # stored in the Datum() field of the object (the other Datum is by default WGS 84). # sub _datum_shift { my $position = shift; # This is our position object my $from_WGS84 = shift; # If 1, then we're converting from WGS 84 # to the datum listed in the position object # If 0, we're going the other way. my $PI = 3.14159265358979323846; my $rad_2_deg = 180.0 / $PI; my $deg_2_rad = $PI / 180; #printf("%s\n", $position->datum() ); my $datum = $position->datum(); # Snag the parameters from the position object # (Get the "other" datum). my $latitude = $position->latitude(); my $longitude = $position->longitude(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); my $dx = DatumTable->dx($datum); # Grab the parameters for the "other" datum. my $dy = DatumTable->dy($datum); # Offsets between "other" datum and WGS84 my $dz = DatumTable->dz($datum); # ellipsoid centers. #print "$dx\t$dy\t$dz\n"; my $WGS_a = EllipsoidTable->equatorial_radius("WGS 84"); # WGS 84 semimajor axis my $WGS_inv_f = EllipsoidTable->inverse_flattening("WGS 84"); # WGS 84 1/f my $phi = $latitude * $deg_2_rad; my $lambda = $longitude * $deg_2_rad; my ($a0, $b0, $es0, $f0); # Reference ellipsoid of input data my ($a1, $b1, $es1, $f1); # Reference ellipsoid of output data my $psi; # geocentric latitude my ($x, $y, $z); # 3D coordinates with respect to original datum my $psi1; # transformed geocentric latitude if ($datum eq "WGS 84") # do nothing if current datum is WGS 84 { return(1); } if ($from_WGS84) # convert from WGS 84 to new datum { $a0 = $WGS_a; # WGS 84 semimajor axis $f0 = 1.0 / $WGS_inv_f; # WGS 84 flattening $a1 = EllipsoidTable->equatorial_radius($ellipsoid); $f1 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid); } else # convert from old datum to WGS 84 { $a0 = EllipsoidTable->equatorial_radius($ellipsoid); # semimajor axis $f0 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid); # flattening $a1 = $WGS_a; # WGS 84 semimajor axis $f1 = 1 / $WGS_inv_f; # WGS 84 flattening $dx = -$dx; $dy = -$dy; $dz = -$dz; } $b0 = $a0 * (1 - $f0); # semiminor axis for input datum $es0 = 2 * $f0 - $f0*$f0; # eccentricity^2 $b1 = $a1 * (1 - $f1); # semiminor axis for output datum $es1 = 2 * $f1 - $f1*$f1; # eccentricity^2 # Convert geodedic latitude to geocentric latitude, psi if ($latitude == 0.0 || $latitude == 90.0 || $latitude == -90.0) { $psi = $phi; } else { $psi = atan((1 - $es0) * tan($phi)); } # Calculate x and y axis coordinates with respect to the original ellipsoid if ($longitude == 90.0 || $longitude == -90.0) { $x = 0.0; $y = abs($a0 * $b0 / sqrt($b0*$b0 + $a0*$a0* ( tan($psi)**2.0) ) ); } else { $x = abs(($a0 * $b0) / sqrt( (1 + (tan($lambda)**2.0) ) * ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) ) ); $y = abs($x * tan($lambda)); } if ($longitude < -90.0 || $longitude > 90.0) { $x = -$x; } if ($longitude < 0.0) { $y = -$y; } # Calculate z axis coordinate with respect to the original ellipsoid if ($latitude == 90.0) { $z = $b0; } elsif ($latitude == -90.0) { $z = -$b0; } else { $z = tan($psi) * sqrt( ($a0*$a0 * $b0*$b0) / ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) ); } # Calculate the geocentric latitude with respect to the new ellipsoid $psi1 = atan(($z - $dz) / sqrt(($x - $dx)*($x - $dx) + ($y - $dy)*($y - $dy))); # Convert to geocentric latitude and save return value $latitude = atan(tan($psi1) / (1 - $es1)) * $rad_2_deg; # Calculate the longitude with respect to the new ellipsoid $longitude = atan(($y - $dy) / ($x - $dx)) * $rad_2_deg; # Correct the resultant for negative x values if ($x-$dx < 0.0) { if ($y-$dy > 0.0) { $longitude = 180.0 + $longitude; } else { $longitude = -180.0 + $longitude; } } # Write the results back to our position object $position->latitude($latitude); $position->longitude($longitude); if (! $from_WGS84) # If we're converting to WGS 84 datum { $position->datum( "WGS 84" ); # Change the datum to correspond to # the new data in the object } #print "New one: $latitude, $longitude\n"; return(1); } # # Method to convert latitude and longitude in decimal degrees from another # datum to WGS 84. The only argument to this method is a Coordinate object # with the lat/lon/datum fields filled in. # # This method returns a NEW Coordinate object with lat/lon/datum fields # filled in and the other fields empty. The original object is not changed. # sub datum_shift_to_wgs84 { my $old_position = shift; # This is our original position object my $to_WGS84 = 0; # Create a new object and fill in a few fields my $new_position = Coordinate->new( $old_position->latitude(), $old_position->longitude(), $old_position->datum() ); &_datum_shift( $new_position, $to_WGS84 ); return( $new_position ); # Return the datum-shifted object } # # Method to convert latitude and longitude in decimal degrees from WGS 84 to # another datum. The arguments to this method are a Coordinate object # with the lat/lon/datum fields filled in (the datum field must be "WGS 84"), # AND a datum (string) to shift to. # # This method returns a NEW Coordinate object with lat/lon/datum fields # filled in. The original object is not changed. # sub datum_shift_from_wgs84_to { my $old_position = shift; # This is our original position object my $new_datum = shift; # The datum we wish to shift to my $from_WGS84 = 1; # Create a new object and fill in a few fields my $new_position = Coordinate->new( $old_position->latitude(), $old_position->longitude(), $new_datum ); &_datum_shift( $new_position, $from_WGS84 ); return( $new_position ); # Return the datum-shifted object } # # Degrees and Decimal Minutes # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub degrees_minutes { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->degrees_minutes() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->degrees_minutes() ); # process it & fill in our finished string return(1); } # # Degrees/Minutes/Seconds # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub degrees_minutes_seconds { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create the temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string return(1); } # # Decimal Degrees # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub decimal_degrees { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create the temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->decimal_degrees() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->decimal_degrees() ); # Process it & fill in our finished string return(1); } #------------------------------------------------------------------------------------------------ # # Auto-run code # # This code will get run automatically whenever this file gets "required" # or "used" in another Perl program. # 1; # Needed to prevent exception when loading this module Xastir-Release-2.2.2/scripts/LSB-BUILD000077500000000000000000000127341501463444000172470ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # TODO: # Check for a link at /opt/Xastir/share/xastir. If found, remove it # until we're done creating the .tar.bz2 file. Perhaps do an rm -rf # there and symlink it to /usr/local/share/xastir when done. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # # The trick: First compile Lesstif as an LSB package, installed at # /opt/lsb-tmp, using LSB-BUILD-LESSTIF script. The commands # below assume you've set up the directory structure at /opt/lsb # specified at the top of that script. # # We should have /opt/lsb/lib.orig & /opt/lsb/lib.lesstif # directories at this point along with a symlink from /opt/lsb/lib # -> lib.lesstif: # # cd /opt/lsb # cp -R lib.orig lib.xastir # rm lib (remove the symlink we created before) # ln -s lib.xastir lib (link to the new directory) # cd lib # rm libXt.so (or just "chmod 000 libXt.so") # rm libz.so (or just "chmod 000 libz.so") # cp /home/src/lsb/libXt.a . (lib from LSB CVS: "lsb/appbat" module) # ln -s /opt/lsb-tmp/lib/libXm.a (from our Lesstif compile) # ln -s /opt/lsb-tmp/lib/libz.a # ln -s /opt/lsb-tmp/lib/libjpeg.a # ln -s /opt/lsb-tmp/lib/libpcre.a # ln -s /opt/lsb-tmp/lib/libcurl.a # ln -s /usr/local/lib/libtiff.a # ln -s /usr/local/lib/libproj.a # ln -s /usr/local/lib/libgeotiff.a # ln -s /opt/lsb-tmp/lib/libpng.a # ln -s /opt/lsb-tmp/lib/libjasper.a # ln -s /opt/lsb-tmp/lib/libGraphicsMagick.a libMagick.a # ln -s /opt/lsb-tmp/lib/libdb.a # ln -s /opt/lsb-tmp/lib/libXpm.a # # cd /opt/lsb # cp -R include include.xastir # mv include include.orig # ln -s include.xastir include (link to the new directory) # cd include # ln -s /opt/lsb-tmp/include/Xm (from our Lesstif compile) # ln -s /opt/lsb-tmp/include/pcre.h # ln -s /opt/lsb-tmp/include/curl # ln -s /opt/lsb-tmp/include/png.h # ln -s /opt/lsb-tmp/include/jasper # rm zlib.h # ln -s /opt/lsb-tmp/include/zlib.h # ln -s /opt/lsb-tmp/include/zconf.h # ln -s /opt/lsb-tmp/include/GraphicsMagick/magick # ln -s /opt/lsb-tmp/include/db.h # mkdir X11 # cd X11 # ln -s /opt/lsb-tmp/include/Xm/xpm.h # This will allow us to statically link libraries without mucking # around with the Makefiles. When done compiling the LSB-Xastir # package, put the /opt/lsb/lib directory back to normal by issuing # these commands: # # cd /opt/lsb # rm lib include (remove the symlinks) # ln -s lib.orig lib (link back to the original directory) # ln -s include.orig include (link back to the original directory) # REV="2.0.8" FILENAME=`date +xastir-lsb-$REV-%Y-%b-%d.tar.bz2` # Remove old versions of the package rm xastir-lsb-*.bz2 ./bootstrap.sh export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS=libXm.so CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/Xastir \ --without-ax25 \ --with-festival \ --without-gpsman \ --with-graphicsmagick \ --with-proj \ --with-geotiff \ --without-gdal \ --with-internal-shapelib \ --with-pcre \ --with-dbfawk \ --with-map_cache \ --with-rtree \ --with-lsb make clean find . -type f -name Makefile -print | while read i do sed -i 's@/usr/include@/opt/lsb/include@g' $i sed -i 's@/usr/local/include@/opt/lsb/include@g' $i sed -i 's@/usr/X11R6/include@/opt/lsb/include@g' $i sed -i 's@/usr/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/X11R6/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/X11/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/X11/include@/opt/lsb/include@g' $i sed -i 's@/usr/local/lib@/opt/lsb/lib@g' $i done (make 2>&1) | tee make.log strip src/xastir strip src/xastir_udp_client strip src/testdbfawk strip callpass/callpass # Get rid of the LSB-Xastir install files so that we get a clean # install each time to make the .tar.bz2 file from. echo Removing /opt/Xastir/ sudo /bin/rm -rf /opt/Xastir (sudo make install 2>&1) | tee install.log # Copy GraphicsMagick "gm" binary to the Xastir area sudo /bin/cp /opt/lsb-tmp/bin/gm /opt/Xastir/bin/. #(lsbappchk -nA /opt/Xastir/bin/xastir 2>&1) | grep -v SHT_NOTE #(lsbappchk -nA /opt/Xastir/bin/callpass 2>&1) | grep -v SHT_NOTE #(lsbappchk -nA /opt/Xastir/bin/xastir_udp_client 2>&1) | grep -v SHT_NOTE #(lsbappchk -nA /opt/Xastir/bin/gm 2>&1) | grep -v SHT_NOTE (lsbappchk -n /opt/Xastir/bin/xastir 2>&1) | grep -v SHT_NOTE (lsbappchk -n /opt/Xastir/bin/callpass 2>&1) | grep -v SHT_NOTE (lsbappchk -n /opt/Xastir/bin/xastir_udp_client 2>&1) | grep -v SHT_NOTE (lsbappchk -n /opt/Xastir/bin/gm 2>&1) | grep -v SHT_NOTE tar cjf $FILENAME /opt/Xastir # Remove old versions of the package from the ftp site #ssh eskimo rm ftp/aprs/xastir/LSB/xastir-lsb* # Upload the latest version scp xastir-lsb-$REV-* eskimo:ftp/aprs/xastir/LSB/. # Fix the permissions so that people can download the file ssh eskimo chmod 644 ftp/aprs/xastir/LSB/* Xastir-Release-2.2.2/scripts/LSB-BUILD-ALL000077500000000000000000000063461501463444000176570ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # # Compile the optional libraries that Xastir can use under Linux # Standard Base 3.0, in the proper compile order. # # These are the files needed: # # curl-7.16.0.tar.gz # db-4.4.20.tar.gz # gdal-1.3.2b2.tar.gz ###### GraphicsMagick-1.1.7.tar.bz2 # GraphicsMagick-1.1.11.tar.bz2 # jasper-1.701.0.zip # jpegsrc.v6b.tar.gz ####### lesstif-0.94.4.tar.gz # lesstif-0.95.0.tar.gz # libpng-1.2.14.tar.gz # libXt.a # pcre-6.7.tar.gz # zlib-1.2.3.tar.gz # # Run this from the /home/src/lsb/ directory, and have the above # files present there. This script needs SUDO access to install # files as well. # ALSO: Create this symlink to get rid of some compiler errors # below, mostly when libtool is trying to use lsbcc: # # /usr/bin/lsbcc -> /opt/lsb/bin/lsbcc # cd /home/src/lsb tar xzf zlib-1.2.3.tar.gz (cd zlib-1.2.3; ../LSB-BUILD-ZLIB) rm -rf zlib-1.2.3 tar xzf jpegsrc.v6b.tar.gz (cd jpeg-6b; ../LSB-BUILD-JPEG) rm -rf jpeg-6b tar xzf db-4.4.20.tar.gz (cd db-4.4.20; ../LSB-BUILD-DB) rm -rf db-4.4.20 tar xzf curl-7.16.0.tar.gz (cd curl-7.16.0; ../LSB-BUILD-CURL) rm -rf curl-7.16.0 # Shows an error creating a shared library but installs the static # library we need before it errors out... (libjasper.a) # If I make a symlink: "/usr/bin/lsbcc -> /opt/lsb/bin/lsbcc", no # more error... #unzip -q jasper-1.701.0.zip #(cd jasper-1.701.0; ../LSB-BUILD-JASPER) #rm -rf jasper-1.701.0 tar xzf libpng-1.2.14.tar.gz (cd libpng-1.2.14; ../LSB-BUILD-PNG) rm -rf libpng-1.2.14 tar xzf pcre-6.7.tar.gz (cd pcre-6.7; ../LSB-BUILD-PCRE) rm -rf pcre-6.7 ## ##tar xzf lesstif-0.94.4.tar.gz ##(cd lesstif-0.94.4; ../LSB-BUILD-LESSTIF) ##rm -rf lesstif-0.94.4 ## # Shows an error but installs the static library we need before it # errors out... (libXm.a) tar xzf lesstif-0.95.0.tar.gz (cd lesstif-0.95.0; ../LSB-BUILD-LESSTIF) rm -rf lesstif-0.95.0 # Shows an error creating a shared library but installs the static # library we need before it errors out... (not true anymore!!!) tar xjf GraphicsMagick-1.1.7.tar.bz2 (cd GraphicsMagick-1.1.7; ../LSB-BUILD-GRAPHICSMAGICK) rm -rf GraphicsMagick-1.1.7 # PROBLEM HERE ##tar xzf gdal-1.3.2b2.tar.gz ##(cd gdal-1.3.2b2; ../LSB-BUILD-GDAL) ##rm -rf gdal-1.3.2b2 # Create the links needed in /opt/lsb/lib.xastir and # /opt/lsb/lib.include directories Xastir-Release-2.2.2/scripts/LSB-BUILD-CURL000077500000000000000000000023061501463444000200040ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # Compile curl-7.16.0 under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-ldap \ --without-libidn \ --disable-shared make clean (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-DB000077500000000000000000000022701501463444000175240ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile Berkely db-4.4.20 under Linux Standard Base 3.0. Install # into /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= cd build_unix CC=lsbcc CXX=lsbc++ ../dist/configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-shared make clean (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-GDAL000077500000000000000000000043421501463444000177500ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile gdal-1.3.2b2 under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= # Change "export *" to "const std::exception &e" sed -i -e 's/exception\*/const std::exception \&e/g' frmts/ilwis/ilwisdataset.cpp CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-gdal \ --exec_prefix=/opt/lsb-gdal \ --oldincludedir=/opt/lsb/include \ --disable-shared \ --without-ld-shared \ --enable-static \ --with-static-proj4 \ --with-threads \ --without-pcraster \ --without-pg \ --without-python \ --without-ngpyton \ --without-netcdf \ --without-png \ --without-jpeg \ --without-gif \ --without-jasper \ --without-perl \ --without-libz # --without-libtiff \ # --without-geotiff \ # --without-libtool \ make clean find . -type f -name Makefile -print | while read i do sed -i 's@/usr/include@/opt/lsb/include@g' $i sed -i 's@/usr/local/include@/opt/lsb/include@g' $i sed -i 's@/usr/X11R6/include@/opt/lsb/include@g' $i sed -i 's@/usr/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/local/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/X11R6/lib@/opt/lsb/lib@g' $i sed -i 's@/usr/X11/lib@/opt/lsb/lib@g' $i done sed -i 's@/usr/lib@/opt/lsb/lib@g' libgdal.la sed -i 's@/usr/local/lib@/opt/lsb/lib@g' libgdal.la (make 2>&1) | tee make.log #make -n install #(sudo make install 2>&1) | tee install.log Xastir-Release-2.2.2/scripts/LSB-BUILD-GRAPHICSMAGICK000077500000000000000000000050271501463444000213160ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile GraphicsMagick-1.1.7 under Linux Standard Base 3.0. # Install into /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # # # We need these additional libraries before compiling # GraphicsMagick: # # ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz # http://www.libpng.org/pub/png/pngcode.html # ftp://ftp.remotesensing.org/libtiff/ # http://www.gzip.org/zlib/ # http://www.ece.uvic.ca/~mdadams/jasper/ export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= # Change freetype2 to LSB include directory in configure. sed -i -e 's@{freetype_prefix}/include/freetype2@/opt/lsb/include@g' configure # Remove "-std=gnu99 -c99" from configure else we'll get a some # libraries compiled in that we don't wish 'cuz the lsbcc compiler # won't get used. sed -i -e 's/-std=gnu99 -c99//g' configure CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-shared \ --without-magick-plus-plus \ --without-perl \ --x-libraries=/opt/lsb/lib \ --without-x \ --enable-libtool-verbose \ --enable-maintainer-mode \ --without-freetype \ --without-freetype2 \ --without-gslib \ --with-quantum-depth=16 # --disable-installed make clean (CPPFLAGS="-I/opt/lsb/include" LDFLAGS="/opt/lsb/lib" make 2>&1) | tee make.log #CPPFLAGS="-I/opt/lsb/include" LDFLAGS="/opt/lsb/lib" make -n install CPPFLAGS="-I/opt/lsb/include" LDFLAGS="/opt/lsb/lib" sudo make install # The Make has bombed out at this point, so finish the compile of # "gm" in the utilities directory (cd utilities; \ /opt/lsb/bin/lsbcc -g -O2 -Wall -o gm gm.o \ ../magick/.libs/libGraphicsMagick.a \ -L/opt/lsb/lib -ltiff -ljasper -lpng -lz -lm -lpthread -ljpeg; \ strip gm; \ sudo make install) Xastir-Release-2.2.2/scripts/LSB-BUILD-JASPER000077500000000000000000000022571501463444000202300ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile jasper-1.701.0 under Linux Standard Base 3.0. Install # into /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-shared make clean (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-JPEG000077500000000000000000000023041501463444000177620ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile jpeg-6b under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static make clean (make 2>&1) | tee make.log #sudo mkdir /opt/lsb-tmp /opt/lsb-tmp/lib /opt/lsb-tmp/include #make -n install-lib sudo make install-lib Xastir-Release-2.2.2/scripts/LSB-BUILD-LESSTIF000077500000000000000000000060041501463444000203470ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile lesstif-0.95.0 under Linux Standard Base 3.0. Install # into /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # # In order to build Lesstif on LSB we need a static version of the # LSB libXt.so library, called libXt.a. To get this, we must # compile the "lsb/appbat" portion of LSB-CVS and snag the library # out of there. We can then copy it or symlink it into /opt/lsb/lib # and change permissions on /opt/lsb/lib/libXt.so so that it's # unreadable. We'll get the static version of libXt compiled in to # our app that way. Put the .so back and disable the .a when we're # done compiling Lesstif and Xastir so that the LSB runtime is # intact. # # Actual method used: # # cd /opt/lsb # cp -R lib lib.lesstif # mv lib lib.orig # ln -s lib.lesstif lib # cd lib # rm libXt.so (or just "chmod 000 libXt.so") # ln -s PATH/libXt.a (from LSB "appbat") # # This makes it easy to switch back to the default library setup by # changing the /opt/lsb/lib symlink. # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= # Patches to the Lesstif source code: # # Edit lib/Xm/ImageCache.c: Change "_XInitImageFuncPtrs" to # "XInitImage" in two places, then comment out the first instance: sed -i -e 's/_XInitImageFuncPtrs/XInitImage/g' lib/Xm-2.1/ImageCache.c sed -i -e 's/^extern void XInitImage/\/\/extern void XInitImage/g' lib/Xm-2.1/ImageCache.c # # Comment out the sighandler_t line in lib/Xm/DebugUtil.c: sed -i -e 's/^typedef void ..sighandler_t/\/\/typedef void (*sighandler_t/' lib/Xm-2.1/DebugUtil.c CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --enable-static \ --x-libraries=/opt/lsb/lib \ --x-includes=/opt/lsb/include \ --with-motif-includes=/opt/lsb/include \ --with-motif-libraries=/opt/lsb/lib \ --disable-shared make clean find . -type f -name Makefile -print | while read i do sed -i 's@/usr/include@opt/lsb/include@g' $i sed -i 's@/usr/local/include@opt/lsb/include@g' $i sed -i 's@/usr/X11R6/include@opt/lsb/include@g' $i sed -i 's@/usr/lib@opt/lsb/lib@g' $i sed -i 's@/usr/local/lib@opt/lsb/lib@g' $i sed -i 's@/usr/X11R6/lib@opt/lsb/lib@g' $i sed -i 's@/usr/X11/lib@opt/lsb/lib@g' $i done (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-PCRE000077500000000000000000000022561501463444000177740ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile pcre-6.7 under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= #CC=lsbcc CXX=lsbc++ ./configure \ CC=lsbcc ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-shared make clean (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-PNG000077500000000000000000000022601501463444000176620ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile libpng-1.2.14 under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static \ --disable-shared make clean (make 2>&1) | tee make.log #make -n install sudo make install Xastir-Release-2.2.2/scripts/LSB-BUILD-ZLIB000077500000000000000000000023761501463444000200060ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2000-2023 The Xastir Group # # Compile zlib-1.2.3 0 under Linux Standard Base 3.0. Install into # /opt/lsb-tmp/ directory structure. # NOTE: # "Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries." # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # export PATH=${PATH}:/opt/lsb/bin export LSBCC_WARN=1 # A colon-separated list of "extra" shared libraries to link with # the application. Each shared lib must be LSB-compliant and must # be distributed along with the application. #export LSBCC_SHAREDLIBS= # Patches to the source code: # sed -i -e 's/\$exec_prefix#/$prefix#/g' configure CC=lsbcc CXX=lsbc++ ./configure \ --prefix=/opt/lsb-tmp \ --exec_prefix=/opt/lsb-tmp \ --enable-static make clean (make 2>&1) | tee make.log #make -n install prefix=/opt/lsb-tmp sudo make install prefix=/opt/lsb-tmp Xastir-Release-2.2.2/scripts/Makefile.am000066400000000000000000000016461501463444000201000ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # scriptsdir=${pkgdatadir}/scripts dist_scripts_DATA = \ ads-b.pl \ ais.pl \ ais_pp.pl \ Coordinate.pm \ coord-convert.pl \ geopdf2gtiff.pl \ get-BOMdata \ get-fcc-rac.pl \ get-gnis \ get-NWSdata \ gpx2shape \ icontable.pl \ inf2geo.pl \ kiss-off.pl \ langElmerFudd.pl \ langMuppetsChef.pl \ langOldeEnglish.pl \ langPigLatin.pl \ langPirateEnglish.pl \ mapblast2geo.pl \ mapfgd.pl \ object2shp.pl \ overlay.pl \ ozi2geo.pl \ permutations.pl \ pos2shp.pl \ ridge_radar.pl \ slideshow.pl \ split_gnis.bash \ split_gnis.pl \ test_coord.pl \ toporama50k.pl \ toporama250k.pl\ track-get.pl \ update_langfile.pl \ waypoint-get.pl \ wms.pl \ wxnowsrv.pl install-data-hook: cd $(DESTDIR)$(scriptsdir) && \ chmod a+x *.pl get-* gpx2* *.bash Xastir-Release-2.2.2/scripts/UIView2XastirLog.pl000077500000000000000000000031271501463444000214670ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # Script to convert a UI-View log file to an Xastir log file. # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # NOTE: Run it against an input file and tell it where to put the # output: # # ./UIView2XastirLog.pl output_file.log # # No timestamp info is converted or saved by this script. while (<>) { chomp; if (m/START UTC/) { # Skip it next; } # If line starts with date field, chop off the date, time1, # time2 fields. # if (m/^\d\d\d\d\-\d\d\-\d\d\s.*/) { s/^\d\d\d\d\-\d\d\-\d\d\s+\d\d\:\d\d:\d\d\s+\d\d\:\d\d:\d\dR//; # Get rid of " " s/\s\:\r/:/; # Save current line $temp = $_; # Read next line $_ = <>; chomp; # Concatenate the two $temp = $temp . $_ . "\n"; print $temp; } } Xastir-Release-2.2.2/scripts/XastirGitStamp.sh000077500000000000000000000006671501463444000213300ustar00rootroot00000000000000#!/bin/sh #This script prints the short-format git SHA-1 string if the source directory # has a ".git" directory. # # This will typically only be called from a Makefile, with $(top_srcdir) as the # first argument. Its purpose is so we can inject the git commit ID # into the "Help->About" dialog box. SRCDIR=$1 SHASTRING="" cd $SRCDIR if [ -e .git ] then GITSHA=`git describe --dirty` SHASTRING=" (${GITSHA})" fi echo $SHASTRING Xastir-Release-2.2.2/scripts/ads-b.pl000077500000000000000000003103161501463444000173670ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2023 The Xastir Group # # Converts "dump1090" telnet port output to Xastir UDP input, for decoding # packets directly from aircraft. This script will parse packets containing # lat/long, turn them into APRS-like packets, then use "xastir_udp_client" # to inject them into Xastir. Must have "dump1090" running, and optionally # "dump978" to dump packets into "dump1090" from the other frequency/protocol # for ADS-B. # # # TODO: Create probability circle around my position for aircraft sending altitude # but no lat/long. Change the size of the circle based on altitude and/or RSSI # (Need to tie into Beast-mode port, raw data port, or JSON port to get RSSI). # Would need to keep track of these objects and kill them when the aircraft timed-out # or sent lat/long. Could switch back to the circle when lat/long times out but # altitude is still coming in as well. # # TODO: Check everywhere that we set a variable to "". Make sure we're not setting # it when a sentence including it comes in, then resetting it on all other sentences # so that it never gets seen. "squawk_txt" and "squawk" were 2 of these. # Check everywhere that $fields[] are checked/saved/used. # # TODO: Expire data values from hashes XX minutes after receiving them. # # # Invoke it as: # ./ads-b.pl planes [--circles] [--logging] # # If you add " --circles" to the end you'll also get a red circle around plane # symbols at your current location which represent the area that a plane might # be min, if it's only reporting altitude and not lat/long. # # If you add " --logging" to the end, this script will save the APRS portion of # the output to a file called "~/.xastir/logs/planes.log". You can later suck # this file back in to see the planes move around the map in hyperspeed. Useful # for a quick demo. # # Injecting them from "planes" or "p1anes" assures that Xastir won't try to adopt # the APRS Item packets as its own and re-transmit them. # # # I got the "dump1090" program from here originally: # https://github.com/antirez/dump1090 # Newer fork: # https://github.com/MalcolmRobb/dump1090 # Newer-yet fork, seems to decode much better: # https://github.com/mutability/dump1090 # # Invoke Mutability's "dump1090" program like so: # "./dump1090 --interactive --net --net-sbs-port 30003 --phase-enhance --oversample --fix --ppm -1 --gain -10 --device-index 0 # # # NOTE: There's also "dump978" which listens to 978 MHz ADS-B transmissions. You can # invoke "dump1090" as above, then invoke "dump978" like this: # # rtl_sdr -f 978000000 -s 2083334 -g 0 -d 1 - | ./dump978 | ./uat2esnt | nc -q1 localhost 30001 # # which will convert the 978 MHz packets into ADS-B ES packets and inject them into "dump1090" # for decoding. I haven't determined yet whether those packets will come out on "dump1090"'s # port 30003 (which this Perl script uses). The above command also uses RTL device 1 instead of 0. # If you're only interested in 978 MHz decoding, there's a way to start "dump1090" w/o a # device attached, then start "dump978" and connect it to "dump1090". # # Then invoke this script in another xterm using "planes" as the callsign: # "./ads-b.pl planes " # # NOTE: Do NOT use the same callsign as your Xastir instance, else it will # "adopt" those APRS Item packets as its own and retransmit them. Code was # added to the script to prevent such operation, but using "planes" as the # callsign works great too! # # # This script snags packets from port 30003 of "dump1090", parses them, then injects # APRS packets into Xastir's UDP port (2023) if "Server Ports" are enabled in Xastir. # # # Port 30001 is an input port (dump978 connects there and dumps data in). # # Port 30002 outputs in raw format, like: # *8D451E8B99019699C00B0A81F36E; # Every entry is separated by a simple newline (LF character, hex 0x0A). # The "callsign" (6 digits of hex) in chunk #4 = ICAO (airframe identifier). # Decoding the sentences: # https://www.sussex.ac.uk/webteam/gateway/file.php?name=coote-proj.pdf&site=20] # http://adsb-decode-guide.readthedocs.org/en/latest/ # # Port 30003 outputs data is SBS1 (BaseStation) format, and is used by this script. # Decoding the sentences: # http://woodair.net/SBS/Article/Barebones42_Socket_Data.htm # NOTE: I changed the numbers by -1 to fit Perl's "split()" command field numbering. # Field 0: # Message type (MSG, STA, ID, AIR, SEL or CLK) # Field 1: # Transmission Type MSG sub types 1 to 8. Not used by other message types. # Field 2: # Session ID Database Session record number # Field 3: # AircraftID Database Aircraft record number # Field 4: # HexIdent Aircraft Mode S hexadecimal code (What we use here... Unique identifier) # Field 5: # FlightID Database Flight record number # Field 6: # Date message generated As it says # Field 7: # Time message generated As it says # Field 8: # Date message logged As it says # Field 9: # Time message logged As it says # Field 10: # Callsign An eight digit flight ID - can be flight number or registration (or even nothing). # Field 11: # Altitude Mode C altitude. Height relative to 1013.2mb (Flight Level). Not height AMSL.. # Field 12: # GroundSpeed Speed over ground (not indicated airspeed) # Field 13: # Track Track of aircraft (not heading). Derived from the velocity E/W and velocity N/S # Field 14: # Latitude North and East positive. South and West negative. # Field 15: # Longitude North and East positive. South and West negative. # Field 16: # VerticalRate 64ft resolution # Field 17: # Squawk Assigned Mode A squawk code. # Field 18: # Alert (Squawk change) Flag to indicate squawk has changed. # Field 19: # Emergency Flag to indicate emergency code has been set # Field 20: # SPI (Ident) Flag to indicate transponder Ident has been activated. # Field 21: # IsOnGround Flag to indicate ground squat switch is active # # # Squawk Codes: # https://en.wikipedia.org/wiki/Transponder_%28aeronautics%29 # # # For reference, using 468/frequency (MHz) to get length of 1/2 wave dipole in feet: # # 1/2 wavelength on 1090 MHz: 5.15" # 1/4 wavelength on 1090 MHz: 2.576" or 2 9/16" # # 1/2 wavelength on 978 MHz: 5.74" # 1/4 wavelength on 978 MHz: 2.87" or 2 7/8" # # # NOTE: In the tables below, lines marked with "Per Countries.dat file" are derived # from the work of "Alexis" of the Group "https://mode-s.groups.io/g/mode-s" # most likely arrived at via observation of Mode-S transponder activity. They are # not guaranteed to represent reality in any way. Find the file in the Files section # of the group. # # Most of the rest of the data in the tables was derived from: # http://www.kloth.net/radio/icao24alloc.php (Created 2003-01-12, Last modified 2011-06-23). # Which in turn came from: # "ICAO Annex 10 Volume III Chapter 9. Aircraft Addressing System" # # eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' & eval 'exec perl -S $0 $argv:q' if 0; use IO::Socket; $my_alt = 600; # In feet. Used by probability circles. # Fetch my lat/long from Xastir config file $my_lat = `grep STATION_LAT ~/.xastir/config/xastir.cnf`; if (! ($my_lat =~ m/STATION_LAT:/) ) { die "Couldn't get STATION_LAT from Xastir config file\n"; } $my_lon = `grep STATION_LONG ~/.xastir/config/xastir.cnf`; if (! ($my_lon =~ m/STATION_LONG:/) ) { die "Couldn't get STATION_LONG from Xastir config file\n"; } chomp $my_lat; chomp $my_lon; $my_lat =~ s/STATION_LAT://; $my_lon =~ s/STATION_LONG://; $my_lat =~ s/(\d+\.\d\d)\d(.)/$1$2/; $my_lon =~ s/(\d+\.\d\d)\d(.)/$1$2/; #print "$my_lat $my_lon\n"; $udp_client = "xastir_udp_client"; $dump1090_host = "localhost"; # Server where dump1090 is running $dump1090_port = 30003; # 30003 is dump1090 default port $xastir_host = "localhost"; # Server where Xastir is running $xastir_port = 2023; # 2023 is Xastir default UDP port $plane_TTL = 1; # Secs after which posits too old to create APRS packets from $log_file = "~/.xastir/logs/planes.log"; $xastir_user = shift; if (defined($xastir_user)) { chomp $xastir_user; } if ( (!defined($xastir_user)) || ($xastir_user eq "") ) { print "Please enter a callsign for Xastir injection, but not Xastir's callsign/SSID!\n"; die; } $xastir_user =~ tr/a-z/A-Z/; $xastir_pass = shift; if (defined($xastir_pass)) { chomp $xastir_pass; } if ( (!defined($xastir_pass)) || ($xastir_pass eq "") ) { print "Please enter a passcode for Xastir injection\n"; die; } $enable_circles = 0; $enable_logging = 0; $flag1 = shift; if (defined($flag1)) { chomp $flag1; if ( ($flag1 ne "") && ($flag1 eq "--circles") ) { $enable_circles = 1; } if ( ($flag1 ne "") && ($flag1 eq "--logging") ) { $enable_logging = 1; } } $flag2 = shift; if (defined($flag2)) { chomp $flag2; if ( ($flag2 ne "") && ($flag2 eq "--circles") ) { $enable_circles = 1; } if ( ($flag2 ne "") && ($flag2 eq "--logging") ) { $enable_logging = 1; } } # Connect to the server using a tcp socket # $socket = IO::Socket::INET->new(PeerAddr => $dump1090_host, PeerPort => $dump1090_port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $dump1090_host:$dump1090_port : $@\n"; # Flush output buffers often select((select(STDOUT), $| = 1)[0]); # Check Xastir's callsign/SSID to make sure we don't have a collision. This # will prevent Xastir adopting the Items as its own and retransmitting them. # xastir_udp_client localhost 2023 -identify # Received: WE7U-13 # $injection_call = $xastir_user; $injection_call =~ s/-\d+//; # Get rid of dash and numbers $injection_ssid = $xastir_user; $injection_ssid =~ s/\w+//; # Get rid of letters $injection_ssid =~ s/-//; # Get rid of dash if ($injection_ssid eq "") { $injection_ssid = 0; } # Find out Callsign/SSID of Xastir instance $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass -identify`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } ($remote_call, $remote_ssid) = split('-', $result); chomp($remote_call); $remote_call =~ s/Received:\s+//; if ( !defined($remote_ssid) ) { $remote_ssid = ""; } if ($remote_ssid ne "") { chomp($remote_ssid); } if ($remote_ssid eq "") { $remote_ssid = 0; } #print "$remote_call $remote_ssid $injection_call $injection_ssid\n"; #if ($remote_call eq $injection_call) { print "Call matches\n"; } #if ($remote_ssid == $injection_ssid) { print "SSID matches\n"; } if ( ($remote_call eq $injection_call) && ($remote_ssid == $injection_ssid) ) { $remote_ssid++; $remote_ssid%= 16; # Increment by 1 mod 16 $xastir_user = "$remote_call-$remote_ssid"; print "Injection conflict. Corrected. New user = $xastir_user\n"; } while (<$socket>) { # For testing: # #$_ = "MSG,3,,,A0CF8D,,,,,,,28000,,,47.87670,-122.27269,,,0,0,0,0"; #$_ = "MSG,5,,,AD815E,,,,,,,575,,,,,,,,,,"; #$_ = "MSG,4,,,AAB812,,,,,,,,454,312,,,0,,0,0,0,0"; #$_ = "MSG,3,,,ABB2D5,,,,,,,40975,,,47.68648,-122.67834,,,0,0,0,0"; # Lat/long/altitude (ft) #$_ = "MSG,1,,,A2CB32,,,,,,BOE181 ,,,,,,,,0,0,0,0"; # Tail number or flight number #$_ = "MSG,4,,,A0F4F6,,,,,,,,175,152,,,-1152,,0,0,0,0"; # Ground speed (knots)/Track chomp; if ( $_ eq "" ) { next; } # Sentences have either 10 or 22 fields, assuming they aren't cut off / collided with. @fields = split(","); # Check whether we have a sentence type, message type, and plane ID. If not we're done with this loop iteration if ( (!defined($fields[0])) || (!defined($fields[1])) || (!defined($fields[4])) || ($fields[4] eq "") ) { next; } $plane_id = $fields[4]; $print1 = $plane_id; # Decode the country of registration via this webpage: # http://www.kloth.net/radio/icao24alloc.php # Add it to the APRS comment field. Remove the Tactical call # from the comment field since it is redundant. # Match on more specific first (longer string). # # NOTE: The above link has the countries arranged alphabetically. # The code below is arranged in this order (because of the order # in which they must be decoded): # # 1024 addresses (14 bits defined) # 4096 addresses (12 bits defined) # 32768 addresses (9 bits defined) # 262144 addresses (6 bits defined) # 1048576 addresses (4 bits defined) # # The code below is basically the 1024 column from the chart in # alphabetical order, then the 2nd column, and so on. The chart # should be reviewed against the code periodically, perhaps yearly. # You'll see longer bits decoded here and there prior to the normal # bit lengths in each section, for instance "Azerbaijan Military" # just prior to the "Azerbaijan" entry in the 14-bit address section. # $registry = "Registry?"; # Convert $plane_id to binary string $binary_plane_id = unpack ('B*', pack ('H*',$plane_id) ); # NOTE: In the code below, more specific addresses (more bits) should # appear prior to less specific. The code will snag the first match. # # 4-bit addresses (column "1048576" in the table): # ------------------------------------------------ if ($binary_plane_id =~ m/^0001/) { $registry = "Russia"; } # Russian Federation elsif ($binary_plane_id =~ m/^1010/) { $registry = "U.S."; # United States if ($binary_plane_id =~ m/^1010111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^1010110111111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^1010110111110111111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^10101101111101111101/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^101011011111011111001/) { $registry = "U.S. Military"; } # Per Countries.dat file } # # 6-bit addresses (column "262144" in the table): # ----------------------------------------------- elsif ($binary_plane_id =~ m/^111000/) { $registry = "Argentina"; if ($binary_plane_id =~ m/^111000010100110000110001/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110000110010/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110000110011/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110001110000/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011111/) { $registry = "Australia"; if ($binary_plane_id =~ m/^0111111/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011111001001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110010001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110010000011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011111001000001001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000100011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000100010111/) { $registry = "Australia Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^111001/) { $registry = "Brazil"; if ($binary_plane_id =~ m/^11100100000/) { $registry = "Brazil Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^111001001000100110111001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001000111110111111110/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001000111111001000000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000000111110110/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000000111110111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110111010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110111011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100101101010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001011000010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001011000011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010001000011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010001000100/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111100111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111101000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111101001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100011111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100100000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100100001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^110000/) { $registry = "Canada"; if ($binary_plane_id =~ m/^1100001/) { $registry = "Canada Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011110/) { $registry = "China"; if ($binary_plane_id =~ m/^0111100000000001000/) { $registry = "China"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111100000000001/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001000/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000101000/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111100000001010010/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001100111/) { $registry = "China Macau"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001101000/) { $registry = "China Macau"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^001110/) { $registry = "France"; if ($binary_plane_id =~ m/^00111011/) { $registry = "France Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^001110101/) { $registry = "France Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^001110000000001001011011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000000110100011011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001111001111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001110000111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001111000111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001101110111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000000110100111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001111/) { $registry = "Germany"; if ($binary_plane_id =~ m/^0011111010/) { $registry = "Germany Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0011111101/) { $registry = "Germany Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0011111110/) { $registry = "Germany Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100000/) { $registry = "India"; if ($binary_plane_id =~ m/^1000000000000010/) { $registry = "India Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^100000000000001100001101/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000001111000/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000001111001/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000011010110/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000011110000011100011/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001100/) { $registry = "Italy"; if ($binary_plane_id =~ m/^0011001111111111/) { $registry = "Italy Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100001/) { $registry = "Japan"; if ($binary_plane_id =~ m/^100001111100110000001010/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100000000000000/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100000000000001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000000001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001011/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001000/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001101/) { $registry = "Spain"; if ($binary_plane_id =~ m/^0011011/) { $registry = "Spain Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00110100/) { $registry = "Spain Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010000/) { $registry = "U.K."; # United Kingdom if ($binary_plane_id =~ m/^010000100100010110111010/) { $registry = "Montserrat"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110100/) { $registry = "Falkland Is."; } # Per Countries.dat file specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110101/) { $registry = "Falkland Is."; } # Per Countries.dat file specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110110/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110111/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000111011111001011011/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111101/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111110/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111111/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^01000011111100101100111/) { $registry = "U.K. Jersey"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000011111001110001011/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001001101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001001100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100000000000000100010/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000011010/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000010000/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110011100011/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100000100111/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100100011011/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000010010/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000100011/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000010011/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010010100000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000001100/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001110111110100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111100111001/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001100/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001110/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000010100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000110000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001001000111/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110011101/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100000101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100001001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000110/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000001/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000111/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000000/) { $registry = "U.K. MoD"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000011111001111/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000010/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111101010/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000101/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001001001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110100/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111101/) { $registry = "U.K. Guernsey"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111/) { $registry = "U.K. Military"; } # Per Countries.dat file } # # 9-bit addresses (column "32768" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^000010100/) { $registry = "Algeria"; if ($binary_plane_id =~ m/^000010100100/) { $registry = "Algeria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001000/) { $registry = "Austria"; if ($binary_plane_id =~ m/^0100010001/) { $registry = "Austria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001001/) { $registry = "Belgium"; if ($binary_plane_id =~ m/^010001001111/) { $registry = "Belgium Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001001100000111100001/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100101/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100111/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111101000/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100011/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100100/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000001/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000010/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000011/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001010/) { $registry = "Bulgaria"; if ($binary_plane_id =~ m/^010001010111/) { $registry = "Bulgaria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010010011/) { $registry = "Czech"; # Czech Republic if ($binary_plane_id =~ m/^0100100110000100/) { $registry = "Czech Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011100100/) { $registry = "North Korea"; } # Democratic People's Republic of Korea elsif ($binary_plane_id =~ m/^010001011/) { $registry = "Denmark"; if ($binary_plane_id =~ m/^0100010111110100/) { $registry = "Denmark Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^000000010/) { $registry = "Egypt"; if ($binary_plane_id =~ m/^00000001000000000111/) { $registry = "Egypt Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00000001000000001000/) { $registry = "Egypt Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000010000000100101100/) { $registry = "Egypt Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001100/) { $registry = "Finland"; if ($binary_plane_id =~ m/^0100011001111000/) { $registry = "Finland Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001101/) { $registry = "Greece"; if ($binary_plane_id =~ m/^01000110100000/) { $registry = "Greece Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000110111101011001001/) { $registry = "Greece Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001101010000010010001/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001101010000010010011/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001101010000010010101/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001110/) { $registry = "Hungary"; if ($binary_plane_id =~ m/^01000111001111/) { $registry = "Hungary Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111011111111111/) { $registry = "Hungary Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100010100/) { $registry = "Indonesia"; if ($binary_plane_id =~ m/^100010100010100100000001/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100010100100000010/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100000000000100100/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100000000000101001/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100110/) { $registry = "Iran"; # Iran, Islamic Republic of if ($binary_plane_id =~ m/^011100110100110100011110/) { $registry = "Iran Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100101/) { $registry = "Iraq"; if ($binary_plane_id =~ m/^011100101000000111111/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111001010000010000000/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01110010100000011111011/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100101000000111110101/) { $registry = "Iraq Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100111/) { $registry = "Israel"; if ($binary_plane_id =~ m/^0111001110001010/) { $registry = "Israel Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101000/) { $registry = "Jordan"; } elsif ($binary_plane_id =~ m/^011101001/) { $registry = "Lebanon"; } elsif ($binary_plane_id =~ m/^000000011/) { $registry = "Libya"; # Libyan Arab Jamahiriya if ($binary_plane_id =~ m/^000000011000001111101011/) { $registry = "Libya Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011101010/) { $registry = "Malaysia"; if ($binary_plane_id =~ m/^011101010000000101010110/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011010100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000001100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000001111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100110/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000010111101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011000101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011010111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000011010/) { $registry = "Mexico"; if ($binary_plane_id =~ m/^000011010000011000010101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010011000010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000110111010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010101000110/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010101000111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000000011011/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000000111111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000001010111001/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000001000101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000001011010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000011001001111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000011001001101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000100/) { $registry = "Morocco"; if ($binary_plane_id =~ m/^00000010000000001011/) { $registry = "Morocco Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000100000000011000/) { $registry = "Morocco Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000100000000001011101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001011110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100010/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001000110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000110001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000110111/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111010/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001000001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000011001001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000011001100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010000/) { $registry = "Netherlands"; # Netherlands, Kingdom of the if ($binary_plane_id =~ m/^010010000000/) { $registry = "Netherlands Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010010000100000010010101/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010010110/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010001001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100001111/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100010001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100010010/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010001011/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000000/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000010/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010100100/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010100101/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100/) { $registry = "Aruba"; } # Per Countries.dat file (In Netherlands block) } elsif ($binary_plane_id =~ m/^110010000/) { $registry = "New Zealand"; if ($binary_plane_id =~ m/^1100100001111111/) { $registry = "New Zealand Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^110010000010010100011100/) { $registry = "New Zealand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^110010000010010100011101/) { $registry = "New Zealand Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001111/) { $registry = "Norway"; if ($binary_plane_id =~ m/^0100011110000001/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100011110000000111/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111100000001101/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001111000000011001/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111100000001100011/) { $registry = "Norway Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101100/) { $registry = "Pakistan"; if ($binary_plane_id =~ m/^011101100000000011101001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100000000000011001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000000110000/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000011010110/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000011011000/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000000111111/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001001011/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010010/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010100/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001011101/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100011100110000111/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010101011110011/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010101111110100/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100000001011110101/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010000010011010/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011101011/) { $registry = "Philipines"; } elsif ($binary_plane_id =~ m/^010010001/) { $registry = "Poland"; if ($binary_plane_id =~ m/^0100100011011000/) { $registry = "Poland Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010010001000000110001110/) { $registry = "Poland Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010010/) { $registry = "Portugal"; if ($binary_plane_id =~ m/^0100100101111100/) { $registry = "Portugal Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011100011/) { $registry = "South Korea"; # Republic of Korea if ($binary_plane_id =~ m/^011100011111101100000001/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111101100000010/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111100100001010/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111100100000110/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010100/) { $registry = "Romania"; if ($binary_plane_id =~ m/^010010100011010110101010/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100011010110101011/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100011010110101100/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001011100101010/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001100000010110/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001100000101111/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100010/) { $registry = "Saudi Arabia"; if ($binary_plane_id =~ m/^0111000100000010011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111000100000010100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111000100000011100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100010000001001011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100010000000100001010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000000100001011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100001/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011010101/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011111001/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011110/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011101/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) } # Serbia: See Yugoslavia slot elsif ($binary_plane_id =~ m/^011101101/) { $registry = "Singapore"; if ($binary_plane_id =~ m/^011101101110001100000011/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000010/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000100/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000001/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101000010011000011/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000001/) { $registry = "South Africa"; } elsif ($binary_plane_id =~ m/^011101110/) { $registry = "Sri Lanka"; } elsif ($binary_plane_id =~ m/^010010101/) { $registry = "Sweden"; if ($binary_plane_id =~ m/^010010101000000110000001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000011/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000101/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000110/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110001000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111100110/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000100010100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000011111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000000111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110011/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110101/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000011010000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111111001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111111000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110011001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000101010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010110/) { $registry = "Switzerland"; if ($binary_plane_id =~ m/^010010110111/) { $registry = "Switzerland Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101111/) { $registry = "Syria"; } # Syrian Arab Republic elsif ($binary_plane_id =~ m/^100010000/) { $registry = "Thailand"; if ($binary_plane_id =~ m/^100010000101001100110011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000010001001001000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110100011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110110000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010000000001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000011101011000001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000000100111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000000101100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110100111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101101/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101110/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000001001001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000101001100110010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000110110110110/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000101/) { $registry = "Tunisia"; } elsif ($binary_plane_id =~ m/^010010111/) { $registry = "Turkey"; if ($binary_plane_id =~ m/^0100101110000010/) { $registry = "Turkey Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010100001/) { $registry = "Ukraine"; } elsif ($binary_plane_id =~ m/^000011011/) { $registry = "Venezuela"; if ($binary_plane_id =~ m/^000011011000000000110010/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011011000000001100000/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011011000000001101100/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010001/) { $registry = "Viet Nam"; } elsif ($binary_plane_id =~ m/^010011000/) { $registry = "Serbia"; # Was Yugoslavia if ($binary_plane_id =~ m/^010011000000000101010101/) { $registry = "Serbia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^111100000/) { $registry = "ICAO(1) Temp. Address"; } # # 12-bit addresses (column "4096" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^011100000000/) { $registry = "Afghanistan"; } elsif ($binary_plane_id =~ m/^000010010000/) { $registry = "Angola"; } elsif ($binary_plane_id =~ m/^000010101000/) { $registry = "Bahamas"; if ($binary_plane_id =~ m/^000010101000000000100001/) { $registry = "Bahamas Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010010100/) { $registry = "Bahrain"; if ($binary_plane_id =~ m/^100010010100000000010001/) { $registry = "Bahrain Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010100000000010110/) { $registry = "Bahrain Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100000010/) { $registry = "Bangladesh"; if ($binary_plane_id =~ m/^011100000010110000000010/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100000010110000000011/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100000010110000000100/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^111010010100/) { $registry = "Bolivia"; if ($binary_plane_id =~ m/^111010010100000011111010/) { $registry = "Bolivia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111010010100000100000100/) { $registry = "Bolivia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010011100/) { $registry = "Burkina Faso"; } elsif ($binary_plane_id =~ m/^000000110010/) { $registry = "Burundi"; } elsif ($binary_plane_id =~ m/^011100001110/) { $registry = "Cambodia"; } elsif ($binary_plane_id =~ m/^000000110100/) { $registry = "Cameroon"; if ($binary_plane_id =~ m/^000000110100010001000011/) { $registry = "Cameroon Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000110100010001000101/) { $registry = "Cameroon Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000001101100/) { $registry = "Central African Rep."; } # Central African Republic elsif ($binary_plane_id =~ m/^000010000100/) { $registry = "Chad"; } elsif ($binary_plane_id =~ m/^111010000000/) { $registry = "Chile"; if ($binary_plane_id =~ m/^1110100000000110/) { $registry = "Chile Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^000010101100/) { $registry = "Colombia"; if ($binary_plane_id =~ m/^000010101100000000000101/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000000111011/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001100110/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001100111/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001110001/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000100001100/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000000110110/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010001100/) { $registry = "Congo DRC"; } # Democratic Republic of the Congo elsif ($binary_plane_id =~ m/^000000110110/) { $registry = "Congo ROC"; } elsif ($binary_plane_id =~ m/^000010101110/) { $registry = "Costa Rica"; } elsif ($binary_plane_id =~ m/^000000111000/) { $registry = "Cote d Ivoire"; } elsif ($binary_plane_id =~ m/^000010110000/) { $registry = "Cuba"; } elsif ($binary_plane_id =~ m/^000011000100/) { $registry = "Dominican Republic"; } elsif ($binary_plane_id =~ m/^111010000100/) { $registry = "Ecuador"; if ($binary_plane_id =~ m/^111010000100000000110101/) { $registry = "Ecuador Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111010000100000000110000/) { $registry = "Ecuador Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010110010/) { $registry = "El Salvador"; } elsif ($binary_plane_id =~ m/^000001000010/) { $registry = "Equatorial Guinea"; } elsif ($binary_plane_id =~ m/^000001000000/) { $registry = "Ethiopia"; } elsif ($binary_plane_id =~ m/^110010001000/) { $registry = "Fiji"; } elsif ($binary_plane_id =~ m/^000000111110/) { $registry = "Gabon"; } elsif ($binary_plane_id =~ m/^000010011010/) { $registry = "Gambia"; } elsif ($binary_plane_id =~ m/^000001000100/) { $registry = "Ghana"; } elsif ($binary_plane_id =~ m/^000010110100/) { $registry = "Guatemala"; } elsif ($binary_plane_id =~ m/^000001000110/) { $registry = "Guinea"; } elsif ($binary_plane_id =~ m/^000010110110/) { $registry = "Guyana"; } elsif ($binary_plane_id =~ m/^000010111000/) { $registry = "Haiti"; } elsif ($binary_plane_id =~ m/^000010111010/) { $registry = "Honduras"; } elsif ($binary_plane_id =~ m/^010011001100/) { $registry = "Iceland"; } elsif ($binary_plane_id =~ m/^010011001010/) { $registry = "Ireland"; if ($binary_plane_id =~ m/^010011001010000000100011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000100111110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000100111111/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000101011000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001000000100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111100111/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101001/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101101/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001010001100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001010001011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100011010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100011110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110001/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110101/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010111110/) { $registry = "Jamaica"; } elsif ($binary_plane_id =~ m/^000001001100/) { $registry = "Kenya"; } elsif ($binary_plane_id =~ m/^011100000110/) { $registry = "Kuwait"; } elsif ($binary_plane_id =~ m/^011100001000/) { $registry = "Laos"; } # Lao People's Democratic Republic elsif ($binary_plane_id =~ m/^000001010000/) { $registry = "Liberia"; } elsif ($binary_plane_id =~ m/^000001010100/) { $registry = "Madagascar"; } elsif ($binary_plane_id =~ m/^000001011000/) { $registry = "Malawi"; } elsif ($binary_plane_id =~ m/^000001011100/) { $registry = "Mali"; } elsif ($binary_plane_id =~ m/^000000000110/) { $registry = "Mozambique"; } elsif ($binary_plane_id =~ m/^011100000100/) { $registry = "Myanmar"; } elsif ($binary_plane_id =~ m/^011100001010/) { $registry = "Nepal"; } elsif ($binary_plane_id =~ m/^000011000000/) { $registry = "Nicaragua"; } elsif ($binary_plane_id =~ m/^000001100010/) { $registry = "Niger"; } elsif ($binary_plane_id =~ m/^000001100100/) { $registry = "Nigeria"; if ($binary_plane_id =~ m/^000001100100000001010001/) { $registry = "Nigeria Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001100100000011110000/) { $registry = "Nigeria Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000011000010/) { $registry = "Panama"; if ($binary_plane_id =~ m/^000011000010000001001110/) { $registry = "Panama Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010011000/) { $registry = "Papua New Guinea"; } elsif ($binary_plane_id =~ m/^111010001000/) { $registry = "Paraguay"; } elsif ($binary_plane_id =~ m/^111010001100/) { $registry = "Peru"; if ($binary_plane_id =~ m/^111010001100000000000111/) { $registry = "Peru Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000001101110/) { $registry = "Rwanda"; } elsif ($binary_plane_id =~ m/^000001110000/) { $registry = "Senegal"; } elsif ($binary_plane_id =~ m/^000001111000/) { $registry = "Somalia"; } elsif ($binary_plane_id =~ m/^000001111100/) { $registry = "Sudan"; } elsif ($binary_plane_id =~ m/^000011001000/) { $registry = "Suriname"; } elsif ($binary_plane_id =~ m/^000010001000/) { $registry = "Togo"; } elsif ($binary_plane_id =~ m/^000011000110/) { $registry = "Trinidad and Tobago"; } elsif ($binary_plane_id =~ m/^000001101000/) { $registry = "Uganda"; } elsif ($binary_plane_id =~ m/^100010010110/) { $registry = "United Arab Emirates"; if ($binary_plane_id =~ m/^100010010110110000/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^100010010110000100100110/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101001/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101010/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101011/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101110/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101100/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010000000/) { $registry = "Tanzania"; } # United Republic of Tanzania elsif ($binary_plane_id =~ m/^111010010000/) { $registry = "Uruguay"; } elsif ($binary_plane_id =~ m/^100010010000/) { $registry = "Yemen"; } elsif ($binary_plane_id =~ m/^000010001010/) { $registry = "Zambia"; } # 14-bit addresses (column "1024" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^01010000000100/) { $registry = "Albania"; } elsif ($binary_plane_id =~ m/^00001100101000/) { $registry = "Antigua and Barbuda"; } elsif ($binary_plane_id =~ m/^01100000000000/) { $registry = "Armenia"; } elsif ($binary_plane_id =~ m/^01100000000010/) { $registry = "Azerbaijan"; if ($binary_plane_id =~ m/^011000000000100000000001/) { $registry = "Azerbaijan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^00001010101000/) { $registry = "Barbados"; } elsif ($binary_plane_id =~ m/^01010001000000/) { $registry = "Belarus"; } elsif ($binary_plane_id =~ m/^00001010101100/) { $registry = "Belize"; } elsif ($binary_plane_id =~ m/^00001001010000/) { $registry = "Benin"; } elsif ($binary_plane_id =~ m/^01101000000000/) { $registry = "Bhutan"; } elsif ($binary_plane_id =~ m/^01010001001100/) { $registry = "Bosnia and Herzegovina"; } elsif ($binary_plane_id =~ m/^00000011000000/) { $registry = "Botswana"; if ($binary_plane_id =~ m/^000000110000000000010010/) { $registry = "Botswana Military" } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000110000000000011010/) { $registry = "Botswana Military" } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001010100/) { $registry = "Brunei Darussalam"; } elsif ($binary_plane_id =~ m/^00001001011000/) { $registry = "Cape Verde"; } elsif ($binary_plane_id =~ m/^00000011010100/) { $registry = "Comoros"; } elsif ($binary_plane_id =~ m/^10010000000100/) { $registry = "Cook Islands"; } elsif ($binary_plane_id =~ m/^01010000000111/) { $registry = "Croatia"; if ($binary_plane_id =~ m/^010100000001110100010011/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000001111110000101/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000001111110000110/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01001100100000/) { $registry = "Cyprus"; } elsif ($binary_plane_id =~ m/^00001001100000/) { $registry = "Djibouti"; } elsif ($binary_plane_id =~ m/^00100000001000/) { $registry = "Eritrea"; } elsif ($binary_plane_id =~ m/^01010001000100/) { $registry = "Estonia"; } elsif ($binary_plane_id =~ m/^01010001010000/) { $registry = "Georgia"; } elsif ($binary_plane_id =~ m/^00001100110000/) { $registry = "Grenada"; } elsif ($binary_plane_id =~ m/^00000100100000/) { $registry = "Guinea-Bissau"; } elsif ($binary_plane_id =~ m/^01101000001100/) { $registry = "Kazakhstan"; } elsif ($binary_plane_id =~ m/^11001000111000/) { $registry = "Kiribati"; } elsif ($binary_plane_id =~ m/^01100000000100/) { $registry = "Kyrgyzstan"; } elsif ($binary_plane_id =~ m/^01010000001011/) { $registry = "Latvia"; } elsif ($binary_plane_id =~ m/^00000100101000/) { $registry = "Lesotho"; } elsif ($binary_plane_id =~ m/^01010000001111/) { $registry = "Lithuania"; if ($binary_plane_id =~ m/^010100000011111111010010/) { $registry = "Lithuania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000011111111010011/) { $registry = "Lithuania Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01001101000000/) { $registry = "Luxembourg"; if ($binary_plane_id =~ m/^0100110100000011110/) { $registry = "NATO"; } # Per Countries.dat file (In Luxembourg block) } # Also see NATO in the Luxembourg block above elsif ($binary_plane_id =~ m/^010001110111111111110001/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001110111111111110010/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001110111111111110011/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^00000101101000/) { $registry = "Maldives"; } elsif ($binary_plane_id =~ m/^01001101001000/) { $registry = "Malta"; if ($binary_plane_id =~ m/^010011010010000001011000/) { $registry = "Malta Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10010000000000/) { $registry = "Marshall Islands"; } elsif ($binary_plane_id =~ m/^00000101111000/) { $registry = "Mauritania"; } elsif ($binary_plane_id =~ m/^00000110000000/) { $registry = "Mauritius"; } elsif ($binary_plane_id =~ m/^01101000000100/) { $registry = "Micronesia"; } # Micronesia, Federated States of elsif ($binary_plane_id =~ m/^01001101010000/) { $registry = "Monaco"; } elsif ($binary_plane_id =~ m/^01101000001000/) { $registry = "Mongolia"; } elsif ($binary_plane_id =~ m/^01010001011000/) { $registry = "Montenegro"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00100000000100/) { $registry = "Namibia"; } elsif ($binary_plane_id =~ m/^11001000101000/) { $registry = "Nauru"; } elsif ($binary_plane_id =~ m/^01110000110000/) { $registry = "Oman"; if ($binary_plane_id =~ m/^01110000110000000111/) { $registry = "Oman Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100001100000010001100/) { $registry = "Oman Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100001100000010001011/) { $registry = "Oman Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01101000010000/) { $registry = "Palau"; } elsif ($binary_plane_id =~ m/^00000110101000/) { $registry = "Qatar"; if ($binary_plane_id =~ m/^000001101010001001001010/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001011/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001100/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001101/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010000011011001/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010000011011010/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001000/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001001/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001010101/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001010110/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000010011/) { $registry = "Moldova"; } # Republic of Moldova elsif ($binary_plane_id =~ m/^11001000110000/) { $registry = "Saint Lucia"; } elsif ($binary_plane_id =~ m/^00001011110000/) { $registry = "Saint Vincent and the Grenadines"; } elsif ($binary_plane_id =~ m/^10010000001000/) { $registry = "Samoa"; } elsif ($binary_plane_id =~ m/^01010000000000/) { $registry = "San Marino"; } elsif ($binary_plane_id =~ m/^00001001111000/) { $registry = "Sao Tome and Principe"; } elsif ($binary_plane_id =~ m/^00000111010000/) { $registry = "Seychelles"; } elsif ($binary_plane_id =~ m/^00000111011000/) { $registry = "Sierra Leone"; } elsif ($binary_plane_id =~ m/^01010000010111/) { $registry = "Slovakia"; if ($binary_plane_id =~ m/^010100000101111101101100/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100011/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100001/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100010/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101101010/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101101000/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000011011/) { $registry = "Slovenia"; if ($binary_plane_id =~ m/^0101000001101111/) { $registry = "Slovenia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001011100/) { $registry = "Solomon Islands"; } elsif ($binary_plane_id =~ m/^00000111101000/) { $registry = "Swaziland"; } elsif ($binary_plane_id =~ m/^01010001010100/) { $registry = "Tajikistan"; } elsif ($binary_plane_id =~ m/^01010001001000/) { $registry = "Macedonia"; } # The former Yugoslav Republic of Macedonia elsif ($binary_plane_id =~ m/^11001000110100/) { $registry = "Tonga"; } elsif ($binary_plane_id =~ m/^01100000000110/) { $registry = "Turkmenistan"; if ($binary_plane_id =~ m/^011000000001100001100010/) { $registry = "Turkmenistan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000011111/) { $registry = "Uzbekistan"; } elsif ($binary_plane_id =~ m/^11001001000000/) { $registry = "Vanuatu"; } elsif ($binary_plane_id =~ m/^00000000010000/) { $registry = "Zimbabwe"; } elsif ($binary_plane_id =~ m/^10001001100100/) { $registry = "Taiwan"; # Per Countries.dat file (In ICAO(2) Flight Safety block below) if ($binary_plane_id =~ m/^100010011001000101100000/) { $registry = "Taiwan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001100100/) { $registry = "ICAO(2) Flight Safety"; } elsif ($binary_plane_id =~ m/^11110000100100/) { $registry = "ICAO(2) Flight Safety"; } # NOTE: ICAO blocks are different in Countries.dat file # # Blocks of addresses for anything that hasn't matched so far, from : # ------------------------------------------------------------ elsif ($binary_plane_id =~ m/^00100/) { $registry = "Africa Region"; } # AFI Region elsif ($binary_plane_id =~ m/^00101/) { $registry = "South America Region"; } # SAM Region elsif ($binary_plane_id =~ m/^0101/) { $registry = "Europe/North Atlantic Regions"; } # EUR and NAT Regions elsif ($binary_plane_id =~ m/^01100/) { $registry = "Middle East Region"; } # MID Region elsif ($binary_plane_id =~ m/^01101/) { $registry = "Asia Region"; } # ASIA Region elsif ($binary_plane_id =~ m/^1001/) { $registry = "North America/Pacific Regions"; } # NAM and PAC Regions elsif ($binary_plane_id =~ m/^111011/) { $registry = "Carribean Region"; } # CAR Region elsif ($binary_plane_id =~ m/^1011/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^1101/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^1111/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^000000000000000000000000/) { $registry = "Country Code DISALLOWED"; } # Shall not be assigned elsif ($binary_plane_id =~ m/^111111111111111111111111/) { $registry = "Country Code DISALLOWED"; } # Shall not be assigned # Parse altitude if MSG Type 2, 3, 5, 6, or 7, save in hash. $print2 = " "; if ( $fields[1] == 2 || $fields[1] == 3 || $fields[1] == 5 || $fields[1] == 6 || $fields[1] == 7 ) { if ( defined($fields[11]) && $fields[11] ne "" && $fields[11] ne 0 ) { $old = ""; if (defined($altitude{$plane_id})) { $old = $altitude{$plane_id}; } # Save new altitude $altitude{$plane_id} = sprintf("%06d", $fields[11]); if ($old ne $altitude{$plane_id}) { $print2 = sprintf("%5sft", $fields[11]); $newdata{$plane_id}++; # Found a new altitude! } } } # Parse ground speed and track if MSG Type 2 or 4, save in hash. $print3 = " "; $print4 = " "; if ( $fields[1] == 4 || $fields[1] == 2 ) { if ( defined($fields[12]) && $fields[12] ne "" ) { $old = ""; if (defined($groundspeed{$plane_id})) { $old = $groundspeed{$plane_id}; } # Save new ground speed $groundspeed{$plane_id} = $fields[12]; if ($old ne $groundspeed{$plane_id}) { $print3 = sprintf("%3skn", $fields[12]); $newdata{$plane_id}++; # Found a new ground speed! } } if ( defined($fields[13]) && $fields[13] ne "" ) { $old = ""; if (defined($track{$plane_id})) { $old = $track{$plane_id}; } # Save new track $track{$plane_id} = $fields[13]; if ($old ne $track{$plane_id}) { $print4 = sprintf("%3s", $fields[13]); $newdata{$plane_id}++; # Found a new track! } } } # Parse lat/long if MSG Type 2 or 3, save in hash. $print5 = " "; if ( ( $fields[1] == 2 || $fields[1] == 3 ) && defined($fields[14]) && $fields[14] ne "" && defined($fields[15]) && $fields[15] ne "" ) { $oldlat = ""; if (defined($lat{$plane_id})) { $oldlat = $lat{$plane_id}; } $lat = $fields[14] * 1.0; if ($lat >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $lat = abs($lat); } $latdeg = int($lat); $latmins = $lat - $latdeg; $latmins2 = $latmins * 60.0; # Save new latitude $lat{$plane_id} = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); $oldlon = ""; if (defined($lon{$plane_id})) { $oldlon = $lon{$plane_id}; } $lon = $fields[15] * 1.0; if ($lon >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $lon = abs($lon); } $londeg = int($lon); $lonmins = $lon - $londeg; $lonmins2 = $lonmins * 60.0; # Save new longitude $lon{$plane_id} = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); if ( ($oldlat ne $lat{$plane_id}) || ($oldlon ne $lon{$plane_id}) ) { $print5 = sprintf("%8s,%9s", $lat{$plane_id},$lon{$plane_id}); # Save most recent posit time $last_posit_time{$plane_id} = time(); $newdata{$plane_id}++; # Found a new lat/lon! # Tactical callsign: # Have new lat/lon. Check whether we have a tactical call # already defined. If not, assign one that includes # the plane_id and the country of registration. if ( !defined($tactical{$plane_id}) ) { # Assign tactical call = $plane_id + registry # Max tactical call in Xastir is 57 chars (56 + terminator?) # $tactical{$plane_id} = $plane_id . " (" . $registry . ")"; $tactical{$plane_id} =~ s/\s+/ /g; # Change multiple spaces to one $aprs = $xastir_user . '>' . "APRS::TACTICAL :" . $plane_id . "=" . $tactical{$plane_id}; $print6 = sprintf("%-18s", $tactical{$plane_id}); print("$print1 $print2 $print3 $print4 $print6 $aprs\n"); # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } } # Save tail or flight number in hash if MSG Type 1 or "ID" sentence. if ( ($fields[0] eq "ID" || $fields[1] == 1) && defined($fields[10]) && $fields[10] ne "????????" && $fields[10] ne "" && !($fields[10] =~ m/^\s+$/) ) { $old = ""; if (defined($tail{$plane_id})) { $old = $tail{$plane_id}; } # Save new tail number or flight number, assign tactical call $temp_tail = $fields[10]; $temp_tail =~ s/[^a-zA-Z0-9,]//g; # Filter out all but alphanumeric chars $tail{$plane_id} = $temp_tail; $tail{$plane_id} =~ s/\s//g; # Remove spaces if ($old ne $tail{$plane_id}) { $print6 = sprintf("%-18s", $temp_tail); $newdata{$plane_id}++; # Found a new tail or flight number! # Assign tactical call = tail number or flight number + registry (if defined) # Max tactical call in Xastir is 57 chars (56 + terminator?) # $tactical{$plane_id} = $temp_tail; if ($registry ne "Registry?") { $tactical{$plane_id} = $temp_tail . " (" . $registry . ")"; $tactical{$plane_id} =~ s/\s+/ /g; # Change multiple spaces to one } $aprs = $xastir_user . '>' . "APRS::TACTICAL :" . $plane_id . "=" . $tactical{$plane_id}; print("$print1 $print2 $print3 $print4 $print6 $aprs\n"); # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } $squawk_txt = ""; if ( defined($fields[17]) && ($fields[17] ne "") ) { $old = ""; if (defined($squawk{$plane_id})) { $old = $squawk{$plane_id}; } $squawk{$plane_id} = $fields[17]; if ($old ne $squawk{$plane_id}) { $newdata{$plane_id}++; # Found a new squawk! } } if (defined($squawk{$plane_id})) { $squawk_txt = sprintf(" SQUAWK=%04d", $squawk{$plane_id}); } $emerg_txt = ""; $emergency = "0"; if ( defined($fields[19]) ) { $emergency = $fields[19]; } if ( $emergency eq "-1" ) { # Emergency of some type $emerg_txt = " EMERGENCY="; # Keyword triggers Xastir's emergency mode!!! # Check squawk code if ( defined($squawk{$plane_id}) ) { if ($squawk{$plane_id} eq "7500") { # Unlawful Interference (hijacking) $emerg_txt = $emerg_txt . "Hijacking"; } if ($squawk{$plane_id} eq "7600") { # Communications failure/problems $emerg_txt = $emerg_txt . "Comms_Failure"; } if ($squawk{$plane_id} eq "7700") { # General Emergency $emerg_txt = $emerg_txt . "General"; } } $newdata{$plane_id}++; } $onGroundTxt = ""; if ( defined($fields[21]) ) { $onGround = $fields[21]; if ($onGround eq "-1") { $onGroundTxt = " On_Ground"; $newdata{$plane_id}++; } } $newtrack = "360"; if ( defined($track{$plane_id}) ) { if ($track{$plane_id} == 0) { $newtrack = "360"; } else { $newtrack = sprintf("%03d", $track{$plane_id} ); } } $newspeed = "000"; if ( defined ($groundspeed{$plane_id}) ) { $newspeed = sprintf("%03d", $groundspeed{$plane_id} ); if ( ($groundspeed{$plane_id} > 0) && ($groundspeed{$plane_id} < 57) ) { $symbol = "X"; # Switch to helicopter symbol } if ($groundspeed{$plane_id} > 126) { $symbol = "^"; # Switch to large aircraft symbol } } $newtail = ""; if ( defined($tail{$plane_id}) ) { $newtail = " $tail{$plane_id}"; } # Auto-switch the symbol based on speed/altitude. # Symbols: # Small airplane = /' # Helicopter = /X # Large aircraft = /^ # Aircraft = \^ (Not used in this script) # # Cessna 150: 57 knots minimum. # Twin Cessna: 215 knots maximum. # UH-1N Huey: 110 knots maximum. # Landing speed Boeing 757: 126 knots. # # If <= 10000 feet and 1 - 56 knots: Helicopter # If <= 20000 feet and 57 - 125 knots: Small aircraft # If > 20000 feet : Large aircraft # if > 126 knots: Large aircraft # $symbol = "'"; # Start with small aircraft symbol $newalt = ""; if ( defined($altitude{$plane_id}) ) { $newalt = " /A=$altitude{$plane_id}"; if ($altitude{$plane_id} > 20000) { $symbol = "^"; # Switch to large aircraft symbol } elsif ($symbol eq "^") { # Do nothing, already switched to large aircraft due to speed } elsif ($symbol eq "X" && $altitude{$plane_id} > 10000) { $symbol = "'"; # Switch to small aircraft from helicopter } } # Above we parsed some message that changed some of our data, send out the # new APRS string if we have enough data defined. # if ( defined($newdata{$plane_id}) && $newdata{$plane_id} ) { # Count percentage of planes with lat/lon out of total planes that have altitude listed. # This should show an approximate implementation percentage for ADS-B transponders. $alt_planes = 0; $lat_planes = 0; $print_adsb_percentage = ""; foreach $key (keys %lat) { $lat_planes++; } foreach $key (keys %altitude) { $alt_planes++; } if ($alt_planes != 0) { $adsb_percentage = ( ($lat_planes * 1.0) / $alt_planes) * 100.0; $print_adsb_percentage = sprintf("ADS-B:%-1.1f%% ($lat_planes/$alt_planes)", $adsb_percentage); } # Do we have a lat/lon and is it recent enough? if ( defined($lat{$plane_id}) && defined($lon{$plane_id}) ) { # # Yes we have a lat/lon # # Check the age of the lat/lon $age = time() - $last_posit_time{$plane_id}; if ( $age > $plane_TTL ) { # # We have a lat/lon but it is too old # $print_age1 = sprintf("(%s%s)", $age, "s"); $print_age2 = sprintf("%18s", $print_age1); $print_aprs = sprintf("%-96s", "$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"); print("$print1 $print2 $print3 $print4 $print_age2 $print_aprs $print_adsb_percentage\n"); } else { # # We have a recent lat/lon # $aprs="$xastir_user>APRS:)$plane_id!$lat{$plane_id}/$lon{$plane_id}$symbol$newtrack/$newspeed$newalt$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"; $print_aprs = sprintf("%-95s", $aprs); if ( $age > 0 # Lat/lon is aging a bit || $print5 eq " " ) { # Didn't parse lat/lon this time $print_age1 = sprintf("%s%s", $age, "s"); $print_age2 = sprintf("%18s", $print_age1); print("$print1 $print2 $print3 $print4 $print_age2 $print_aprs $print_adsb_percentage\n"); } else { print("$print1 $print2 $print3 $print4 $print5 $print_aprs $print_adsb_percentage\n"); } # xastir_udp_client {-identify | [-to_rf] } # $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs [Pmin0.0,]\"`; $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } else { # # No, we have no lat/lon # $print_age = sprintf("%18s", "-"); $print_aprs = sprintf("%-96s", "$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"); print("$print1 $print2 $print3 $print4 $print_age$print_aprs $print_adsb_percentage\n"); if ($enable_circles == 1) { $radius = 10.0; # Set a default of 10 miles if ( defined($altitude{$plane_id}) ) { $radius = ( ( ($altitude{$plane_id} - $my_alt) / 1000 ) * 2 ); # 40k = 80 miles, 20k = 40 miles, 10k = 20 miles, 1k = 2 miles } $print_radius = sprintf("%2.1f", $radius); $aprs="$xastir_user>APRS:)$plane_id!$my_lat/$my_lon$symbol$newtrack/$newspeed$newalt$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry) [Pmin$print_radius,]"; # print "$aprs\n"; # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } # Reset the newdata flag $newdata{$plane_id} = 0; } # Convert altitude to altitude above MSL instead of altitude from a reference barometric reading? # Info: http://forums.flyer.co.uk/viewtopic.php?t=16375 # How many millibar in 1 feet of air? The answer is 0.038640888 @ 0C (25.879232 ft/mb). # How many millibar in 1 foot of air [15 C]? The answer is 0.036622931 @ 15C (27.3053 ft/mb). # Flight Level uses a pressure of 29.92 "Hg (1,013.2 mb). # Yesterday the pressure here was about 1013, so the altitudes looked right on. Today the planes # are reporting ~500' higher via ADS-B when landing at Paine Field. Turns out the pressure today # is 21mb lower, which equates to an additional 573' of altitude reported using the 15C figure! # # /A=aaaaaa feet # CSE/SPD, i.e. 180/999 (speed in knots, direction is WRT true North), if unknown: .../... # )AIDV#2!4903.50N/07201.75WA # ;LEADERVVV*092345z4903.50N/07201.75W>088/036 # )A19E61!4903.50N/07201.75W' 356/426 /A=29275 # Example Small Airplane Object # end of while loop } close($socket); Xastir-Release-2.2.2/scripts/ais.pl000077500000000000000000002663371501463444000171720ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; ########################################################################### # # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2023 The Xastir Group # # "ais.pl", a Perl script to connect aisdecoder and Xastir for receiving # packets from ships. This script will create a UDP server at localhost:10110 # for aisdecoder to send packets into. It decodes AIS sentences, creates APRS # packets out of them and sends them to Xastir's server port (2023) via UDP. # # AIS is the international tracking system for ships. They transmit on Marine # VHF frequencies between 156.025 and 162.025, using a low power output of 1W, # high power output of either 5W or 12.5W, at a bit rate of 9600 bits/s using # NRZI data encoding and GMSK/FM at 0.5 modulation index. # # The two default AIS channels are: # Ch 87B, AIS-1: 161.975 MHz # Ch 88B, AIS-2: 162.025 MHz # # The two long-range channels are: # Ch 75: 156.775 MHz # Ch 76: 156.825 MHz # # # You'll need "libusb", "libpthread", "librtlsdr" installed to be able to # compile "rtl_ais". # # Get aisdecoder (rtl-ais). # git clone https://github.com/dgiardini/rtl-ais/ # cd rtl_ais # make # # # Run "rtl_ais" like this (create a simple script!) for the two default channels: # # ./rtl_ais -h 127.0.0.1 -P 10110 -d 0 -l 161.975M -r 162.025M -n -p -2 # # Change to marine channels 75 (156.775 MHz) and 76 (156.825 MHz) to pick # up long-range AIS (Type 27 packets), perhaps with another dongle: # # ./rtl_ais -h 127.0.0.1 -P 10110 -d 1 -l 156.775M -r 156.825M -n -p -2 # # Note that "-p -2" is the frequency error of the RTL dongle. # Set that to the proper number determined from "Kal". # # "-d 0" or "-d 1" selects which dongle you're attaching to. # # Don't use "-g " and instead use auto-gain, which appears to work # better. This also works better than enabling AGC in the chipset itself. # # # Run "ais.pl" like this (again, create a simple script!): # ./ais.pl boats [--pipe] [--logging] # # You may add the "--pipe" flag in order to have "ais.pl" accept data # from a pipe instead of setting up a UDP server for "rtl_ais" to send # packets to. This is very useful for debugging or for processing # stored log files. # # If you add " --logging" to the end, this script will save the APRS portion of # the output to a file called "~/.xastir/logs/ships.log". You can later suck # this file back in to see the ships move around the map in hyperspeed. Useful # for a quick demo. # # # Antenna length should be: # 1/2 wave dipole: 2.89' -or- 2' 10.7" -or- 2' 10 5/8" # 1/4 wave: 1.44' -or- 1' 5.3" -or- 1' 5 5/16" # # # Excellent AIS info: # http://catb.org/gpsd/AIVDM.html # Eric Raymond/GPSD # https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-5-201402-I!!PDF-E.pdf # ITU Spec # http://www.navcen.uscg.gov/pdf/AIS/AIS_Special_Notice_and_AIS_Encoding_Guide_2012.pdf # # Example packets w/decoding of fields, plus large sample NMEA data file: # http://fossies.org/linux/gpsd/test/sample.aivdm # # Possible live data feed (Too many connections when I try): # ais.exploratorium.edu:80 # ########################################################################### use IO::Socket; use Storable; #use File::HomeDir; #use Data::Dumper; # Only used for debugging vessel_hash # Enable sending APRS packets to Xastir $enable_tx = 1; # Enable the printing of a statistics line every 100 messages # The format is: total type1 type2 ... type27 # Example: 3600 62 0 15 857 0 0 0 0 0 0 0 0 0 0 113 0 0 0 0 685 1868 0 0 0 0 0 0 $statistics_mode = 1; # Turn on/off printing of various types of messages. Enables debugging of a few # sentence types at a time w/o other messages cluttering up the output. $print_123 = 1; $print_4 = 1; $print_5 = 1; # (includes vesselName and shipType) $print_9 = 1; $print_18 = 1; $print_19 = 1; # (includes vesselName) $print_21 = 1; $print_24_A = 1; # A Variant (includes vesselName) $print_24_B = 1; # B Variant (includes shipType $print_27 = 1; $print_others = 1; # Not decoded yet # Keep statistics on each type (28 slots) @message_type_count = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); $statistics_count = 0; # Number of messages before printing stats # Hash to store tac-calls in, to minimize tac-call assignment packets # This stores the complete tactical call, including whatever name # the ship goes by currently + the country of registry. my %tactical_hash; # Create external copy of vessel_hash for persistent store. # This contains only the vessel name, not the country of registry # or the 9-digit MMSI number. $home = `echo ~`; chomp $home; $persistentFileSpec = "$home/.xastir/config/vessel_hash"; #$persistentFileSpec = File::HomeDir->my_home . "/.xastir/config/vessel_hash"; # # # Hash to store vessel names in, for assigning tactical calls # If it doesn't exist, create it with some initial values # For final release this should simply create a dummy file my %vessel_hash; if ( !(-e $persistentFileSpec )) { %vessel_hash = ( ); # Create the new hash file store \%vessel_hash , $persistentFileSpec; } # Retrieve the cache %vessel_hash = %{retrieve($persistentFileSpec)}; # Debug - print the hash values #print Dumper(\%vessel_hash); $udp_client = "xastir_udp_client"; $xastir_host = "localhost"; # Server where Xastir is running $xastir_port = 2023; # 2023 is Xastir default UDP port $log_file = "~/.xastir/logs/ships.log"; %countries = ( "201" => "Albania", #"Albania (Republic of)" "202" => "Andorra", # "Andorra (Principality of)" "203" => "Austria", "204" => "Azores", # "Azores - Portugal" "205" => "Belgium", "206" => "Belarus", # "Belarus (Republic of)" "207" => "Bulgaria", # "Bulgaria (Republic of)" "208" => "Vatican", # "Vatican City State" "209" => "Cyprus", # "Cyprus (Republic of)" "210" => "Cyprus", # "Cyprus (Republic of)" "211" => "Germany", # "Germany (Federal Republic of)" "212" => "Cyprus", # "Cyprus (Republic of)" "213" => "Georgia", "214" => "Moldova", # "Moldova (Republic of)" "215" => "Malta", "216" => "Armenia", # "Armenia (Republic of)" "218" => "Germany", # "Germany (Federal Republic of)" "219" => "Denmark", "220" => "Denmark", "224" => "Spain", "225" => "Spain", "226" => "France", "227" => "France", "228" => "France", "229" => "Malta", "230" => "Finland", "231" => "Faroe Is.", # "Faroe Islands - Denmark" "232" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "233" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "234" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "235" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "236" => "Gibraltar", # "Gibraltar - United Kingdom of Great Britain and Northern Ireland" "237" => "Greece", "238" => "Croatia", # "Croatia (Republic of)" "239" => "Greece", "240" => "Greece", "241" => "Greece", "242" => "Morocco", # "Morocco (Kingdom of)" "243" => "Hungary", "244" => "Netherlands", # "Netherlands (Kingdom of the)" "245" => "Netherlands", # "Netherlands (Kingdom of the)" "246" => "Netherlands", # "Netherlands (Kingdom of the)" "247" => "Italy", "248" => "Malta", "249" => "Malta", "250" => "Ireland", "251" => "Iceland", "252" => "Liechtenstein", # "Liechtenstein (Principality of)" "253" => "Luxembourg", "254" => "Monaco", # "Monaco (Principality of)" "255" => "Madeira", # "Madeira - Portugal" "256" => "Malta", "257" => "Norway", "258" => "Norway", "259" => "Norway", "261" => "Poland", # "Poland (Republic of)" "262" => "Montenegro", "263" => "Portugal", "264" => "Romania", "265" => "Sweden", "266" => "Sweden", "267" => "Slovakia", # "Slovak Republic" "268" => "San Marino", # "San Marino (Republic of)" "269" => "Switzerland", # "Switzerland (Confederation of)" "270" => "Czech Rep.", # "Czech Republic" "271" => "Turkey", "272" => "Ukraine", "273" => "Russian Fed.", # "Russian Federation" "274" => "Macedonia", # "The Former Yugoslav Republic of Macedonia" "275" => "Latvia", # "Latvia (Republic of)" "276" => "Estonia", # "Estonia (Republic of)" "277" => "Lithuania", # "Lithuania (Republic of)" "278" => "Slovenia", # "Slovenia (Republic of)" "279" => "Serbia", # "Serbia (Republic of)" "301" => "Anguilla", # "Anguilla - United Kingdom of Great Britain and Northern Ireland" "303" => "Alaska,U.S.", # "Alaska (State of) - United States of America" "304" => "Antigua & Barbuda", # "Antigua and Barbuda" "305" => "Antigua & Barbuda", # "Antigua and Barbuda" "306" => "Sint Maarten", # "Sint Maarten (Dutch part) - Netherlands (Kingdom of the)" "306" => "Bonaire, Sint Eustatius & Saba", # "Bonaire, Sint Eustatius and Saba - Netherlands (Kingdom of the)" "306" => "Curaao", # "Curaao - Netherlands (Kingdom of the)" "307" => "Aruba", # "Aruba - Netherlands (Kingdom of the)" "308" => "Bahamas", # "Bahamas (Commonwealth of the)" "309" => "Bahamas", # "Bahamas (Commonwealth of the)" "310" => "Bermuda", # "Bermuda - United Kingdom of Great Britain and Northern Ireland" "311" => "Bahamas", # "Bahamas (Commonwealth of the)" "312" => "Belize", "314" => "Barbados", "316" => "Canada", "319" => "Cayman Is.", # "Cayman Islands - United Kingdom of Great Britain and Northern Ireland" "321" => "Costa Rica", "323" => "Cuba", "325" => "Dominica", # "Dominica (Commonwealth of)" "327" => "Dominican Rep.", # "Dominican Republic" "329" => "Guadeloupe", # "Guadeloupe (French Department of) - France" "330" => "Grenada", "331" => "Greenland", # "Greenland - Denmark" "332" => "Guatemala", # "Guatemala (Republic of)" "334" => "Honduras", # "Honduras (Republic of)" "336" => "Haiti", # "Haiti (Republic of)" "338" => "U.S.", # "United States of America" "339" => "Jamaica", "341" => "St. Kitts & Nevis", # "Saint Kitts and Nevis (Federation of)" "343" => "St. Lucia", "345" => "Mexico", "347" => "Martinique", # "Martinique (French Department of) - France" "348" => "Montserrat", # "Montserrat - United Kingdom of Great Britain and Northern Ireland" "350" => "Nicaragua", "351" => "Panama", # "Panama (Republic of)" "352" => "Panama", # "Panama (Republic of)" "353" => "Panama", # "Panama (Republic of)" "354" => "Panama", # "Panama (Republic of)" "355" => "Panama", # "Panama (Republic of)" "356" => "Panama", # "Panama (Republic of)" "357" => "Panama", # "Panama (Republic of)" "358" => "Puerto Rico,U.S.", # "Puerto Rico - United States of America" "359" => "El Salvador", # "El Salvador (Republic of)" "361" => "St. Pierre & Miquelon", # "Saint Pierre and Miquelon (Territorial Collectivity of) - France" "362" => "Trinidad & Tobago", # "Trinidad and Tobago" "364" => "Turks & Caicos Is.", # "Turks and Caicos Islands - United Kingdom of Great Britain and Northern Ireland" "366" => "U.S.", # "United States of America" "367" => "U.S.", # "United States of America" "368" => "U.S.", # "United States of America" "369" => "U.S.", # "United States of America" "370" => "Panama", # "Panama (Republic of)" "371" => "Panama", # "Panama (Republic of)" "372" => "Panama", # "Panama (Republic of)" "373" => "Panama", # "Panama (Republic of)" "374" => "Panama", # "Panama (Republic of)" "375" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "376" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "377" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "378" => "British Virgin Is.", # "British Virgin Islands - United Kingdom of Great Britain and Northern Ireland" "379" => "U.S. Virgin Is.", # "United States Virgin Islands - United States of America" "401" => "Afghanistan", "403" => "Saudi Arabia", # "Saudi Arabia (Kingdom of)" "405" => "Bangladesh", # "Bangladesh (People's Republic of)" "408" => "Bahrain", # "Bahrain (Kingdom of)" "410" => "Bhutan", # "Bhutan (Kingdom of)" "412" => "China", # "China (People's Republic of)" "413" => "China", # "China (People's Republic of)" "414" => "China", # "China (People's Republic of)" "416" => "Taiwan", # "Taiwan (Province of China) - China (People's Republic of)" "417" => "Sri Lanka", # "Sri Lanka (Democratic Socialist Republic of)" "419" => "India", # "India (Republic of)" "422" => "Iran", # "Iran (Islamic Republic of)" "423" => "Azerbaijan", # "Azerbaijan (Republic of)" "425" => "Iraq", # "Iraq (Republic of)" "428" => "Israel", # "Israel (State of)" "431" => "Japan", "432" => "Japan", "434" => "Turkmenistan", "436" => "Kazakhstan", # "Kazakhstan (Republic of)" "437" => "Uzbekistan", # "Uzbekistan (Republic of)" "438" => "Jordan", # "Jordan (Hashemite Kingdom of)" "440" => "Korea", # "Korea (Republic of)" "441" => "Korea", # "Korea (Republic of)" "443" => "Palestine", # "State of Palestine (In accordance with Resolution 99 Rev. Guadalajara, 2010)" "445" => "N. Korea", # "Democratic People's Republic of Korea" "447" => "Kuwait", # "Kuwait (State of)" "450" => "Lebanon", "451" => "Kyrgyzstan", # "Kyrgyz Republic" "453" => "Macao", # "Macao (Special Administrative Region of China) - China (People's Republic of)" "455" => "Maldives", # "Maldives (Republic of)" "457" => "Mongolia", "459" => "Nepal", # "Nepal (Federal Democratic Republic of)" "461" => "Oman", # "Oman (Sultanate of)" "463" => "Pakistan", # "Pakistan (Islamic Republic of)" "466" => "Qatar", # "Qatar (State of)" "468" => "Syria", # "Syrian Arab Republic" "470" => "United Arab Emirates", "471" => "United Arab Emirates", "472" => "Tajikistan", # "Tajikistan (Republic of)" "473" => "Yemen", # "Yemen (Republic of)" "475" => "Yemen", # "Yemen (Republic of)" "477" => "Hong Kong", # "Hong Kong (Special Administrative Region of China) - China (People's Republic of)" "478" => "Bosnia & Herzegovina", # "Bosnia and Herzegovina" "501" => "Adelie Land", # "Adelie Land - France" "503" => "Australia", "506" => "Myanmar", # "Myanmar (Union of)" "508" => "Brunei Darussalam", "510" => "Micronesia", # "Micronesia (Federated States of)" "511" => "Palau", # "Palau (Republic of)" "512" => "New Zealand", "514" => "Cambodia", # "Cambodia (Kingdom of)" "515" => "Cambodia", # "Cambodia (Kingdom of)" "516" => "Christmas Is.", # "Christmas Island (Indian Ocean) - Australia" "518" => "Cook Is.", # "Cook Islands - New Zealand" "520" => "Fiji", # "Fiji (Republic of)", "523" => "Cocos (Keeling) Is.", # "Cocos (Keeling) Islands - Australia" "525" => "Indonesia", # "Indonesia (Republic of)" "529" => "Kiribati", # "Kiribati (Republic of)" "531" => "Laos", # "Lao People's Democratic Republic" "533" => "Malaysia", "536" => "N. Mariana Is,U.S.", # "Northern Mariana Islands (Commonwealth of the) - United States of America" "538" => "Marshall Is.", # "Marshall Islands (Republic of the)" "540" => "New Caledonia", # "New Caledonia - France" "542" => "Niue", # "Niue - New Zealand" "544" => "Nauru", # "Nauru (Republic of)" "546" => "French Polynesia", # "French Polynesia - France" "548" => "Philippines", # "Philippines (Republic of the)" "553" => "Papua New Guinea", "555" => "Pitcairn Is.", # "Pitcairn Island - United Kingdom of Great Britain and Northern Ireland" "557" => "Solomon Islands", "559" => "American Samoa,U.S.", # "American Samoa - United States of America" "561" => "Samoa", # "Samoa (Independent State of)" "563" => "Singapore", # "Singapore (Republic of)" "564" => "Singapore", # "Singapore (Republic of)" "565" => "Singapore", # "Singapore (Republic of)" "566" => "Singapore", # "Singapore (Republic of)" "567" => "Thailand", "570" => "Tonga", # "Tonga (Kingdom of)" "572" => "Tuvalu", "574" => "Viet Nam", # "Viet Nam (Socialist Republic of)" "576" => "Vanuatu", # "Vanuatu (Republic of)" "577" => "Vanuatu", # "Vanuatu (Republic of)" "578" => "Wallis & Futuna Is.", # "Wallis and Futuna Islands - France" "601" => "S. Africa", # "South Africa (Republic of)" "603" => "Angola", # "Angola (Republic of)" "605" => "Algeria", # "Algeria (People's Democratic Republic of)" "607" => "St. Paul & Amsterdam Is.", # "Saint Paul and Amsterdam Islands - France" "608" => "Ascension Is.", # "Ascension Island - United Kingdom of Great Britain and Northern Ireland" "609" => "Burundi", # "Burundi (Republic of)" "610" => "Benin", # "Benin (Republic of)" "611" => "Botswana", # "Botswana (Republic of)" "612" => "Central African Rep.", # "Central African Republic" "613" => "Cameroon", # "Cameroon (Republic of)" "615" => "Congo", # "Congo (Republic of the)" "616" => "Comoros", # "Comoros (Union of the)" "617" => "Cape Verde", # "Cabo Verde (Republic of)" "618" => "Crozet Archipelago", # "Crozet Archipelago - France" "619" => "Cte d'Ivoire", # "Cte d'Ivoire (Republic of)" "620" => "Comoros", # "Comoros (Union of the)" "621" => "Djibouti", # "Djibouti (Republic of)" "622" => "Egypt", # "Egypt (Arab Republic of)" "624" => "Ethiopia", # "Ethiopia (Federal Democratic Republic of)" "625" => "Eritrea", "626" => "Gabonese Rep.", # "Gabonese Republic" "627" => "Ghana", "629" => "Gambia", # "Gambia (Republic of the)" "630" => "Guinea-Bissau", # "Guinea-Bissau (Republic of)" "631" => "Equatorial Guinea", # "Equatorial Guinea (Republic of)" "632" => "Guinea", # "Guinea (Republic of)" "633" => "Burkina Faso", "634" => "Kenya", # "Kenya (Republic of)" "635" => "Kerguelen Is.", # "Kerguelen Islands - France" "636" => "Liberia", # "Liberia (Republic of)" "637" => "Liberia", # "Liberia (Republic of)" "638" => "S. Sudan", # "South Sudan (Republic of)" "642" => "Libya", "644" => "Lesotho", # "Lesotho (Kingdom of)" "645" => "Mauritius", # "Mauritius (Republic of)" "647" => "Madagascar", # "Madagascar (Republic of)" "649" => "Mali", # "Mali (Republic of)" "650" => "Mozambique", # "Mozambique (Republic of)" "654" => "Mauritania", # "Mauritania (Islamic Republic of)" "655" => "Malawi", "656" => "Niger", # "Niger (Republic of the)" "657" => "Nigeria", # "Nigeria (Federal Republic of)" "659" => "Namibia", # "Namibia (Republic of)" "660" => "Reunion", # "Reunion (French Department of) - France" "661" => "Rwanda", # "Rwanda (Republic of)" "662" => "Sudan", # "Sudan (Republic of the)" "663" => "Senegal", # "Senegal (Republic of)" "664" => "Seychelles", # "Seychelles (Republic of)" "665" => "St. Helena", # "Saint Helena - United Kingdom of Great Britain and Northern Ireland" "666" => "Somalia", # "Somalia (Federal Republic of)" "667" => "Sierra Leone", "668" => "Sao Tome & Principe", # "Sao Tome and Principe (Democratic Republic of)" "669" => "Swaziland", # "Swaziland (Kingdom of)" "670" => "Chad", # "Chad (Republic of)" "671" => "Togolese Rep.", # "Togolese Republic" "672" => "Tunisia", "674" => "Tanzania", # "Tanzania (United Republic of)" "675" => "Uganda", # "Uganda (Republic of)", "676" => "Dem. Rep. of Congo", # "Democratic Republic of the Congo" "677" => "Tanzania", # "Tanzania (United Republic of)" "678" => "Zambia", # "Zambia (Republic of)" "679" => "Zimbabwe", # "Zimbabwe (Republic of)" "701" => "Argentine Rep.", # "Argentine Republic" "710" => "Brazil", # "Brazil (Federative Republic of)" "720" => "Bolivia", # "Bolivia (Plurinational State of)" "725" => "Chile", "730" => "Columbia", # "Colombia (Republic of)" "735" => "Ecuador", "740" => "Falkland Is.", # "Falkland Islands (Malvinas) - United Kingdom of Great Britain and Northern Ireland" "745" => "Guiana", # "Guiana (French Department of) - France" "750" => "Guyana", "755" => "Paraguay", # "Paraguay (Republic of)" "760" => "Peru", "765" => "Suriname", # "Suriname (Republic of)" "770" => "Uruguay", # "Uruguay (Eastern Republic of)" "775" => "Venezuela", # "Venezuela (Bolivarian Republic of)" ); $xastir_user = shift; if (defined($xastir_user)) { chomp $xastir_user; } if ( (!defined($xastir_user)) || ($xastir_user eq "") ) { print "Please enter a callsign for Xastir injection, but not Xastir's callsign/SSID!\n"; die; } $xastir_user =~ tr/a-z/A-Z/; $xastir_pass = shift; if (defined($xastir_pass)) { chomp $xastir_pass; } if ( (!defined($xastir_pass)) || ($xastir_pass eq "") ) { print "Please enter a passcode for Xastir injection\n"; die; } # Enable pipe mode by adding the "--pipe" flag, then can pipe # packets into the program's STDIN for testing. Without this flag # we'll get our packets from "rtl_ais" via a UDP server we set up. # Enable logging mode by adding the "--logging" flag. $pipe_mode = 0; $logging_mode = 0; $pipe_flag = shift; if (defined($pipe_flag) && $pipe_flag ne "") { chomp $pipe_flag; if ($pipe_flag eq "--pipe") { $pipe_mode = 1; } if ($pipe_flag eq "--logging") { $logging_mode = 1; } } # Try again in case there are two flags $pipe_flag = shift; if (defined($pipe_flag) && $pipe_flag ne "") { chomp $pipe_flag; if ($pipe_flag eq "--pipe") { $pipe_mode = 1; } if ($pipe_flag eq "--logging") { $logging_mode = 1; } } if ($enable_tx) { # Check Xastir's callsign/SSID to make sure we don't have a collision. This # will prevent Xastir adopting the Items as its own and retransmitting them. # "xastir_udp_client localhost 2023 -identify" # "Received: WE7U-13" # $injection_call = $xastir_user; $injection_call =~ s/-\d+//; # Get rid of dash and numbers $injection_ssid = $xastir_user; $injection_ssid =~ s/\w+//; # Get rid of letters $injection_ssid =~ s/-//; # Get rid of dash if ($injection_ssid eq "") { $injection_ssid = 0; } # Find out Callsign/SSID of Xastir instance $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass -identify`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } ($remote_call, $remote_ssid) = split('-', $result); chomp($remote_call); $remote_call =~ s/Received:\s+//; if ( !defined($remote_ssid) ) { $remote_ssid = ""; } if ($remote_ssid ne "") { chomp($remote_ssid); } if ($remote_ssid eq "") { $remote_ssid = 0; } #print "$remote_call $remote_ssid $injection_call $injection_ssid\n"; #if ($remote_call eq $injection_call) { print "Call matches\n"; } #if ($remote_ssid == $injection_ssid) { print "SSID matches\n"; } if ( ($remote_call eq $injection_call) && ($remote_ssid == $injection_ssid) ) { $remote_ssid++; $remote_ssid%= 16; # Increment by 1 mod 16 $xastir_user = "$remote_call-$remote_ssid"; print "Injection conflict. Corrected. New user = $xastir_user\n"; } } if ($pipe_mode) { # # Debug mode: # Read from pipe in a loop # while () { &process_line($_); } } else { # # Not debug mode: # Create UDP server which connects to rtl_ais to get AIS data # Listen on localhost port 10110 for UDP packets # my $host = "localhost"; my $port = 10110; my $protocol = 'udp'; my $server = IO::Socket::INET->new( #PeerAddr => $host, LocalPort => $port, Proto => $protocol, Type => SOCK_DGRAM ) or die "Socket could not be created, failed with error: $!\n"; # Main processing loop. Fetch packets as they are received via # UDP from port 10110. Create APRS packets out of the interesting # ones and inject them into Xastir at port 2023 using UDP. # while ($server->recv($received_data, 1024)) { #my $peer_address = $server->peerhost(); #my $peer_port = $server->peerport(); #print "Message was received from: $peer_address, $peer_port\n"; #print "$received_data"; &process_line($received_data); } # End of main processing loop } sub process_line () { $received_data = shift; if ($pipe_mode) { $received_data =~ s/\n//; # Remove LF if present $received_data =~ s/\r//; # Remove CR if present } else { # Live mode, receiving from rtl-ais. CRLF line-ends. chop($received_data); chop($received_data); } # Check for empty line if ($received_data eq "") { return; } # Verify the checksum: Refuse to process a message if it's bad. # Computed on entire sentence including the AIVDM tag but excluding # the leading "!" character. my $str = $received_data; $str =~ s/^!//; # Chop off leading '!' #$str =~ s/(,\d)\*../$1/; # Chop to '*' char with leading digit and two trailing chars $str =~ s/(,\d)\*...*/$1/; # Chop to '*' char with leading digit and at least two trailing chars #print "$str\n"; # Received checksum. Catches the correct bytes except # for those cases where the NMEA sentences continues # on past the checksum. my $str2 = $received_data; #$str2 =~ s/.*(..)/$1/; # Catches only a checksum at the end $str2 =~ s/.*,\d\*(..).*/$1/; # Catches checksum at end or middle # Compute the checksum on the string between the '!' and the '*' chars. $j = length($str); my $sum = 0; my $i; for ($i = 0; $i <= $j; $i++) { my $c = ord( substr($str, $i, 1) ); $sum = $sum ^ $c; } my $sum2 = sprintf( "%02X", $sum); if ($str2 ne $sum2) { #print "$received_data\n"; #print "$str\t$str2\t$sum2\n"; printf("***** Bad checksum: Received:%s Computed:%s $received_data\n\n", $str2, $sum2); return(); # Skip this sentence } else { #print "$str2\t$sum2\n"; } @pieces = split( ',', $received_data); # $pieces[0] = NMEA message type # $pieces[1] = Number of sentences # $pieces[2] = Sequential Message ID # $pieces[3] = Sentence number # $pieces[4] = AIS Channel # $pieces[5] = Encoded AIS data # $pieces[6] = End of data & NMEA Checksum $data = $pieces[5]; # Encoded AIS data: Each ASCII character represents 6 bits. # Subtract 48. If still a decimal number > 40, subtract 8. # Convert to binary. $bin_string = ""; $len = length($data); for ($i = 0; $i < $len; $i++) { $c = substr($data, $i, 1); #print("$c"); $d = ord($c) - 48; if ($d > 40) { $d = $d - 8; } #print "\t$d\n"; # Convert each character to 6 bits of binary. # Add the binary strings together to make one # long binary string. Pull out the bits we need # to decode each piece of the message. # $b = &dec2bin($d); #print "\t$b\n"; $bin_string = $bin_string . $b; } #print "$bin_string\n"; #printf("%d\n", length($data) ); #printf("%d\n", length($bin_string) ); # If first six bits are 000001 (message type 1): # MMSI Number - bit 8 for 30 bits # HDG - bit 128 for 9 bits # COG - bit 116 for 12 bits (and divide by 10) # SOG - bit 50 for 10 bits (and divide by 10) # Lat - bit 89 for 27 bits (a signed binary number, divide by 600,000) # Lon - bit 61 for 28 bits (a signed binary number, divide by 600,000) # #if (substr($bin_string,0,6) eq "000001") { # print "Message Type: 1\n"; #} #else { # printf"Message Type: %s\n", substr($bin_string,0,6); # die; #} $bmessage_type = substr($bin_string, 0, 6); $message_type = &bin2dec($bmessage_type); if ($statistics_mode) { # Keep a count of the received message types if ($message_type < 28) { $message_type_count[$message_type] += 1; } # Since there's no message type 0 use it's array location for total $message_type_count[0] += 1; # Print the totals every 100 messages if ( ++$statistics_count >= 100 ) { printf("Stats: "); for (my $jj = 0; $jj < 28; $jj++) { if ($jj == 0) { printf("%d", $message_type_count[$jj]); } else { printf(",%d", $message_type_count[$jj]); } } print "\n\n"; $statistics_count = 0; } } # The escape clause for bad message types is here # so that they get included in the total count above. # Don't move this escape above that code. if ( ($message_type > 27) || ($message_type == 0) ) { # print "***** Undefined Msg Type $message_type: $received_data\n\n"; return(); } #print "Message Type: $message_type\n"; # If not messages types 1, 2, 3, skip for now if ( $message_type != 1 && $message_type != 2 && $message_type != 3 && $message_type != 4 && $message_type != 5 && $message_type != 9 && $message_type != 18 && $message_type != 19 && $message_type != 21 && $message_type != 24 && $message_type != 27 ) { # Not something we decode so don't process the sentence. if ($print_others == 1) { print " Msg Type: $message_type\n\n"; } return; } if ( $message_type == 1 || $message_type == 2 || $message_type == 3 ) { if ($print_123) { print " Msg Type: $message_type\n"; } &process_types_1_2_3($message_type); } elsif ( $message_type == 4 ) { if ($print_4) { print " Msg Type: $message_type\n"; } &process_type_4($message_type); } elsif ( $message_type == 5 ) { if ($print_5) { print " Msg Type: $message_type\n"; } &process_type_5($message_type); } elsif ( $message_type == 9 ) { if ($print_9) { print " Msg Type: $message_type\n"; } &process_type_9($message_type); } elsif ( $message_type == 18 ) { if ($print_18) { print " Msg Type: $message_type\n"; } &process_type_18($message_type); } elsif ( $message_type == 19 ) { if ($print_19) { print " Msg Type: $message_type\n"; } &process_type_19($message_type); } elsif ( $message_type == 21 ) { if ($print_21) { print " Msg Type: $message_type\n"; } &process_type_21($message_type); } elsif ( $message_type == 24 ) { #if ($print_24) { print " Msg Type: $message_type\t"; } # This is printed from the subroutine instead &process_type_24($message_type); } elsif ( $message_type == 27 ) { if ($print_27) { print " Msg Type: $message_type\n"; } if ($print_27) { print "$received_data\n"; } &process_type_27($message_type); } } # End of "process_line" # Message types 1, 2 and 3: Position Report Class A # These messages should have 168 bits total # sub process_types_1_2_3() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("123\t%s\t%d\n", $bin_string, length($bin_string)); #printf("123\t%d\n", length($bin_string)); if ($print_123) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type #my $brepeat_indicator = substr($bin_string, 6, 2); my $bUserID = substr($bin_string, 8, 30); # MMSI my $bnavStatus = substr($bin_string, 38, 4); #my $brateOfTurn = substr($bin_string, 42, 8); my $bSpeedOverGnd = substr($bin_string, 50, 10); ##### #my $bpositionAccuracy = substr($bin_string, 60, 1); my $bLongitude = substr($bin_string, 61, 28); ##### my $bLatitude = substr($bin_string, 89, 27); ##### my $bCourseOverGnd = substr($bin_string, 116, 12); ##### #my $btrueHeading = substr($bin_string, 128, 9); #my $btimestamp = substr($bin_string, 137, 6); #my $bspecialManeuver = substr($bin_string, 143, 2); #my $bspare = substr($bin_string, 145, 3); #my $bRAIM = substr($bin_string, 148, 1); #my $bCommState = substr($bin_string, 149, 19); my $userID = &bin2dec($bUserID); if ($print_123) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_123) { print " Country: $country\n"; } my $navStatus = &bin2dec($bnavStatus); my $navStatusTxt = ""; if ($navStatus == 0) { $navStatusTxt = "Under_way:engine"; } elsif ($navStatus == 1) { $navStatusTxt = "At_anchor"; } elsif ($navStatus == 2) { $navStatusTxt = "Not_under_command"; } elsif ($navStatus == 3) { $navStatusTxt = "Restricted_maneuverability"; } elsif ($navStatus == 4) { $navStatusTxt = "Constrained_by_draught"; } elsif ($navStatus == 5) { $navStatusTxt = "Moored"; } elsif ($navStatus == 6) { $navStatusTxt = "Aground"; } elsif ($navStatus == 7) { $navStatusTxt = "Fishing"; } elsif ($navStatus == 8) { $navStatusTxt = "Under_way:sailing"; } #elsif ($navStatus == 9) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 10) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 11) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 12) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 13) { $navStatusTxt = "Reserved"; } elsif ($navStatus == 14) { $navStatusTxt = "AIS-SART_is_active"; } #elsif ($navStatus == 15) { $navStatusTxt = "Not defined"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_123) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_123) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_123) { print "\n"; } return(); } my $NS; if ($print_123) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_123) { print "\n"; } return(); } my $EW; if ($print_123) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed $navStatusTxt$vesselTag"); if ($print_123) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_123) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_123) { print "\n"; } return(); } # Message type 4: Base station report # These messages should have 168 bits total # sub process_type_4() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("123\t%s\t%d\n", $bin_string, length($bin_string)); #printf("123\t%d\n", length($bin_string)); if ($print_4) { print "Msg too short\n\n"; } return; } my $bUserID = substr($bin_string, 8, 30); # MMSI my $bLongitude = substr($bin_string, 79, 28); ##### my $bLatitude = substr($bin_string, 107, 27); ##### my $userID = &bin2dec($bUserID); if ($print_4) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_4) { print " Country: $country\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { return(); } my $NS; if ($print_4) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { return(); } my $EW; if ($print_4) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "/"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " Fixed Base Station"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol $vesselTag"); if ($print_4) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; # if ( defined( $vessel_hash{$userID}) ) { # $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars # } # else { # # No vessel name # # N7IPB: Display country of registry # $temp = substr("($country)", 0, 56); # Chop at 56 chars # # # WE7U: Display the 9-digit MMSI + country of registry # #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars # } # Force the tactical call to be FS since there are no names for Base Stations # $temp = "FS"; if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_4) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_4) { print "\n"; } return(); } # Message type 5: Static and Voyage Related Data (Vessel name, callsign, ship type) # This message should have 424 bits total # sub process_type_5() { #if ( length($bin_string) < 424 ) { if ( length($bin_string) < 240 ) { #printf("5\t%s\t%d\n", $bin_string, length($bin_string)); #printf("5\t%d\n", length($bin_string)); if ($print_5) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 2); # AIS Version # substr($bin_string, 40, 30); # IMO Number #my $bCallsign = substr($bin_string, 70, 42); # Call Sign my $bVesselName = substr($bin_string, 112, 120); # Vessel Name ##### my $bShipType = substr($bin_string, 232, 8); # Ship Type: Page 114 of ITU spec, Table 53 # substr($bin_string, 240, 9); # Dimension to Bow # substr($bin_string, 249, 9); # Dimension to Stern # substr($bin_string, 258, 6); # Dimension to Port # substr($bin_string, 264, 6); # Dimension to Starboard # substr($bin_string, 270, 4); # Position Fix Type # substr($bin_string, 274, 4); # ETA month (UTC) # substr($bin_string, 278, 5); # ETA day (UTC) # substr($bin_string, 283, 5); # ETA hour (UC) # substr($bin_string, 288, 6); # ETA minute (UTC) # substr($bin_string, 294, 8); # Draught # substr($bin_string, 302, 120); # Destination # substr($bin_string, 422, 1); # DTE # substr($bin_string, 423, 1); # Spare my $userID = &bin2dec($bUserID); if ($print_5) { print " User ID: $userID\n"; } #my $callSign = &bin2text($bCallsign); #print "Callsign: $callSign\n"; my $country = &decode_MID($userID); if ($print_5) { print " Country: $country\n"; } my $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_5) { print " Vessel: $vesselName\n"; } my $shipTypeTxt = &decodeShipType($bShipType); if ($print_5) { print "Ship Type: $shipTypeTxt\n"; } # Assign tactical call = $vesselName + $country # Max tactical call in Xastir is 57 chars (56 + terminator?) # # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars my $temp = substr($vesselName . " ($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_5) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_5) { print "\n"; } return(); } # Message type 9: Standard SAR Aircraft Position Report # This message should have 168 bits total # sub process_type_9() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("9\t%s\t%d\n", $bin_string, length($bin_string)); #printf("9\t%d\n", length($bin_string)); if ($print_9) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI my $bAltitude = substr($bin_string, 38, 12); # Altitude my $bSpeedOverGnd = substr($bin_string, 50, 10); # SOG # substr($bin_string, 60, 1); # Position Accuracy my $bLongitude = substr($bin_string, 61, 28); # Longitude my $bLatitude = substr($bin_string, 89, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 116, 12); # Course Over Ground # substr($bin_string, 128, 6); # Time Stamp # substr($bin_string, 134, 1); # Altitude sensor # substr($bin_string, 135, 7); # Spare # substr($bin_string, 142, 1); # DTE # substr($bin_string, 143, 3); # Spare # substr($bin_string, 146, 1); # Assigned mode # substr($bin_string, 147, 1); # RAIM flag # substr($bin_string, 148, 1); # Comm state selector flag # substr($bin_string, 149, 19); # Radio status my $userID = &bin2dec($bUserID); if ($print_9) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_9) { print " Country: $country\n"; } # NOTE: 4095 = N/A # NOTE: 4094 = 4094 meters or higher. my $altitude_meters = &bin2dec($bAltitude); my $altitude = ""; if ($altitude_meters != 4095) { if ($altitude_meters == 4094) { $altitude = sprintf( "%s%06d%s", " /A=", $altitude_meters * 3.28084, "(Higher than)" ); } else { $altitude = sprintf( "%s%06d", " /A=", $altitude_meters * 3.28084 ); } if ($print_9) { print " Altitude: $altitude\n"; } } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_9) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_9) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_9) { print "\n"; } return(); } my $NS; if ($print_9) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_9) { print "\n"; } return(); } my $EW; if ($print_9) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "^"; # "^" = Large Aircraft. Could be "'" for small aircraft, "X" for helicopter. my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$altitude SAR Aircraft$vesselTag"); if ($print_9) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_9) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_9) { print "\n"; } return(); } # Message type 18: Standard Class B CS Position Report # This message should have 168 bits total # sub process_type_18() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 124 ) { #printf("18\t%s\t%d\n", $bin_string, length($bin_string)); #printf("18\t%d\n", length($bin_string)); if ($print_18) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 8); # Spare my $bSpeedOverGnd = substr($bin_string, 46, 10); # Speed Over Ground # substr($bin_string, 56, 1); # Position Accuracy my $bLongitude = substr($bin_string, 57, 28); # Longitude my $bLatitude = substr($bin_string, 85, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 112, 12); # Course Over Ground # substr($bin_string, 124, 9); # True Heading # substr($bin_string, 133, 6); # Time Stamp # substr($bin_string, 139, 2); # Spare # substr($bin_string, 141, 1); # CS Unit # substr($bin_string, 142, 1); # Display flag # substr($bin_string, 143, 1); # DSC Flag # substr($bin_string, 144, 1); # Band flag # substr($bin_string, 145, 1); # Message 22 flag # substr($bin_string, 146, 1); # Assigned mode # substr($bin_string, 147, 1); # RAIM flag # substr($bin_string, 148, 1); # Comm state selector flag # substr($bin_string, 149, 19); # Radio status my $userID = &bin2dec($bUserID); if ($print_18) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_18) { print " Country: $country\n"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_18) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_18) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_18) { print "\n"; } return(); } my $NS; if ($print_18) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_18) { print "\n"; } return(); } my $EW; if ($print_18) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$vesselTag"); if ($print_18) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_18) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_18) { print "\n"; } return(); } # Message type 19: Extended Class B CS Position Report # This message should have 312 bits total # sub process_type_19() { #if ( length($bin_string) < 312 ) { if ( length($bin_string) < 263 ) { #printf("19\t%s\t%d\n", $bin_string, length($bin_string)); #printf("19\t%d\n", length($bin_string)); if ($print_19) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 8); # Spare my $bSpeedOverGnd = substr($bin_string, 46, 10); # Speed Over Ground # substr($bin_string, 56, 1); # Position Accuracy my $bLongitude = substr($bin_string, 57, 28); # Longitude my $bLatitude = substr($bin_string, 85, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 112, 12); # Course Over Ground # substr($bin_string, 124, 9); # True Heading # substr($bin_string, 133, 6); # Time Stamp # substr($bin_string, 139, 4); # Spare my $bVesselName = substr($bin_string, 143, 120); # Name # substr($bin_string, 263, 8); # Type of ship and cargo # substr($bin_string, 271, 9); # Dimension to Bow # substr($bin_string, 280, 9); # Dimension to Stern # substr($bin_string, 289, 6); # Dimension to Port # substr($bin_string, 295, 6); # Dimension to Starboard # substr($bin_string, 301, 4); # Position Fix Type # substr($bin_string, 305, 1); # RAIM flag # substr($bin_string, 306, 1); # DTE # substr($bin_string, 307, 1); # Assigned mode flag # substr($bin_string, 308, 4); # Spare my $userID = &bin2dec($bUserID); if ($print_19) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_19) { print " Country: $country\n"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_19) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_19) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_19) { print "\n"; } return(); } my $NS; if ($print_19) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_19) { print "\n"; } return(); } my $EW; if ($print_19) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $vesselName = ""; if ($bVesselName ne "") { $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end } my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$vesselTag"); if ($print_19) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } if ($vesselName ne "") { $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_19) { print " Vessel: $vesselName\n"; } # Assign tactical call = $vesselName # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_19) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } if ($print_19) { print "\n"; } return(); } # Message type 21: Aid to Navigation report # These messages should have between 272 and 360 bits total # We don't use the full message and don't parse the name extension # sub process_type_21() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 272 ) { #printf("21\t%s\t%d\n", $bin_string, length($bin_string)); #printf("21\t%d\n", length($bin_string)); if ($print_21) { print "Msg too short\n\n"; } return; } my $bUserID = substr($bin_string, 8, 30); # MMSI my $bAidType = substr($bin_string, 38, 5); my $bVesselName = substr($bin_string, 43, 120); # Vessel Name ##### my $bLongitude = substr($bin_string, 164, 28); ##### my $bLatitude = substr($bin_string, 192, 27); ##### my $userID = &bin2dec($bUserID); if ($print_21) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_21) { print " Country: $country\n"; } my $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_21) { print " Vessel: $vesselName\n"; } my $AidTypeTxt = &decodeAidType($bAidType); if ($print_21) { print "Navaid Type: $AidTypeTxt\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { return(); } my $NS; if ($print_21) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { return(); } my $EW; if ($print_21) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "N"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " (nav-aid)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat\\$lon$symbol $AidTypeTxt"); if ($print_21) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = $vesselName + $country # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName, 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_21) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_21) { print "\n"; } return(); } # Message type 24: Static Data Report (Vessel name, callsign, ship type) # This one has three variations: # # If Part Number field is 0, it's a Type A message. # If Part Number is 1, it's a Type B. # # Part B has two variations as well: # If the MMSI is that of an auxiliary craft, then the Mothership MMSI # is that of the mothership. # If not, then those 30 bits represent vessel dimmensions. # # This message should have: # Type A: 160 bits total # Type B: 168 bits total # sub process_type_24() { #if ( length($bin_string) < 160 ) { if ( length($bin_string) < 160 ) { #printf("24\t%s\t%d\n", $bin_string, length($bin_string)); #printf("24\t%d\n", length($bin_string)); if ($print_24_A || $print_24_B) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI my $bPartNumber = substr($bin_string, 38, 2); # Part Number my $userID = &bin2dec($bUserID); # Check for Type A/B Variant (Type B also has two variants!) $PartNumber = &bin2dec($bPartNumber); if ($PartNumber == 0) { # It is a Type A Variant if ($print_24_A) { print " Msg Type: $message_type\tType A Variant\n"; } if ($print_24_A) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_24_A) { print " Country: $country\n"; } # Type A Variant format starts at bit 40: my $bVesselName = substr($bin_string, 40, 120); # Vessel Name # substr($bin_string, 160, 8); # Spare. my $vesselName = ""; if ($bVesselName ne "") { $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end } if ($vesselName ne "") { $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_24_A) { print " Vessel: $vesselName\n"; } # Assign tactical call = $vesselName # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_24_A) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } if ($print_24_A) { print "\n"; } } else { # It is a Type B Variant. There are two variants of this type! if ($print_24_B) { print " Msg Type: $message_type\tType B Variant\n"; } if ($print_24_B) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_24_B) { print " Country: $country\n"; } # Check the UserID to see if it is an Auxiliary Craft, # to determine which Type B Variant to decode. # Auxiliary craft: MMSI of form 98XXXYYYY, the XXX digits are the country code. if ( !($userID =~ m/^98/)) { # It is NOT an auxiliary craft: # Alternate format starting at bit 40: $bShipType = substr($bin_string, 40, 8); # Ship Type: Page 114 of ITU spec, Table 53 # substr($bin_string, 48, 18); # Vendor ID # substr($bin_string, 66, 4); # Unit Model Code # substr($bin_string, 70, 20); # Serial Number) # substr($bin_string, 90, 42); # Call Sign # substr($bin_string, 132, 9); # Dimension to bow # substr($bin_string, 141, 9); # Dimension to Stern # substr($bin_string, 150, 6); # Dimension to Port # substr($bin_string, 156, 6); # Dimension to Starboard # substr($bin_string, 162, 4); # Type of fix # substr($bin_string, 166, 2); # Spare my $shipTypeTxt = &decodeShipType($bShipType); if ($print_24_B) { print "Ship Type: $shipTypeTxt\n"; } # Assign tactical call = $vesselName + $shipTypeTxt # Max tactical call in Xastir is 57 chars (56 + terminator?) # #my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars my $temp; if (defined($vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " ($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars } else { $temp = substr("($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_24_A) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } else { # It IS an auxiliary craft: # Alternate format starting at bit 132: # substr($bin_string, 132, 30); # Mothership MMSI # substr($bin_string, 162, 6); # Spare } if ($print_24_B) { print "\n"; } } return(); } # Message type 27: Position Report For Long-Range Applications (rare) # This message should have 96 bits total # sub process_type_27() { #if ( length($bin_string) < 96 ) { if ( length($bin_string) < 94 ) { #printf("27\t%s\t%d\n", $bin_string, length($bin_string)); #printf("27\t%d\n", length($bin_string)); if ($print_27) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 1); # Position Accuracy # substr($bin_string, 39, 1); # RAIM flag my $bNavStatus = substr($bin_string, 40, 4); # Navigation Status my $bLongitude = substr($bin_string, 44, 18); # Longitude my $bLatitude = substr($bin_string, 62, 17); # Latitude my $bSpeedOverGnd = substr($bin_string, 79, 6); # Speed Over Ground my $bCourseOverGnd = substr($bin_string, 85, 9); # Course Over Ground # substr($bin_string, 94, 1); # GNSS Position latency # substr($bin_string, 95, 1); # Spare my $userID = &bin2dec($bUserID); if ($print_27) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_27) { print " Country: $country\n"; } my $navStatus = &bin2dec($bNavStatus); my $navStatusTxt = ""; if ($navStatus == 0) { $navStatusTxt = "Under_way:engine"; } elsif ($navStatus == 1) { $navStatusTxt = "At_anchor"; } elsif ($navStatus == 2) { $navStatusTxt = "Not_under_command"; } elsif ($navStatus == 3) { $navStatusTxt = "Restricted_maneuverability"; } elsif ($navStatus == 4) { $navStatusTxt = "Constrained_by_draught"; } elsif ($navStatus == 5) { $navStatusTxt = "Moored"; } elsif ($navStatus == 6) { $navStatusTxt = "Aground"; } elsif ($navStatus == 7) { $navStatusTxt = "Fishing"; } elsif ($navStatus == 8) { $navStatusTxt = "Under_way:sailing"; } #elsif ($navStatus == 9) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 10) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 11) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 12) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 13) { $navStatusTxt = "Reserved"; } elsif ($navStatus == 14) { $navStatusTxt = "AIS-SART_is_active"; } #elsif ($navStatus == 15) { $navStatusTxt = "Not defined"; } # NOTE: 0-359 degrees # NOTE: 511 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd); my $course = ""; if ($courseOverGnd == 511) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_27) { print " Course: $courseOverGnd\n"; } # NOTE: 0-62 knots # NOTE: 63 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd); my $speed = ""; if ($speedOverGnd == 63) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_27) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A = D548h or 54600 decimal. Divide by 91 to get 600 (our factor). my $latitude = &signedBin2dec($bLatitude) / 600.0; if ($latitude == 91) { if ($print_27) { print "\n"; } return(); } if ($print_27) { #printf(" bLatitude: %s\n", $bLatitude); printf(" Latitude: %07.5f\n", $latitude); } my $NS; if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A = 1A838h or 108600 decimal. Divide by 181 to get 600 (our factor). my $longitude = &signedBin2dec($bLongitude) / 600.0; if ($longitude == 181) { if ($print_27) { print "\n"; } return(); } if ($print_27) { #printf("bLongitude: %s\n", $bLongitude); printf("Longitude: %08.5f\n", $longitude); } my $EW; if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed $navStatusTxt$vesselTag"); if ($print_27) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_27) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_27) { print "\n"; } return(); } # Convert binary string $bShipType into text string $shipType # sub decodeAidType() { my $bAidType = shift; my $aidType = sprintf("%02d", &bin2dec($bAidType)); my $aidTypeTxt = "$aidType:"; # Special Craft if ($aidType == 1) { $aidTypeTxt = $aidTypeTxt . "Reference point"; } elsif ($aidType == 2) { $aidTypeTxt = $aidTypeTxt . "RACON"; } elsif ($aidType == 3) { $aidTypeTxt = $aidTypeTxt . "Fixed structure off shore"; } elsif ($aidType == 4) { $aidTypeTxt = $aidTypeTxt . "Reserved"; } elsif ($aidType == 5) { $aidTypeTxt = $aidTypeTxt . "Light, without sectors"; } elsif ($aidType == 6) { $aidTypeTxt = $aidTypeTxt . "Light, with sectors"; } elsif ($aidType == 7) { $aidTypeTxt = $aidTypeTxt . "Leading Light Front"; } elsif ($aidType == 8) { $aidTypeTxt = $aidTypeTxt . "Leading Light Rear"; } elsif ($aidType == 9) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal N"; } elsif ($aidType == 10) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal E"; } elsif ($aidType == 11) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal S"; } elsif ($aidType == 12) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal W"; } elsif ($aidType == 13) { $aidTypeTxt = $aidTypeTxt . "Beacon, Port hand"; } elsif ($aidType == 14) { $aidTypeTxt = $aidTypeTxt . "Beacon, Starboard hand"; } elsif ($aidType == 15) { $aidTypeTxt = $aidTypeTxt . "Beacon, Preferred Channel port hand"; } elsif ($aidType == 16) { $aidTypeTxt = $aidTypeTxt . "Beacon, Preferred Channel starboard hand"; } elsif ($aidType == 17) { $aidTypeTxt = $aidTypeTxt . "Beacon, Isolated danger"; } elsif ($aidType == 18) { $aidTypeTxt = $aidTypeTxt . "Beacon, Safe water"; } elsif ($aidType == 19) { $aidTypeTxt = $aidTypeTxt . "Beacon, Special mark"; } elsif ($aidType == 20) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark N"; } elsif ($aidType == 21) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark E"; } elsif ($aidType == 22) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark S"; } elsif ($aidType == 23) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark W"; } elsif ($aidType == 24) { $aidTypeTxt = $aidTypeTxt . "Port hand Mark"; } elsif ($aidType == 25) { $aidTypeTxt = $aidTypeTxt . "Starboard hand Mark"; } elsif ($aidType == 26) { $aidTypeTxt = $aidTypeTxt . "Preferred Channel Port hand"; } elsif ($aidType == 27) { $aidTypeTxt = $aidTypeTxt . "Preferred Channel Starboard hand"; } elsif ($aidType == 28) { $aidTypeTxt = $aidTypeTxt . "Isolated danger"; } elsif ($aidType == 29) { $aidTypeTxt = $aidTypeTxt . "Safe Water"; } elsif ($aidType == 30) { $aidTypeTxt = $aidTypeTxt . "Special Mark"; } elsif ($aidType == 31) { $aidTypeTxt = $aidTypeTxt . "Light Vessel / LANBY / Rigs"; } return($aidTypeTxt); } # Convert binary string $bShipType into text string $shipType # sub decodeShipType() { my $bShipType = shift; my $shipType = sprintf("%02d", &bin2dec($bShipType)); my $shipTypeTxt = "$shipType:"; # Special Craft if ($shipType == 50) { $shipTypeTxt = $shipTypeTxt . "Pilot_Vessel"; } elsif ($shipType == 51) { $shipTypeTxt = $shipTypeTxt . "Search_and_Rescue"; } elsif ($shipType == 52) { $shipTypeTxt = $shipTypeTxt . "Harbor_Tug"; } elsif ($shipType == 53) { $shipTypeTxt = $shipTypeTxt . "Fish,Offshore_or_Port_Tender"; } elsif ($shipType == 54) { $shipTypeTxt = $shipTypeTxt . "Anti-pollution"; } elsif ($shipType == 55) { $shipTypeTxt = $shipTypeTxt . "Law_Enforcement"; } elsif ($shipType == 56) { $shipTypeTxt = $shipTypeTxt . "Local"; } elsif ($shipType == 57) { $shipTypeTxt = $shipTypeTxt . "Local"; } elsif ($shipType == 58) { $shipTypeTxt = $shipTypeTxt . "Medical_Transport_or_Public_Safety"; } elsif ($shipType == 59) { $shipTypeTxt = $shipTypeTxt . "Neutral_State_Vessel"; } # U.S. Specific Vessels elsif ($shipType =~ m/^2/) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . "Wing_in_Ground"; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "Tow-Push"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "Tow-Push"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "Light_Boat"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "Mobile_Offshore_Drilling"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "Offshore_Supply_Vessel"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "Processing_Vessel"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "School/Scientific/Research/Training_Vessel"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "U.S._Public_or_Govt"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . "Autonomous_or_Remotely-Operated"; } } # Other Vessels elsif ($shipType =~ m/^3/) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . "Fishing"; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "Towing-Pull"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "Towing-Big"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "Dredging_or_Underwater_Ops"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "Diving_Ops"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "Military_Ops"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "Sailing"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "Pleasure_Craft"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "Other:Reserved"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . "Other:Reserved"; } } elsif ($shipType =~ m/^0/) { $shipTypeTxt = $shipTypeTxt . "Not-Available"; } elsif ($shipType =~ m/^1/) { $shipTypeTxt = $shipTypeTxt . "Reserved"; } elsif ($shipType =~ m/^4/) { $shipTypeTxt = $shipTypeTxt . "Passenger_or_High_Speed"; } elsif ($shipType =~ m/^6/) { $shipTypeTxt = $shipTypeTxt . "Passenger-Big"; } elsif ($shipType =~ m/^7/) { $shipTypeTxt = $shipTypeTxt . "Cargo"; } elsif ($shipType =~ m/^8/) { $shipTypeTxt = $shipTypeTxt . "Tanker"; } elsif ($shipType =~ m/^9/) { $shipTypeTxt = $shipTypeTxt . "Other"; } # Decode 2nd digit for 1/4/6/7/8/9 types: if ( ($shipType =~ m/^1/) || ($shipType =~ m/^4/) || ($shipType =~ m/^6/) || ($shipType =~ m/^7/) || ($shipType =~ m/^8/) || ($shipType =~ m/^9/) ) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . ""; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:A/X"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:B/Y"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:C/Z"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:D/O"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . ""; } } return($shipTypeTxt); } # Convert a 6-digit binary string to ASCII text # Encoded AIS data: Each 6 bits represents one ASCII character. # # Each six-bit nibble maps to an ASCII character. # Decimal 0-31 map to "@" ( ASCII 64) through "\_" (ASCII 95) # Decimal 32-63 map to " " (ASCII 32) though "?" (ASCII 63) # Lowercase, backtick, right/left braces, pipe, tilde and DEL can't be encoded sub bin2text() { my $input = shift; my $final_string = ""; my $len = length($input); my $i; for ($i = 0; $i < $len; $i+=6) { my $binary_char = substr($input, $i, 6); # Convert from binary to decimal (ord) my $d = unpack("N", pack("B32", substr("00000000000000000000000000000000" . $binary_char, -32))); if ($d > 0) { # Skip NULL characters if ($d < 32) { $d += 64; } $final_string = $final_string . chr($d); } } $final_string =~ s/\s\s/ /g; return($final_string); } ## Convert a signed binary string of ASCII 0's and 1's to a decimal #sub signedBin2dec { # my $input = shift; # # if ( substr($input, 0, 1) eq "1") { # Negative number # # Pad to 32 bits with 1's ## return unpack("i", pack("B32", substr("11111111111111111111111111111111" . $input, -32))); # # Invert all the bits. Add 1. Convert to decimal. Negate. # my $ii; # my $input2 = ""; # my $len = length($input); # for ($ii = 0; $ii < $len; $ii++) { # my $j = substr($input, $ii, 1); # if ($j eq "0") { $j = "1"; } # else { $j = "0"; } # $input2 = $input2 . $j; # } ##print "$input\n"; ##print "$input2\n"; # my $binary = pack("B32", substr("00000000000000000000000000000000" . $input2, -32, 32)); # my $decimal = unpack("N", $binary); # $decimal++; # $decimal = -$decimal; # return $decimal; # } # else { # Positive number # # Pad to 32 bits with 0's # return unpack("N", pack("B32", substr("00000000000000000000000000000000" . $input, -32))); ##### # # } #} # Convert a signed binary string of ASCII 0's and 1's to a decimal the hard way. # This subroutine should be platform-agnostic as it does all the work internally. sub signedBin2dec { my $input = shift; my $input2 = ""; my $decimal; my $multiplier; #print "\n$input\n"; if ( substr($input, 0, 1) eq "1") { # Negative number # Invert all the bits. Add 1. Convert to decimal. Negate. my $ii; my $len = length($input); for ($ii = 0; $ii < $len; $ii++) { my $j = substr($input, $ii, 1); if ($j eq "0") { $j = "1"; } else { $j = "0"; } $input2 = $input2 . $j; } $decimal = &toDecimal($input2); $decimal++; $decimal = -$decimal; return $decimal; } else { # Positive number return &toDecimal($input); } } # Convert to decimal from positive binary string. # Used by above signedBin2dec subroutine. sub toDecimal { my $input = shift; my $multiplier = 1; my $decimal = 0; my $len = length($input); # Start at LSB bit, work toward MSB bit for (my $ii = $len-1; $ii >= 0; $ii--) { if (substr($input, $ii, 1) == 1) { $decimal = $decimal + $multiplier; #print "1\tMult: $multiplier\n"; } else { #print "0\n"; } $multiplier = $multiplier * 2 ; } return $decimal; } # Convert an unsigned binary string of ASCII 0's and 1's to a decimal sub bin2dec { my $temp = shift; if (!defined($temp) || $temp eq "") { return; } return unpack("N", pack("B32", substr("00000000000000000000000000000000" . $temp, -32))); ##### } # Convert a decimal string (ASCII) to a binary string (ASCII) sub dec2bin { my $input = "00000000000000000000000000" . shift; my $str = unpack("B32", pack("N", $input)); my $str2 = substr($str, -6); return $str2; } # Decode MID out of MMSI ($userID) too: # 8MIDXXXXX Diver's radio (not used in the U.S. in 2013) # MIDXXXXXX Ship # 0MIDXXXXX Group of ships; the U.S. Coast Guard, for example, is 03699999 # 00MIDXXXX Coastal stations # 111MIDXXX SAR (Search and Rescue) aircraft # 99MIDXXXX Aids to Navigation # 98MIDXXXX Auxiliary craft associated with a parent ship # 970MIDXXX AIS SART (Search and Rescue Transmitter) # 972XXXXXX MOB (Man Overboard) device # 974XXXXXX EPIRB (Emergency Position Indicating Radio Beacon) AIS # # NOTE: U.S. ships sometimes incorrectly send "669" for those first 3 digits. # http://www.itu.int/online/mms/glad/cga_mids.sh?lng=E # sub decode_MID { my $userID = shift; my $MID = $userID; if ($userID =~ m/^8.*/) { # Diver's radio $MID =~ s/^8(...).*/$1/; } elsif ($userID =~ m/^00.*/) { # Coastal station $MID =~ s/^00(...).*/$1/; } elsif ($userID =~ m/^0.*/) { # Group of ships $MID =~ s/^0(...).*/$1/; } elsif ($userID =~ m/^111.*/) { # SAR aircraft $MID =~ s/^111(...).*/$1/; } elsif ($userID =~ m/^99.*/) { # Navigation aid $MID =~ s/^99(...).*/$1/; } elsif ($userID =~ m/^98.*/) { # Auxiliary craft $MID =~ s/^98(...).*/$1/; } elsif ($userID =~ m/^970.*/) { # AIS SART $MID =~ s/^970(...).*/$1/; } elsif ($userID =~ m/^972.*/) { # Man overboard device $MID = "MOB"; } elsif ($userID =~ m/^974.*/) { # EPIRB $MID = "EPIRB"; } else { # Ship $MID =~ s/^(...).*/$1/; } my $country = ""; if (defined($countries{$MID})) { $country = $countries{$MID}; } else { $country = "Unknown"; } return $country; } # Escape characters from the shell # # Between double quotes the literal value of all characters is preserved except # for dollar sign, backticks (backward single quotes, ``) and backslash. # # The backslash retains its meaning only when followed by dollar, backtick, double quote, # backslash or newline. Within double quotes, the backslashes are removed from the input # stream when followed by one of these characters. Backslashes preceding characters that # don't have a special meaning are left unmodified for processing by the shell interpreter. # sub escape_from_shell { $temp = shift; $temp =~ s/\\/\\/g; # Look for \ and escape it. Do this one FIRST! $temp =~ s/"/\\"/g; # Look for " and escape it $temp =~ s/\$/\\\$/g; # Look for $ and escape it $temp =~ s/\`/\\`/g; # Look for ` and escape it return ($temp); } # Log messages to log file if logging enabled # sub log_aprs { $sentence = shift; if ($logging_mode) { `echo \"$sentence\" >> $log_file`; } } Xastir-Release-2.2.2/scripts/ais_pp.pl000077500000000000000000000453151501463444000176600ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; ########################################################################### # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2023 The Xastir Group # # "ais_pp.pl", a Perl script that prints a formatted list of the # ships found in the vessel hash checkpoint file created by ais.pl # ########################################################################### #use IO::Socket; use Storable; #use File::HomeDir; use Data::Dumper; # Only used for debugging vessel_hash $home = `echo ~`; chomp $home; $persistentFileSpec = "$home/.xastir/config/vessel_hash"; #$persistentFileSpec = File::HomeDir->my_home . "/.xastir/config/vessel_hash"; # # # Hash to store vessel names in, for assigning tactical calls # If it doesn't exist, create it with some initial values # For final release this should simply create a dummy file my %vessel_hash; if ( !(-e $persistentFileSpec )) { %vessel_hash = ( ); # Create the new hash file # store \%vessel_hash , $persistentFileSpec; } # Retrieve the cache %vessel_hash = %{retrieve($persistentFileSpec)}; # Debug - print the hash values #print Dumper(\%vessel_hash); #open(my $fh, '>', 'report.txt'); #print $fh Dumper(\%vessel_hash); %countries = ( "201" => "Albania", #"Albania (Republic of)" "202" => "Andorra", # "Andorra (Principality of)" "203" => "Austria", "204" => "Azores", # "Azores - Portugal" "205" => "Belgium", "206" => "Belarus", # "Belarus (Republic of)" "207" => "Bulgaria", # "Bulgaria (Republic of)" "208" => "Vatican", # "Vatican City State" "209" => "Cyprus", # "Cyprus (Republic of)" "210" => "Cyprus", # "Cyprus (Republic of)" "211" => "Germany", # "Germany (Federal Republic of)" "212" => "Cyprus", # "Cyprus (Republic of)" "213" => "Georgia", "214" => "Moldova", # "Moldova (Republic of)" "215" => "Malta", "216" => "Armenia", # "Armenia (Republic of)" "218" => "Germany", # "Germany (Federal Republic of)" "219" => "Denmark", "220" => "Denmark", "224" => "Spain", "225" => "Spain", "226" => "France", "227" => "France", "228" => "France", "229" => "Malta", "230" => "Finland", "231" => "Faroe Is.", # "Faroe Islands - Denmark" "232" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "233" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "234" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "235" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "236" => "Gibraltar", # "Gibraltar - United Kingdom of Great Britain and Northern Ireland" "237" => "Greece", "238" => "Croatia", # "Croatia (Republic of)" "239" => "Greece", "240" => "Greece", "241" => "Greece", "242" => "Morocco", # "Morocco (Kingdom of)" "243" => "Hungary", "244" => "Netherlands", # "Netherlands (Kingdom of the)" "245" => "Netherlands", # "Netherlands (Kingdom of the)" "246" => "Netherlands", # "Netherlands (Kingdom of the)" "247" => "Italy", "248" => "Malta", "249" => "Malta", "250" => "Ireland", "251" => "Iceland", "252" => "Liechtenstein", # "Liechtenstein (Principality of)" "253" => "Luxembourg", "254" => "Monaco", # "Monaco (Principality of)" "255" => "Madeira", # "Madeira - Portugal" "256" => "Malta", "257" => "Norway", "258" => "Norway", "259" => "Norway", "261" => "Poland", # "Poland (Republic of)" "262" => "Montenegro", "263" => "Portugal", "264" => "Romania", "265" => "Sweden", "266" => "Sweden", "267" => "Slovakia", # "Slovak Republic" "268" => "San Marino", # "San Marino (Republic of)" "269" => "Switzerland", # "Switzerland (Confederation of)" "270" => "Czech Rep.", # "Czech Republic" "271" => "Turkey", "272" => "Ukraine", "273" => "Russian Fed.", # "Russian Federation" "274" => "Macedonia", # "The Former Yugoslav Republic of Macedonia" "275" => "Latvia", # "Latvia (Republic of)" "276" => "Estonia", # "Estonia (Republic of)" "277" => "Lithuania", # "Lithuania (Republic of)" "278" => "Slovenia", # "Slovenia (Republic of)" "279" => "Serbia", # "Serbia (Republic of)" "301" => "Anguilla", # "Anguilla - United Kingdom of Great Britain and Northern Ireland" "303" => "Alaska - U.S.", # "Alaska (State of) - United States of America" "304" => "Antigua & Barbuda", # "Antigua and Barbuda" "305" => "Antigua & Barbuda", # "Antigua and Barbuda" "306" => "Sint Maarten", # "Sint Maarten (Dutch part) - Netherlands (Kingdom of the)" "306" => "Bonaire, Sint Eustatius & Saba", # "Bonaire, Sint Eustatius and Saba - Netherlands (Kingdom of the)" "306" => "Curaao", # "Curaao - Netherlands (Kingdom of the)" "307" => "Aruba", # "Aruba - Netherlands (Kingdom of the)" "308" => "Bahamas", # "Bahamas (Commonwealth of the)" "309" => "Bahamas", # "Bahamas (Commonwealth of the)" "310" => "Bermuda", # "Bermuda - United Kingdom of Great Britain and Northern Ireland" "311" => "Bahamas", # "Bahamas (Commonwealth of the)" "312" => "Belize", "314" => "Barbados", "316" => "Canada", "319" => "Cayman Is.", # "Cayman Islands - United Kingdom of Great Britain and Northern Ireland" "321" => "Costa Rica", "323" => "Cuba", "325" => "Dominica", # "Dominica (Commonwealth of)" "327" => "Dominican Rep.", # "Dominican Republic" "329" => "Guadeloupe", # "Guadeloupe (French Department of) - France" "330" => "Grenada", "331" => "Greenland", # "Greenland - Denmark" "332" => "Guatemala", # "Guatemala (Republic of)" "334" => "Honduras", # "Honduras (Republic of)" "336" => "Haiti", # "Haiti (Republic of)" "338" => "U.S.", # "United States of America" "339" => "Jamaica", "341" => "St. Kitts & Nevis", # "Saint Kitts and Nevis (Federation of)" "343" => "St. Lucia", "345" => "Mexico", "347" => "Martinique", # "Martinique (French Department of) - France" "348" => "Montserrat", # "Montserrat - United Kingdom of Great Britain and Northern Ireland" "350" => "Nicaragua", "351" => "Panama", # "Panama (Republic of)" "352" => "Panama", # "Panama (Republic of)" "353" => "Panama", # "Panama (Republic of)" "354" => "Panama", # "Panama (Republic of)" "355" => "Panama", # "Panama (Republic of)" "356" => "Panama", # "Panama (Republic of)" "357" => "Panama", # "Panama (Republic of)" "358" => "Puerto Rico - U.S.", # "Puerto Rico - United States of America" "359" => "El Salvador", # "El Salvador (Republic of)" "361" => "St. Pierre & Miquelon", # "Saint Pierre and Miquelon (Territorial Collectivity of) - France" "362" => "Trinidad & Tobago", # "Trinidad and Tobago" "364" => "Turks & Caicos Is.", # "Turks and Caicos Islands - United Kingdom of Great Britain and Northern Ireland" "366" => "U.S.", # "United States of America" "367" => "U.S.", # "United States of America" "368" => "U.S.", # "United States of America" "369" => "U.S.", # "United States of America" "370" => "Panama", # "Panama (Republic of)" "371" => "Panama", # "Panama (Republic of)" "372" => "Panama", # "Panama (Republic of)" "373" => "Panama", # "Panama (Republic of)" "374" => "Panama", # "Panama (Republic of)" "375" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "376" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "377" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "378" => "British Virgin Is.", # "British Virgin Islands - United Kingdom of Great Britain and Northern Ireland" "379" => "U.S. Virgin Is.", # "United States Virgin Islands - United States of America" "401" => "Afghanistan", "403" => "Saudi Arabia", # "Saudi Arabia (Kingdom of)" "405" => "Bangladesh", # "Bangladesh (People's Republic of)" "408" => "Bahrain", # "Bahrain (Kingdom of)" "410" => "Bhutan", # "Bhutan (Kingdom of)" "412" => "China", # "China (People's Republic of)" "413" => "China", # "China (People's Republic of)" "414" => "China", # "China (People's Republic of)" "416" => "Taiwan", # "Taiwan (Province of China) - China (People's Republic of)" "417" => "Sri Lanka", # "Sri Lanka (Democratic Socialist Republic of)" "419" => "India", # "India (Republic of)" "422" => "Iran", # "Iran (Islamic Republic of)" "423" => "Azerbaijan", # "Azerbaijan (Republic of)" "425" => "Iraq", # "Iraq (Republic of)" "428" => "Israel", # "Israel (State of)" "431" => "Japan", "432" => "Japan", "434" => "Turkmenistan", "436" => "Kazakhstan", # "Kazakhstan (Republic of)" "437" => "Uzbekistan", # "Uzbekistan (Republic of)" "438" => "Jordan", # "Jordan (Hashemite Kingdom of)" "440" => "Korea", # "Korea (Republic of)" "441" => "Korea", # "Korea (Republic of)" "443" => "Palestine", # "State of Palestine (In accordance with Resolution 99 Rev. Guadalajara, 2010)" "445" => "N. Korea", # "Democratic People's Republic of Korea" "447" => "Kuwait", # "Kuwait (State of)" "450" => "Lebanon", "451" => "Kyrgyzstan", # "Kyrgyz Republic" "453" => "Macao", # "Macao (Special Administrative Region of China) - China (People's Republic of)" "455" => "Maldives", # "Maldives (Republic of)" "457" => "Mongolia", "459" => "Nepal", # "Nepal (Federal Democratic Republic of)" "461" => "Oman", # "Oman (Sultanate of)" "463" => "Pakistan", # "Pakistan (Islamic Republic of)" "466" => "Qatar", # "Qatar (State of)" "468" => "Syria", # "Syrian Arab Republic" "470" => "United Arab Emirates", "471" => "United Arab Emirates", "472" => "Tajikistan", # "Tajikistan (Republic of)" "473" => "Yemen", # "Yemen (Republic of)" "475" => "Yemen", # "Yemen (Republic of)" "477" => "Hong Kong", # "Hong Kong (Special Administrative Region of China) - China (People's Republic of)" "478" => "Bosnia & Herzegovina", # "Bosnia and Herzegovina" "501" => "Adelie Land", # "Adelie Land - France" "503" => "Australia", "506" => "Myanmar", # "Myanmar (Union of)" "508" => "Brunei Darussalam", "510" => "Micronesia", # "Micronesia (Federated States of)" "511" => "Palau", # "Palau (Republic of)" "512" => "New Zealand", "514" => "Cambodia", # "Cambodia (Kingdom of)" "515" => "Cambodia", # "Cambodia (Kingdom of)" "516" => "Christmas Is.", # "Christmas Island (Indian Ocean) - Australia" "518" => "Cook Is.", # "Cook Islands - New Zealand" "520" => "Fiji", # "Fiji (Republic of)", "523" => "Cocos (Keeling) Is.", # "Cocos (Keeling) Islands - Australia" "525" => "Indonesia", # "Indonesia (Republic of)" "529" => "Kiribati", # "Kiribati (Republic of)" "531" => "Laos", # "Lao People's Democratic Republic" "533" => "Malaysia", "536" => "N. Mariana Is. - U.S.", # "Northern Mariana Islands (Commonwealth of the) - United States of America" "538" => "Marshall Is.", # "Marshall Islands (Republic of the)" "540" => "New Caledonia", # "New Caledonia - France" "542" => "Niue", # "Niue - New Zealand" "544" => "Nauru", # "Nauru (Republic of)" "546" => "French Polynesia", # "French Polynesia - France" "548" => "Philippines", # "Philippines (Republic of the)" "553" => "Papua New Guinea", "555" => "Pitcairn Is.", # "Pitcairn Island - United Kingdom of Great Britain and Northern Ireland" "557" => "Solomon Islands", "559" => "American Samoa - U.S.", # "American Samoa - United States of America" "561" => "Samoa", # "Samoa (Independent State of)" "563" => "Singapore", # "Singapore (Republic of)" "564" => "Singapore", # "Singapore (Republic of)" "565" => "Singapore", # "Singapore (Republic of)" "566" => "Singapore", # "Singapore (Republic of)" "567" => "Thailand", "570" => "Tonga", # "Tonga (Kingdom of)" "572" => "Tuvalu", "574" => "Viet Nam", # "Viet Nam (Socialist Republic of)" "576" => "Vanuatu", # "Vanuatu (Republic of)" "577" => "Vanuatu", # "Vanuatu (Republic of)" "578" => "Wallis & Futuna Is.", # "Wallis and Futuna Islands - France" "601" => "S. Africa", # "South Africa (Republic of)" "603" => "Angola", # "Angola (Republic of)" "605" => "Algeria", # "Algeria (People's Democratic Republic of)" "607" => "St. Paul & Amsterdam Is.", # "Saint Paul and Amsterdam Islands - France" "608" => "Ascension Is.", # "Ascension Island - United Kingdom of Great Britain and Northern Ireland" "609" => "Burundi", # "Burundi (Republic of)" "610" => "Benin", # "Benin (Republic of)" "611" => "Botswana", # "Botswana (Republic of)" "612" => "Central African Rep.", # "Central African Republic" "613" => "Cameroon", # "Cameroon (Republic of)" "615" => "Congo", # "Congo (Republic of the)" "616" => "Comoros", # "Comoros (Union of the)" "617" => "Cape Verde", # "Cabo Verde (Republic of)" "618" => "Crozet Archipelago", # "Crozet Archipelago - France" "619" => "Cte d'Ivoire", # "Cte d'Ivoire (Republic of)" "620" => "Comoros", # "Comoros (Union of the)" "621" => "Djibouti", # "Djibouti (Republic of)" "622" => "Egypt", # "Egypt (Arab Republic of)" "624" => "Ethiopia", # "Ethiopia (Federal Democratic Republic of)" "625" => "Eritrea", "626" => "Gabonese Rep.", # "Gabonese Republic" "627" => "Ghana", "629" => "Gambia", # "Gambia (Republic of the)" "630" => "Guinea-Bissau", # "Guinea-Bissau (Republic of)" "631" => "Equatorial Guinea", # "Equatorial Guinea (Republic of)" "632" => "Guinea", # "Guinea (Republic of)" "633" => "Burkina Faso", "634" => "Kenya", # "Kenya (Republic of)" "635" => "Kerguelen Is.", # "Kerguelen Islands - France" "636" => "Liberia", # "Liberia (Republic of)" "637" => "Liberia", # "Liberia (Republic of)" "638" => "S. Sudan", # "South Sudan (Republic of)" "642" => "Libya", "644" => "Lesotho", # "Lesotho (Kingdom of)" "645" => "Mauritius", # "Mauritius (Republic of)" "647" => "Madagascar", # "Madagascar (Republic of)" "649" => "Mali", # "Mali (Republic of)" "650" => "Mozambique", # "Mozambique (Republic of)" "654" => "Mauritania", # "Mauritania (Islamic Republic of)" "655" => "Malawi", "656" => "Niger", # "Niger (Republic of the)" "657" => "Nigeria", # "Nigeria (Federal Republic of)" "659" => "Namibia", # "Namibia (Republic of)" "660" => "Reunion", # "Reunion (French Department of) - France" "661" => "Rwanda", # "Rwanda (Republic of)" "662" => "Sudan", # "Sudan (Republic of the)" "663" => "Senegal", # "Senegal (Republic of)" "664" => "Seychelles", # "Seychelles (Republic of)" "665" => "St. Helena", # "Saint Helena - United Kingdom of Great Britain and Northern Ireland" "666" => "Somalia", # "Somalia (Federal Republic of)" "667" => "Sierra Leone", "668" => "Sao Tome & Principe", # "Sao Tome and Principe (Democratic Republic of)" "669" => "Swaziland", # "Swaziland (Kingdom of)" "670" => "Chad", # "Chad (Republic of)" "671" => "Togolese Rep.", # "Togolese Republic" "672" => "Tunisia", "674" => "Tanzania", # "Tanzania (United Republic of)" "675" => "Uganda", # "Uganda (Republic of)", "676" => "Dem. Rep. of the Congo", # "Democratic Republic of the Congo" "677" => "Tanzania", # "Tanzania (United Republic of)" "678" => "Zambia", # "Zambia (Republic of)" "679" => "Zimbabwe", # "Zimbabwe (Republic of)" "701" => "Argentine Rep.", # "Argentine Republic" "710" => "Brazil", # "Brazil (Federative Republic of)" "720" => "Bolivia", # "Bolivia (Plurinational State of)" "725" => "Chile", "730" => "Columbia", # "Colombia (Republic of)" "735" => "Ecuador", "740" => "Falkland Is.", # "Falkland Islands (Malvinas) - United Kingdom of Great Britain and Northern Ireland" "745" => "Guiana", # "Guiana (French Department of) - France" "750" => "Guyana", "755" => "Paraguay", # "Paraguay (Republic of)" "760" => "Peru", "765" => "Suriname", # "Suriname (Republic of)" "770" => "Uruguay", # "Uruguay (Eastern Republic of)" "775" => "Venezuela", # "Venezuela (Bolivarian Republic of)" ); # Main processing loop. Fetch lines from vessel_hash # and print them out on stdio # Format: MILLENIUM FALCON 366978720 U.S. while(my($userID, $vesselName) = each %vessel_hash) { my $country = &decode_MID($userID); printf "%-20s %-9d %s\n",$vesselName,$userID,$country; } exit; # Decode MID out of MMSI ($userID) too: # 8MIDXXXXX Diver's radio (not used in the U.S. in 2013) # MIDXXXXXX Ship # 0MIDXXXXX Group of ships; the U.S. Coast Guard, for example, is 03699999 # 00MIDXXXX Coastal stations # 111MIDXXX SAR (Search and Rescue) aircraft # 99MIDXXXX Aids to Navigation # 98MIDXXXX Auxiliary craft associated with a parent ship # 970MIDXXX AIS SART (Search and Rescue Transmitter) # 972XXXXXX MOB (Man Overboard) device # 974XXXXXX EPIRB (Emergency Position Indicating Radio Beacon) AIS # # NOTE: U.S. ships sometimes incorrectly send "669" for those first 3 digits. # http://www.itu.int/online/mms/glad/cga_mids.sh?lng=E # sub decode_MID { my $userID = shift; my $MID = $userID; if ($userID =~ m/^8.*/) { # Diver's radio $MID =~ s/^8(...).*/$1/; } elsif ($userID =~ m/^00.*/) { # Coastal station $MID =~ s/^00(...).*/$1/; } elsif ($userID =~ m/^0.*/) { # Group of ships $MID =~ s/^0(...).*/$1/; } elsif ($userID =~ m/^111.*/) { # SAR aircraft $MID =~ s/^111(...).*/$1/; } elsif ($userID =~ m/^99.*/) { # Navigation aid $MID =~ s/^99(...).*/$1/; } elsif ($userID =~ m/^98.*/) { # Auxiliary craft $MID =~ s/^98(...).*/$1/; } elsif ($userID =~ m/^970.*/) { # AIS SART $MID =~ s/^970(...).*/$1/; } elsif ($userID =~ m/^972.*/) { # Man overboard device $MID = "MOB"; } elsif ($userID =~ m/^974.*/) { # EPIRB $MID = "EPIRB"; } else { # Ship $MID =~ s/^(...).*/$1/; } my $country = ""; if (defined($countries{$MID})) { $country = $countries{$MID}; } else { $country = "Unknown"; } return $country; } Xastir-Release-2.2.2/scripts/coord-convert.pl000077500000000000000000000202331501463444000211610ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # Written by Paul Lutt, KE7XT. # Released to the public domain. # # # # # Converts between different lat/lon formats. Will also give UMS # position if the lat/lon resides somewhere inside the Seattle area # aeronautical map. # # UMS coordinates have been used in the past by King County, WA SAR. # It can be useful for plotting positions on Green Trails maps and # perhaps other maps. The maps must be 15' topo maps and marked in # tenths of miles along the edge in order to make use of this # coordinate system. # # Web pages which discuss UMS format: # http://www.impulse.net/~mlynch/land_nav.html # http://www.logicsouth.com/~lcoble/dir9/land_nav.htm # http://www.aasar.org/training/academy/navigation.pdf # use lib "${prefix}/lib"; use Coordinate; # WE7U's Coordinate.pm module # Create new Coordinate object my $position = Coordinate->new(); $position->datum("WGS 84"); # Datum print "\n"; print "Examples: 48.123N 122.123W\n"; print " 48 07.380N 122 07.380W\n"; print " 48 07 22.8N 122 07 22.8W\n"; print " 10U 0565264 5330343\n"; while (1) { print "\nEnter a Lat/Long value or UTM value:\n"; # Snag the input $_ = <>; print "\n"; # If the first item has 2 digits and one character and there are # three "words" in the input, we're starting with a UTM value. if (/^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { # printf("Found a UTM value\n"); # We'll convert it to the standard format first and then run # through the rest of the code. $zone = $_; $easting = $_; $northing = $_; $zone =~ s/^(\d\d[a-zA-Z])\s+\w+\s+\w+\s*$/$1/; $easting =~ s/^\d\d[a-zA-Z]\s+(\w+)\s+\w+\s*$/$1/; $northing =~ s/^\d\d[a-zA-Z]\s+\w+\s+(\w+)\s*$/$1/; if ($easting > 999999) { printf("Easting value is too high!\n"); next; } $position->zone($zone); $position->easting($easting); $position->northing($northing); # Convert to lat/lon values $position->utm_to_lat_lon(); # printf("Calculated Lat, Long position(Lat, Long): %f %f\n", # $position->latitude(), # $position->longitude() ); $latitude = $position->latitude(); $longitude = $position->longitude(); $lat_dir = "N"; $long_dir = "E"; if ($latitude < 0.0) { $latitude = abs($latitude); $lat_dir = "S" } if ($longitude < 0.0) { $longitude = abs($longitude); $long_dir = "W"; } # printf("%f%s %f%s\n", $latitude,$lat_dir,$longitude,$long_dir); $_ = sprintf("%f%s %f%s", $latitude,$lat_dir,$longitude,$long_dir); } # Look for lat/long value in the input # Add missing decimal points. s/^(\d+)([NSns])\s+(\d+)([EWew])\s*$/$1.$2 $3.$4/; # Check for N/S/E/W characters in the input. Set the # appropriate flags if found. $lat_dir = "N"; $long_dir = "E"; if (/S/ || /s/) { $lat_dir = "S"; } if (/W/ || /w/) { $long_dir = "W"; } # Filter out these characters from the input tr/nsewNSEW//d; # Convert to DD MM SS format ($lat_deg, $lat_min, $lat_sec, $long_deg, $long_min, $long_sec) = split(' '); # Decimal Degrees? if ($lat_deg =~ /\./) { $long_deg = $lat_min; # Save long_degrees in proper place $temp = $lat_deg; $lat_deg = int $temp; $lat_min = int ((abs($temp) * 60.0) % 60); # Modulus converts to integers, so we bump up by 10 and then # back down. $lat_sec = (abs($temp) * 36000.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_deg; $long_deg = int $temp; $long_min = int ((abs($temp) * 60.0) % 60); $long_sec = (abs($temp) * 36000.0) % 600; $long_sec = $long_sec / 10; } # Decimal Minutes? elsif ($lat_min =~ /\./) { $long_min = $long_deg; # Save long_minutes in proper place $long_deg = $lat_sec; # Save long_degrees in proper place $temp = $lat_min; $lat_min = int abs($temp); $lat_sec = (abs($temp) * 600.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_min; $long_min = int abs($temp); $long_sec = (abs($temp) * 600.0) % 600; $long_sec = $long_sec / 10; } # Decimal Seconds else { # Already in DD MM SS format, don't convert } # Print out the three lat/long formats printf(" Decimal Degrees: %8.5f%s %8.5f%s\n", $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0), $lat_dir, $long_deg + ($long_min/60.0) + ($long_sec/3600.0), $long_dir ); printf(" Degrees/Decimal Minutes: %02d %06.3f%s %02d %06.3f%s\n", $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); printf(" Degrees/Minutes/Dec. Seconds: %02d %02d %4.1f%s %02d %02d %4.1f%s\n", $lat_deg, $lat_min, $lat_sec, $lat_dir, $long_deg, $long_min, $long_sec, $long_dir); # Fill in the coordinate object with the current lat/lon. # Assuming WGS84 datum if ($lat_dir =~ /S/) { $position->latitude( -( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ) ); } else { $position->latitude( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ); } if ($long_dir =~ /W/) { $position->longitude( -( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ) ); } else { $position->longitude( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ); } #printf("%f %f\n",$position->latitude,$position->longitude); $position->lat_lon_to_utm(); printf(" Universal Transverse Mercator: %s %07.0f %07.0f\n", $position->zone(), $position->easting(), $position->northing() ); # Check whether the coordinates are within the SEA aeronautical # map area $lat_err = 0; if ($lat_dir =~ /S/ || $lat_deg < 44 || $lat_deg > 49 || ($lat_deg == 44 && ($lat_min < 30 || ($lat_min == 30 && $lat_sec == 0))) || ($lat_deg == 49 && ($lat_min > 0 || $lat_sec > 0))) { print " lat. out of range "; $lat_err = 1; } $long_err = 0; if ($long_dir =~ /E/ || $long_deg < 117 || $long_deg > 125 || ($long_deg == 117 && ($long_min == 0 && $long_sec == 0)) || ($long_deg == 125 && ($long_min > 0 || $long_sec > 0))) { print " long. out of range"; $long_err = 1; } next if ( $lat_err || $long_err); # Compute UMS coordinates $y_sec = 3600 * ($lat_deg - 44) + 60 * $lat_min + $lat_sec; $y_sec = 18000 - $y_sec; $x_sec = 3600 * ($long_deg - 117) + 60 * $long_min + $long_sec; $x_sec = 28800 - $x_sec; $quad = 32 * int($y_sec / 900) + int($x_sec / 900) + 1; # print "\tx_sec= $x_sec, y_sec= $y_sec, quad= $quad\n"; $y_subquad_offset = int($y_sec / 450); $x_subquad_offset = int($x_sec / 450); if (&even($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} A "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&odd($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} B "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&even($x_subquad_offset) && &odd($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} C "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } else { print " UMS (Green Trails Maps): SEA ${quad} D "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } } sub even { return (($_[0] & 1) == 0); } sub odd { return (($_[0] & 1) == 1); } sub s2m_y { return (int((0.1917966 * $_[0]) + 0.5)); } sub s2m_x { return (int((cos(($lat_deg + ($lat_min / 60.0) + ($lat_sec / 3600.0)) / 57.29578) * (0.1917966 * $_[0])) + 0.5)); } Xastir-Release-2.2.2/scripts/db_gis_mysql.sql000077500000000000000000000044421501463444000212410ustar00rootroot00000000000000-- MYSQL SPATIAL (>4.1) -- Updated by Dan Zubey N7NMD dzubey@openincident.com 03Oct2010 -- -- See the last four lines to set permissions for a user -- to access this database. CREATE DATABASE IF NOT EXISTS xastir; USE xastir; CREATE TABLE version ( version_number INT, compatable_series INT ); INSERT INTO version (version_number,compatable_series) VALUES (1,1); -- MySQL spatial table using geometry POINT rather than lat/long -- CREATE TABLE simpleStationSpatial ( simpleStationId INT PRIMARY KEY NOT NULL AUTO_INCREMENT, station VARCHAR(9) NOT NULL, symbol VARCHAR(1), overlay VARCHAR(1), aprstype VARCHAR(1), transmit_time DATETIME, position POINT, origin VARCHAR(9) NOT NULL DEFAULT '', record_type VARCHAR(1), node_path VARCHAR(56) ); -- Note: Use the asText() function to retrieve data from the position field. -- In a shell, the return values from the raw position field will often -- change the character set in the shell, to avoid this, use asText(position). -- Example query returning the position in WKT format: -- select station, asText(position), transmit_time from simpleStationSpatial; -- MYSQL (default table) CREATE TABLE simpleStation ( simpleStationId INT PRIMARY KEY NOT NULL AUTO_INCREMENT, station VARCHAR(9) NOT NULL, symbol VARCHAR(1), overlay VARCHAR(1), aprstype VARCHAR(1), transmit_time DATETIME, latitude FLOAT, longitude FLOAT, origin VARCHAR(9) NOT NULL DEFAULT '', record_type VARCHAR(1), node_path VARCHAR(56) ); -- Example query to retrieve symbol as aprsworld icon filename. -- select count(*), concat(lpad(ascii(aprstype),3,'0'), '_', lpad(ascii(symbol),3,'0'), '.png') from simpleStationSpatial group by aprstype,symbol; -- *** Permissions *** -- Use the following grants to set up a user with minimal rights -- to the database. -- -- Change the password on the next line and uncomment the next four lines. -- GRANT USAGE ON xastir.* to 'xastir_user'@'localhost' identified by 'set_this_password'; -- GRANT SELECT ON xastir.version TO 'xastir_user'@'localhost'; -- GRANT SELECT, INSERT, UPDATE ON xastir.simpleStation to 'xastir_user'@'localhost'; -- GRANT SELECT, INSERT, UPDATE ON xastir.simpleStationSpatial TO 'xastir_user'@'localhost'; Xastir-Release-2.2.2/scripts/db_gis_postgis.sql000077500000000000000000000062311501463444000215620ustar00rootroot00000000000000-- POSTGRES/POSTGIS create database xastir; --set the password and uncomment --create user xastir_user with encrypted password ''; -- edit pg_hba.conf to allow access from local host --local xastir xastir_user md5 --host xastir xastir_user 127.0.0.1/32 md5 -- run create lang to add plpgsql to xastir db --createlang --dbname=xastir plpgsql -- run lwpostgis script to enable postgis for xastir db --psql -d xastir -f lwpostgis.sql --run the following sql commands in psql --psql xastir create table version ( version_number int, compatable_series int ); grant select on version to xastir_user; insert into version (version_number,compatable_series) values (1,1); create table simpleStation ( simpleStationId serial primary key, station varchar(9) not null, symbol varchar(1), overlay varchar(1), aprstype varchar(1), transmit_time timestamptz not null default now(), origin varchar(9) not null default '', record_type varchar(1), node_path varchar(56), ); create index ssstation on simplestation(station); create index sssymbol on simplestation(symbol); create index sstype on simplestation(aprstype); create index sstransmittime on simplestation(transmit_time); create index ssstationtime on simplestation(station,transmit_time); --select AddGeometryColumn('','simpleStation','position',-1,'POINT',2); --alternately, set geometry explicitly as WGS84 Latitude/Longitude: insert into spatial_ref_sys (srid,auth_name,auth_srid,srtext,proj4text) values (1,'NAD83',4269,'+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs ','+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs '); --- EPSG 4326 : WGS 84 Lat/Long INSERT INTO spatial_ref_sys (srid,auth_name,auth_srid,srtext,proj4text) VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '); select AddGeometryColumn('','simpleStation','position',4326,'POINT',2); grant select, insert, update on simpleStation to xastir_user; grant select, update on simpleStation_simpleStationId_seq to xastir_user; -- the next two grants allow xastir_user to be used in other applications -- such as qgis that need access to the spatial metadata tables grant select on geometry_columns to xastir_user; grant select on spatial_ref_sys to xastir_user; -- 0 update alter table simpleStation add column origin varchar(9) not null default ''; alter table simpleStation add column record_type varchar(1); alter table simpleStation add column node_path varchar(56); -- note - lat/long is transposed in version 0 and version 1 -- example query to list symbols by aprsworld icon filenames -- select count(*), lpad(ascii(aprstype),3,'0') || '_' || lpad(ascii(symbol),3,'0') || '.png' from simpleStation group by aprstype, symbol; -- view to add icon filenames create view simplestationicons as select *, lpad(ascii(aprstype),3,'0') || '_' || lpad(ascii(symbol),3,'0') || '.png' as icon from simpleStation; Xastir-Release-2.2.2/scripts/example_objects.log000066400000000000000000000213171501463444000217100ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # # Compare your results with the Area Object images here after # sucking this file in as a log file (They should appear in the # Pacific Ocean): # # http://www.xastir.org/wiki/index.php/HowTo:Scripts # #Corridors (Line with width in miles) #{1} means a corridor 1 mile on either side of the line N0CALL>APRS:)Corridor1!5012.00N\13033.00Wl130/200{1} N0CALL>APRS:)Corridor2!4955.00N\13000.00Wl630/400{1} N0CALL>APRS:)Corridor3!5012.00N\13000.00Wl130/330{2} N0CALL>APRS:)Corridor4!4957.00N\13033.00Wl630/130{2} N0CALL>APRS:)Corridor5!4800.00N\13000.00Wl100/599{20} #Shape 0, Open Circle N0CALL>APRS:)C-black !5000.00N\13000.00Wl004/004 N0CALL>APRS:)C-blue !5000.00N\13002.00Wl004/104 N0CALL>APRS:)C-green !5000.00N\13004.00Wl004/204 N0CALL>APRS:)C-cyan !5000.00N\13006.00Wl004/304 N0CALL>APRS:)C-red !5000.00N\13008.00Wl004/404 N0CALL>APRS:)C-violet !5000.00N\13010.00Wl004/504 N0CALL>APRS:)C-yellow !5000.00N\13012.00Wl004/604 N0CALL>APRS:)C-gray !5000.00N\13014.00Wl004/704 N0CALL>APRS:)CD-black !5000.00N\13016.00Wl004/804 N0CALL>APRS:)CD-blue !5000.00N\13018.00Wl004/904 N0CALL>APRS:)CD-green !5000.00N\13020.00Wl0041004 N0CALL>APRS:)CD-cyan !5000.00N\13022.00Wl0041104 N0CALL>APRS:)CD-red !5000.00N\13024.00Wl0041204 N0CALL>APRS:)CD-violet!5000.00N\13026.00Wl0041304 N0CALL>APRS:)CD-yellow!5000.00N\13028.00Wl0041404 N0CALL>APRS:)CD-gray !5000.00N\13030.00Wl0041504 #Shape 1, Line Right N0CALL>APRS:)L-black !5001.00N\13000.00Wl104/004 N0CALL>APRS:)L-blue !5001.00N\13002.00Wl104/104 N0CALL>APRS:)L-green !5001.00N\13004.00Wl104/204 N0CALL>APRS:)L-cyan !5001.00N\13006.00Wl104/304 N0CALL>APRS:)L-red !5001.00N\13008.00Wl104/404 N0CALL>APRS:)L-violet !5001.00N\13010.00Wl104/504 N0CALL>APRS:)L-yellow !5001.00N\13012.00Wl104/604 N0CALL>APRS:)L-gray !5001.00N\13014.00Wl104/704 N0CALL>APRS:)LD-black !5001.00N\13016.00Wl104/804 N0CALL>APRS:)LD-blue !5001.00N\13018.00Wl104/904 N0CALL>APRS:)LD-green !5001.00N\13020.00Wl1041004 N0CALL>APRS:)LD-cyan !5001.00N\13022.00Wl1041104 N0CALL>APRS:)LD-red !5001.00N\13024.00Wl1041204 N0CALL>APRS:)LD-violet!5001.00N\13026.00Wl1041304 N0CALL>APRS:)LD-yellow!5001.00N\13028.00Wl1041404 N0CALL>APRS:)LD-gray !5001.00N\13030.00Wl1041504 #Shape 2, Open Ellipse, not defined by Bob N0CALL>APRS:)E-black !5002.00N\13000.00Wl204/004 N0CALL>APRS:)E-blue !5002.00N\13002.00Wl204/104 N0CALL>APRS:)E-green !5002.00N\13004.00Wl204/204 N0CALL>APRS:)E-cyan !5002.00N\13006.00Wl204/304 N0CALL>APRS:)E-red !5002.00N\13008.00Wl204/404 N0CALL>APRS:)E-violet !5002.00N\13010.00Wl204/504 N0CALL>APRS:)E-yellow !5002.00N\13012.00Wl204/604 N0CALL>APRS:)E-gray !5002.00N\13014.00Wl204/704 N0CALL>APRS:)ED-black !5002.00N\13016.00Wl204/804 N0CALL>APRS:)ED-blue !5002.00N\13018.00Wl204/904 N0CALL>APRS:)ED-green !5002.00N\13020.00Wl2041004 N0CALL>APRS:)ED-cyan !5002.00N\13022.00Wl2041104 N0CALL>APRS:)ED-red !5002.00N\13024.00Wl2041204 N0CALL>APRS:)ED-violet!5002.00N\13026.00Wl2041304 N0CALL>APRS:)ED-yellow!5002.00N\13028.00Wl2041404 N0CALL>APRS:)ED-gray !5002.00N\13030.00Wl2041504 #Shape 3, Open Triangle N0CALL>APRS:)T-black !5003.00N\13000.00Wl304/004 N0CALL>APRS:)T-blue !5003.00N\13002.00Wl304/104 N0CALL>APRS:)T-green !5003.00N\13004.00Wl304/204 N0CALL>APRS:)T-cyan !5003.00N\13006.00Wl304/304 N0CALL>APRS:)T-red !5003.00N\13008.00Wl304/404 N0CALL>APRS:)T-violet !5003.00N\13010.00Wl304/504 N0CALL>APRS:)T-yellow !5003.00N\13012.00Wl304/604 N0CALL>APRS:)T-gray !5003.00N\13014.00Wl304/704 N0CALL>APRS:)TD-black !5003.00N\13016.00Wl304/804 N0CALL>APRS:)TD-blue !5003.00N\13018.00Wl304/904 N0CALL>APRS:)TD-green !5003.00N\13020.00Wl3041004 N0CALL>APRS:)TD-cyan !5003.00N\13022.00Wl3041104 N0CALL>APRS:)TD-red !5003.00N\13024.00Wl3041204 N0CALL>APRS:)TD-violet!5003.00N\13026.00Wl3041304 N0CALL>APRS:)TD-yellow!5003.00N\13028.00Wl3041404 N0CALL>APRS:)TD-gray !5003.00N\13030.00Wl3041504 #Shape 4, Open Box N0CALL>APRS:)B-black !5004.00N\13000.00Wl404/004 N0CALL>APRS:)B-blue !5004.00N\13002.00Wl404/104 N0CALL>APRS:)B-green !5004.00N\13004.00Wl404/204 N0CALL>APRS:)B-cyan !5004.00N\13006.00Wl404/304 N0CALL>APRS:)B-red !5004.00N\13008.00Wl404/404 N0CALL>APRS:)B-violet !5004.00N\13010.00Wl404/504 N0CALL>APRS:)B-yellow !5004.00N\13012.00Wl404/604 N0CALL>APRS:)B-gray !5004.00N\13014.00Wl404/704 N0CALL>APRS:)BD-black !5004.00N\13016.00Wl404/804 N0CALL>APRS:)BD-blue !5004.00N\13018.00Wl404/904 N0CALL>APRS:)BD-green !5004.00N\13020.00Wl4041004 N0CALL>APRS:)BD-cyan !5004.00N\13022.00Wl4041104 N0CALL>APRS:)BD-red !5004.00N\13024.00Wl4041204 N0CALL>APRS:)BD-violet!5004.00N\13026.00Wl4041304 N0CALL>APRS:)BD-yellow!5004.00N\13028.00Wl4041404 N0CALL>APRS:)BD-gray !5004.00N\13030.00Wl4041504 #Shape 5, Color-Filled Circle N0CALL>APRS:)CF-black !5005.00N\13000.00Wl504/004 N0CALL>APRS:)CF-blue !5005.00N\13002.00Wl504/104 N0CALL>APRS:)CF-green !5005.00N\13004.00Wl504/204 N0CALL>APRS:)CF-cyan !5005.00N\13006.00Wl504/304 N0CALL>APRS:)CF-red !5005.00N\13008.00Wl504/404 N0CALL>APRS:)CF-violet!5005.00N\13010.00Wl504/504 N0CALL>APRS:)CF-yellow!5005.00N\13012.00Wl504/604 N0CALL>APRS:)CF-gray !5005.00N\13014.00Wl504/704 N0CALL>APRS:)CFDblack !5005.00N\13016.00Wl504/804 N0CALL>APRS:)CFDblue !5005.00N\13018.00Wl504/904 N0CALL>APRS:)CFDgreen !5005.00N\13020.00Wl5041004 N0CALL>APRS:)CFDcyan !5005.00N\13022.00Wl5041104 N0CALL>APRS:)CFDred !5005.00N\13024.00Wl5041204 N0CALL>APRS:)CFDviolet!5005.00N\13026.00Wl5041304 N0CALL>APRS:)CFDyellow!5005.00N\13028.00Wl5041404 N0CALL>APRS:)CFDgray !5005.00N\13030.00Wl5041504 #Shape 6, Line Left N0CALL>APRS:)L2-black !5006.00N\13000.00Wl604/004 N0CALL>APRS:)L2-blue !5006.00N\13002.00Wl604/104 N0CALL>APRS:)L2-green !5006.00N\13004.00Wl604/204 N0CALL>APRS:)L2-cyan !5006.00N\13006.00Wl604/304 N0CALL>APRS:)L2-red !5006.00N\13008.00Wl604/404 N0CALL>APRS:)L2-violet!5006.00N\13010.00Wl604/504 N0CALL>APRS:)L2-yellow!5006.00N\13012.00Wl604/604 N0CALL>APRS:)L2-gray !5006.00N\13014.00Wl604/704 N0CALL>APRS:)L2Dblack !5006.00N\13016.00Wl604/804 N0CALL>APRS:)L2Dblue !5006.00N\13018.00Wl604/904 N0CALL>APRS:)L2Dgreen !5006.00N\13020.00Wl6041004 N0CALL>APRS:)L2Dcyan !5006.00N\13022.00Wl6041104 N0CALL>APRS:)L2Dred !5006.00N\13024.00Wl6041204 N0CALL>APRS:)L2Dviolet!5006.00N\13026.00Wl6041304 N0CALL>APRS:)L2Dyellow!5006.00N\13028.00Wl6041404 N0CALL>APRS:)L2Dgray !5006.00N\13030.00Wl6041504 #Shape 7, Color-Filled Ellipse, not defined by Bob N0CALL>APRS:)E2-black !5007.00N\13000.00Wl704/004 N0CALL>APRS:)E2-blue !5007.00N\13002.00Wl704/104 N0CALL>APRS:)E2-green !5007.00N\13004.00Wl704/204 N0CALL>APRS:)E2-cyan !5007.00N\13006.00Wl704/304 N0CALL>APRS:)E2-red !5007.00N\13008.00Wl704/404 N0CALL>APRS:)E2-violet!5007.00N\13010.00Wl704/504 N0CALL>APRS:)E2-yellow!5007.00N\13012.00Wl704/604 N0CALL>APRS:)E2-gray !5007.00N\13014.00Wl704/704 N0CALL>APRS:)E2Dblack !5007.00N\13016.00Wl704/804 N0CALL>APRS:)E2Dblue !5007.00N\13018.00Wl704/904 N0CALL>APRS:)E2Dgreen !5007.00N\13020.00Wl7041004 N0CALL>APRS:)E2Dcyan !5007.00N\13022.00Wl7041104 N0CALL>APRS:)E2Dred !5007.00N\13024.00Wl7041204 N0CALL>APRS:)E2Dviolet!5007.00N\13026.00Wl7041304 N0CALL>APRS:)E2Dyellow!5007.00N\13028.00Wl7041404 N0CALL>APRS:)E2Dgray !5007.00N\13030.00Wl7041504 #Shape 8, Color-Filled Triangle N0CALL>APRS:)T2-black !5008.00N\13000.00Wl804/004 N0CALL>APRS:)T2-blue !5008.00N\13002.00Wl804/104 N0CALL>APRS:)T2-green !5008.00N\13004.00Wl804/204 N0CALL>APRS:)T2-cyan !5008.00N\13006.00Wl804/304 N0CALL>APRS:)T2-red !5008.00N\13008.00Wl804/404 N0CALL>APRS:)T2-violet!5008.00N\13010.00Wl804/504 N0CALL>APRS:)T2-yellow!5008.00N\13012.00Wl804/604 N0CALL>APRS:)T2-gray !5008.00N\13014.00Wl804/704 N0CALL>APRS:)T2Dblack !5008.00N\13016.00Wl804/804 N0CALL>APRS:)T2Dblue !5008.00N\13018.00Wl804/904 N0CALL>APRS:)T2Dgreen !5008.00N\13020.00Wl8041004 N0CALL>APRS:)T2Dcyan !5008.00N\13022.00Wl8041104 N0CALL>APRS:)T2Dred !5008.00N\13024.00Wl8041204 N0CALL>APRS:)T2Dviolet!5008.00N\13026.00Wl8041304 N0CALL>APRS:)T2Dyellow!5008.00N\13028.00Wl8041404 N0CALL>APRS:)T2Dgray !5008.00N\13030.00Wl8041504 #Shape 9, Color-Filled Box N0CALL>APRS:)B2-black !5009.00N\13000.00Wl904/004 N0CALL>APRS:)B2-blue !5009.00N\13002.00Wl904/104 N0CALL>APRS:)B2-green !5009.00N\13004.00Wl904/204 N0CALL>APRS:)B2-cyan !5009.00N\13006.00Wl904/304 N0CALL>APRS:)B2-red !5009.00N\13008.00Wl904/404 N0CALL>APRS:)B2-violet!5009.00N\13010.00Wl904/504 N0CALL>APRS:)B2-yellow!5009.00N\13012.00Wl904/604 N0CALL>APRS:)B2-gray !5009.00N\13014.00Wl904/704 N0CALL>APRS:)B2Dblack !5009.00N\13016.00Wl904/804 N0CALL>APRS:)B2Dblue !5009.00N\13018.00Wl904/904 N0CALL>APRS:)B2Dgreen !5009.00N\13020.00Wl9041004 N0CALL>APRS:)B2Dcyan !5009.00N\13022.00Wl9041104 N0CALL>APRS:)B2Dred !5009.00N\13024.00Wl9041204 N0CALL>APRS:)B2Dviolet!5009.00N\13026.00Wl9041304 N0CALL>APRS:)B2Dyellow!5009.00N\13028.00Wl9041404 N0CALL>APRS:)B2Dgray !5009.00N\13030.00Wl9041504 Xastir-Release-2.2.2/scripts/geopdf2gtiff.pl000077500000000000000000000164061501463444000207520ustar00rootroot00000000000000#!/usr/bin/env perl ############################################################################### # # Portions Copyright (C) 2000-2023 The Xastir Group # # Script to convert a GeoPDF file with included neatline into a collar-stripped # geotiff in EPSG:4326 projection (WGS84 equidistant cylindrical) in 8-bit # color. # # You must have installed GDAL/OGR, configured to use python in order to use # this script. This is because the script attempts to run rgb2pct.py, which # is only installed if you've built GDAL with python support. # # This also depends on the -cutline and -crop_to_cutline features of # gdalwarp, which are only present in versions of GDAL after 1.8.1. # # Last Edit:$Date$ # Revision:$Revision$ # Last Edited By: $Author$ ############################################################################### use Getopt::Long; my $fudgeNeatline; $result=GetOptions("fixneatline|f"=>\$fudgeNeatline); # Input file is a geopdf: if ($#ARGV<0) { print STDERR "Usage: $0 \n"; exit 1; } my $inputPDF=$ARGV[0]; if (! -e $inputPDF) { print STDERR "File $inputPDF does not exist.\n"; exit 1; } open GDALINFO, "gdalinfo $inputPDF |" or die "can't fork $!"; my $readingCoordSys=0; my $coordSys=""; my $readingMetadata=0; my $neatlinePoly=""; my $minLat=360,$maxLat=-360,$minLon=360,$maxLon=-360,$templat,$templon; while () { if (/^Driver: (.*)$/) { if ($1 ne "PDF/Geospatial PDF") { print STDERR "This script is intended to run only on GeoPDF input files.\n"; exit 1; } next; } if (/^Coordinate System is:/) { $readingCoordSys=1; next; } if ($readingCoordSys == 1) { # This is tricky --- finding the end of the coordinate system # means looking for the first line that starts in column 1 that isn't # the first line of the coordinate system. All lines of the coordinate # system other than the first start with space. if (/^[^ ]/ && $coordSys ne "") { $readingCoordSys=0; next; } else { chomp($_); $coordSys .= $_; next; } } if (/^Metadata:/) { $readingMetadata=1; next; } if ($readingMetadata==1) { if (/^Corner Coordinates:/) { $readingMetadata=0; next; } if (/^ *NEATLINE=(.*)$/) { $neatlinePoly=$1; next; } } if (/^Band ([0-9]+).*Type=([^,]*)/) { $bandinfo[$#bandinfo+1]=$2; next; } if (/^(Upper|Lower) (Left|Right)/) { s/(Upper|Lower) (Left|Right) *\([^)]*\) *//; /\(([^,]*), *([^\)]*)\)/; $templonstr=$1; $templatstr=$2; $templonstr =~ /([0-9]*)d( *[0-9]*)'( *[0-9.]*)"([EW])/; $deg=$1; $min=$2; $sec=$3; $hem=$4; $templon=$deg+$min/60+$sec/3600; $templon *= -1 if ($hem eq "W"); $minLon=$templon if ($templon<$minLon); $maxLon=$templon if ($templon>$maxLon); $templatstr =~ /([0-9]*)d( *[0-9]*)'( *[0-9.]*)"([NS])/; $deg=$1; $min=$2; $sec=$3; $hem=$4; $templat=$deg+$min/60+$sec/3600; $templat *= -1 if ($hem eq "S"); $minLat=$templat if ($templat<$minLat); $maxLat=$templat if ($templat>$maxLat); } } close GDALINFO; if (! $fudgeNeatline) { # Create a CSV for the neatline. OGR will recognize this geometry open CSVFILE, ">$inputPDF.csv"; print CSVFILE "foo,WKT\n"; print CSVFILE "bar,\"$neatlinePoly\"\n"; close CSVFILE; # Unfortunately, there's no easy way to attach a spatial reference system # (SRS) to the csv file so that gdalwarp will recognize it. So make a # virtual layer out of the CSV with the reference system in it. open VRTFILE, ">$inputPDF.vrt"; print VRTFILE "\n"; print VRTFILE " \n"; print VRTFILE " $coordSys\n"; print VRTFILE " $inputPDF.csv\n"; print VRTFILE " wkbPolygon\n"; print VRTFILE " WKT\n"; print VRTFILE " \n"; print VRTFILE "\n"; close VRTFILE; } else { print "User asked us to fudge the neatline, finding nearest 7.5 minute quad boundaries\n"; # Instead of using the neatline specified, round it to nearest 7.5' # quad boundary $left=(int((abs($minLon)-int(abs($minLon)))/.125+.5)*.125+int(abs($minLon)))*($minLon/abs($minLon)); $right=(int((abs($maxLon)-int(abs($maxLon)))/.125+.5)*.125+int(abs($maxLon)))*($maxLon/abs($maxLon)); if ($maxLon<0) { $temp=$left; $left=$right; $right=$temp; } $bottom=(int((abs($minLat)-int(abs($minLat)))/.125+.5)*.125+int(abs($minLat)))*($minLat/abs($minLat)); $top=(int((abs($maxLat)-int(abs($maxLat)))/.125+.5)*.125+int(abs($maxLat)))*($maxLat/abs($maxLat)); if ($maxLat<0) { $temp=$top; $top=$bottom; $bottom=$temp; } open CSVFILE, ">$inputPDF.csv"; print CSVFILE "foo,WKT\n"; print CSVFILE "bar,\"POLYGON(($left $top,$right $top, $right $bottom, $left $bottom, $left $top))\"\n"; close CSVFILE; # Unfortunately, there's no easy way to attach a spatial reference system # (SRS) to the csv file so that gdalwarp will recognize it. So make a # virtual layer out of the CSV with the reference system in it. open VRTFILE, ">$inputPDF.vrt"; print VRTFILE "\n"; print VRTFILE " \n"; print VRTFILE " EPSG:4326\n"; print VRTFILE " $inputPDF.csv\n"; print VRTFILE " wkbPolygon\n"; print VRTFILE " WKT\n"; print VRTFILE " \n"; print VRTFILE "\n"; close VRTFILE; } # The VRT virtual source will now appear to gdal warp as a complete # specification of the neatline, with both coordinates *AND* description of # the coordinate system. This will enable gdalwarp to do the clipping of the # neatline *AND* conversion to a different coordinate system in the same # operation. Had we not done the vrt, gdalwarp would have assumed the # neatline to be in the coordinates of the DESTINATION raster, not the # source raster. $outputTif=$inputPDF; $outputTif =~ s/pdf/tif/i; # We will warp from whatever the coordinate system is into EPSG:4326, the # coordinate system that requires the least work and involves the fewest # approximations from Xastir. #$theGdalWarp="gdalwarp -cutline $inputPDF.vrt -crop_to_cutline -t_srs EPSG:4326 -co \"COMPRESS=PACKBITS\" $inputPDF $outputTif"; $theGdalWarp="gdalwarp -cutline $inputPDF.vrt -crop_to_cutline -t_srs EPSG:4326 $inputPDF $outputTif"; system ($theGdalWarp) == 0 or die "System $theGdalWarp failed: $?"; if ($#bandinfo>0) { print "This is a multi-band raster, dithering...\n"; system ("mv $outputTif $$.tif"); # $theRGB2PCT="rgb2pct.py $$.tif $$-2.tif"; $theRGB2PCT="rgb2pct.py $$.tif $outputTif"; system ($theRGB2PCT) == 0 or die "Could not run rgb2pct: $?"; # system("gdal_translate -co \"COMPRESS=PACKBITS\" $$-2.tif $outputTif") == 0 or die "Could not gdal_translate: $?"; system("rm -f $$.tif $$-2.tif"); } # now clean up our mess: system ("rm $inputPDF.csv $inputPDF.vrt"); Xastir-Release-2.2.2/scripts/get-BOMdata.in000077500000000000000000000055141501463444000204210ustar00rootroot00000000000000#!/bin/sh # # # Script to retrieve BOM data files. # # Originally written 2006/03/07 by Steven, WM5Z, and Curt, WE7U. # Modified from original get-NWSdata script by Geoff VK2XJG. # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # See README.MAPS for a bit more information on the program. # # # NOTE: Run this script as root. # # MAINTAINERS: Go here to find out what the latest versions are: # FILE1="gfe_public_weather" # BOM Spatial: Public Warning Zone Boundaries FILE2="gfe_metro_areas" # BOM Spatial: Metropolitan Warning Area Boundaries FILE3="gfe_coastal_water" # BOM Spatial: Coastal Forecast Marine Zones FILE4="gfe_coastal_water_warning" # BOM Spatial: Coastal Warning Zones FILE5="gfe_local_effects" # BOM Spatial: Local Effects Areas FILE6="gfe_fire_weather" # BOM Spatial: Fire Weather Zone Boundaries FILE7="LGA08aAust" # Local Government Area Boundaries prefix=@prefix@ cd ${prefix}/share/xastir/Counties # Remove any old zip files hanging around in this directory # rm -f *.zip 2>&1 >/dev/null # Fetch new copies, unzip into place, delete archive. # # DIR=wsom for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6; do if [ -e $d.shp ] then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-30 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget ftp://ftp.bom.gov.au/anon/home/adfd/spatial/$d.zip unzip $d.zip rm -f *.zip mv $d*.shx $d.shx 2>&1 >/dev/null mv $d*.shp $d.shp 2>&1 >/dev/null mv $d*.dbf $d.dbf 2>&1 >/dev/null mv $d*.prj $d.prj 2>&1 >/dev/null mv $d*.sbx $d.sbx 2>&1 >/dev/null mv $d*.sbn $d.sbn 2>&1 >/dev/null fi done DIR=county for d in $FILE7; do if [ -e $d.shp ] then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget http://wxsvr.aprs.net.au/shapefiles/$d\_shape.zip unzip $d\_shape.zip rm -f *.zip fi done Xastir-Release-2.2.2/scripts/get-NWSdata.in000077500000000000000000000101671501463444000204530ustar00rootroot00000000000000#!/bin/sh # # Script to retrieve NWS data files. # # Run this from the INSTALLED location of the script, i.e. # /usr/local/share/xastir/scripts # or /usr/share/xastir/scripts # # # Originally written 2006/03/07 by Steven, WM5Z, and Curt, WE7U. # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # See README.MAPS for a bit more information on the program. # # # NOTE: Run this script as root. # # MAINTAINERS: Go here to find out what the latest versions are: # # # Please only have ONE of each variable listed here! Note that the "Valid # Date" listed on the NWS web pages is the date at which the Shapefile # should START to be used. Don't just blindly put the newest filename # here if that start-date hasn't arrived yet! # FILE1="w_18mr25" # GREEN: NWSM Library: County Warning Area Boundaries FILE2="z_18mr25" # GREEN: NWSM Library: Public Forecast Zone Boundaries FILE3="mz18mr25" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE4="oz18mr25" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE5="hz20fe25" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE6="fz18mr25" # GREEN: NWSM Library: Fire Weather Zone Boundaries FILE7="c_18mr25" # RED: Counties, States, Provinces: U.S. Counties prefix=@prefix@ cd ${prefix}/share/xastir/Counties || exit 1 # Remove any old zip files hanging around in this directory # rm -f *.zip 2>&1 >/dev/null # Fetch new copies, unzip into place, delete archive. # # DIR=WSOM for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6; do if [ -e $d.shp ]; then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget https://www.weather.gov/source/gis/Shapefiles/$DIR/$d.zip unzip $d.zip rm -f *.zip fi done DIR=County for d in $FILE7; do if [ -e $d.shp ]; then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget https://www.weather.gov/source/gis/Shapefiles/$DIR/$d.zip unzip $d.zip rm -f *.zip fi done #################### # After download/install of map files above, run commands such as these: # # cd /usr/local/share/xastir; testdbfawk -D config -d Counties/mz11au16.dbf 2>&1 | head -5 # cd /usr/local/share/xastir; testdbfawk -D config -d Counties/w_11au16.dbf 2>&1 | head -5 # # to determine whether there's dbfawk support for each of the NWS files. NWS # changes the signature on their files often so we need to create a new # dbfawk for each in xastir/config, test it, then add it into the # Makefile.am file there and commit, then do another "make install" to put # the dbfawk's into place. # Fixed the issue where there's an 'a' or 'b' after the filename root. NWS likes # to do that, but have non-a/b files extracted from the zip, which made the below # tests fail. #################### # for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6 $FILE7; do e=`echo $d | sed -e's/\(.*[0-9]\)[a-f]$/\1/'` if [ -e $e.dbf ]; then echo echo $e.dbf # Run in a separate shell so we don't mess up the current directory for the -e test above (cd ${prefix}/share/xastir; ${prefix}/bin/testdbfawk -D config -d Counties/$e.dbf 2>&1 | head -3 | tail -1) fi done echo Xastir-Release-2.2.2/scripts/get-fcc-rac.pl.in000077500000000000000000000076621501463444000210700ustar00rootroot00000000000000#!/usr/bin/env perl # # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # Updated on 7/5/03 to reflect the new directory structure # N0VH # # Note: Run this script as root in order to write the files into the # destination directory listed below, or change directory write access. use File::Basename; $prefix="@prefix@"; my $XASTIR_BASE="${prefix}/share/xastir"; # This script uses temporary storage space in /var/tmp to do its work. chdir "/var/tmp"; ##################################################################### # Get the RAC database, process it. # Download size: ~2MB # Final file size: ~13MB ##################################################################### # $file = "amateur.zip"; #$file2 = "amateur.rpt"; $file2 = "amateur.txt"; print STDERR "*********************************\n"; print STDERR "*** Fetching the RAC database ***\n"; print STDERR "*********************************\n"; #`wget -c http://205.236.99.41/%7Eindicatif/download/$file`; `wget -c http://apc-cap.ic.gc.ca/datafiles/$file`; if (-e $file && -r $file && -f $file) { print STDERR "***********************************\n"; print STDERR "*** Installing the RAC database ***\n"; print STDERR "***********************************\n"; `unzip $file $file2`; `mv $file2 $XASTIR_BASE/fcc/AMACALL.LST`; } # Remove the RAC download files unlink $file, $file2; ##################################################################### # Get the FCC database, process it. # Download size: ~84MB # Final file size: ~101MB ##################################################################### # my $file = "l_amat.zip"; my $file2 = "EN.dat"; print STDERR "*********************************\n"; print STDERR "*** Fetching the FCC database ***\n"; print STDERR "*********************************\n"; `wget -c ftp://wirelessftp.fcc.gov/pub/uls/complete/$file`; if (-e $file && -r $file && -f $file) { my $file_out = "$XASTIR_BASE/fcc/$file2"; # Get rid of characters "^M^M^J" which are sometimes present, sort # the file by callsign & remove old entries for vanity call access. print STDERR "*****************************************************\n"; print STDERR "*** Filtering/sorting/installing the FCC database ***\n"; print STDERR "*****************************************************\n"; my %from = (); open FILE, "unzip -p $file $file2|" or die "Can't open $file2 in $file : $!"; open FILE_OUT, '|-', "sort -k 5,5 -t \\| -o $file_out" or die "Can't sort $file_out : $!"; while( ) { if (/^EN\|(\d+)\|\|\|(\w+)\|.*/) { $x = $1; $z = $2; chop; chop; $y = $_; if (defined $from{$2}) { # check for vanity reassignment if ($from{$z} =~ /^EN\|(\d+)\|\|\|(\w+)\|.*/) { if ($1 < $x) { $replaced++; $from{$2} = $y; } } } else { $from{$2} = $_; } } } close FILE; for my $callsign ( keys %from ) { $total++; print FILE_OUT "$from{$callsign}\n"; } close FILE_OUT; print STDERR "Total callsigns: " . $total . ".\n"; print STDERR " Replaced callsigns: " . $replaced . ".\n"; } # Remove the FCC download files unlink $file; print STDERR "*************\n"; print STDERR "*** Done! ***\n"; print STDERR "*************\n"; Xastir-Release-2.2.2/scripts/get-gnis.in000077500000000000000000000043151501463444000201100ustar00rootroot00000000000000#!/bin/sh # # Script to retrieve GNIS files by state. # # Written 20041205 Dan Brown N8YSZ # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # Look at the README for more information on the program. # GNIS_SITE=https://geonames.usgs.gov/docs/stategaz SUFFIX=_Features prefix=@prefix@ if [ $# -lt 1 ] then printf "%s: error - Need at least one state to download\n" $0 printf "Usage: %s ST [ST]... \n" $0 exit 1 fi cd /tmp while [ $1 ] do MYSTATE=`printf ${1} | tr a-z A-Z ` printf "Retrieving GNIS file for %s\n" ${MYSTATE} rm -f ${MYSTATE}${SUFFIX}.zip ${MYSTATE}${SUFFIX}_20*.txt if (wget ${GNIS_SITE}/${MYSTATE}${SUFFIX}.zip) then if ( [ -f ${MYSTATE}${SUFFIX}.zip ] ) then unzip ${MYSTATE}${SUFFIX}.zip GNIS_FILE=`ls -t ${MYSTATE}${SUFFIX}*.txt | head -1` else GNIS_FILE="badfiledownload" fi else SUFFIX=_Features_20191101 rm -f ${MYSTATE}${SUFFIX}.zip ${MYSTATE}${SUFFIX}.txt wget ${GNIS_SITE}/${MYSTATE}${SUFFIX}.txt GNIS_FILE=${MYSTATE}${SUFFIX}.txt fi if ( [ -f ${GNIS_FILE} ] ) then printf "File successfully downloaded. Moving to ${prefix}/share/xastir/GNIS\n" sudo mv ${GNIS_FILE} ${prefix}/share/xastir/GNIS/${MYSTATE}.gnis if [ ${MYSTATE} = "AK" -o ${MYSTATE} = "HI" ]; then sudo recode utf16..utf8 ${prefix}/share/xastir/GNIS/${MYSTATE}.gnis fi else printf "File for %s not successfully downloaded.\n" ${MYSTATE} fi shift done Xastir-Release-2.2.2/scripts/gpx2shape000077500000000000000000000137651501463444000177000ustar00rootroot00000000000000#!/usr/bin/env perl # # Copyright (C) 2006 James Washer # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # use strict; use XML::Simple; use Getopt::Std; use Geo::Shapelib qw/:all/; my $routenum=1; my @vertices; my $shp; my ($comment,$notes,$elevation)=("no comment", "no note",-9999); my %shapetype = ( wpt => 1, rte => 3, trk => 3 ); our ( $opt_v, $opt_t, $opt_w, $opt_r, $opt_d, $opt_s); getopts("vtwrds");#v=verbose t=tracks w=waypoints r=routes d=dbfawk s=shapefile_prefix print " args are \"@ARGV\"vals are $opt_t, $opt_w, $opt_r, $opt_d\n" if $opt_v; my $f = $ARGV[0]; $opt_s =$ARGV[0]; $opt_s =~ s/.gpx$//; print "shapename is $opt_s\n" if $opt_v; my $xml = XMLin($f,ForceArray => 1); process_rte() if $opt_r; process_trk() if $opt_t; process_wpt() if $opt_w; exit; sub dumpit{ use Data::Dumper; print Dumper($xml); exit; } ################################################################# ###################### SHAPEFILE SETUP ####################### ################################################################# sub init_shape{ my $type=shift; $shp = new Geo::Shapelib; $shp->{Name}=${opt_s}."-".$type; $shp->{Shapetype}= $shapetype{$type}; $shp->{FieldNames} = [ 'Name', 'Comment', 'Notes', 'Elevation' ]; $shp->{FieldTypes} = [ 'String:40','String:40','String:100','Integer:8' ]; } sub save_shape{ $shp->save(); } sub do_shape{ my($type,$name,$comment,$notes,$elevation)=@_; push @{$shp->{Shapes}}, { SHPType => $shapetype{$type}, ShapeID => $name, NVertices => scalar @vertices, Vertices => [ @vertices ] }; push @{$shp->{ShapeRecords}}, [ $name, $comment, $notes, $elevation]; print "\t\tdo_shape $name $type ",scalar @vertices,"\n" if $opt_v; } ################################################################# ###################### ROUTE PROCESSING ####################### ################################################################# sub process_rte{ print "Process Route called\n"; unless(exists $xml->{rte}){ print "\tNo Routes\n" if $opt_v; return; } my $aref=$xml->{rte}; return unless defined $aref; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('rte'); foreach my $rref ( @$aref ){ my $name="Route.$routenum++"; $name=$rref->{name}->[0] if defined $rref->{name}; print "\tProcessing route \"$name\"\n" if $opt_v; @vertices=(); do_route($rref->{rtept}); do_shape('rte',$name,"","",""); } save_shape(); } sub do_route{ my $rtept_ref=shift; die "do_route Unexpected reference $rtept_ref\n" unless ref($rtept_ref) eq "ARRAY"; foreach my $rtept ( @$rtept_ref ){ #print "\t\t$rtept->{lon} $rtept->{lat} $rtept->{name}->[0] $rtept->{sym}->[0]\n"; my $snell=get_snell($rtept); print_snell($snell) if $opt_v; push @vertices, [ $snell->{lon}, $snell->{lat} ]; } } ################################################################# ###################### TRACK PROCESSING ####################### ################################################################# sub process_trk{ print "Process Track called\n"; unless(exists $xml->{trk}){ print "\tNo Tracks\n" if $opt_v; return; } my $aref=$xml->{trk}; my $aref=$xml->{trk}; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('trk'); foreach my $tref( @$aref ){ print "Track $tref->{name}->[0]\n" if $opt_v; @vertices=(); foreach my $ele ( @{$tref->{trkseg}->[0]->{trkpt}}){ my $snell=get_snell($ele); print_snell($snell) if $opt_v; push @vertices, [ $snell->{lon}, $snell->{lat} ]; } do_shape('trk',$tref->{name}->[0],"","",""); } save_shape(); } sub do_trk{ my $trk_aref=shift; die "Unexpected reference $trk_aref\n" unless ref($trk_aref) eq "ARRAY"; } ################################################################# ##################### WAYPOINT PROCESSING ####################### ################################################################# sub process_wpt{ print "Process Waypoint called\n"; unless(exists $xml->{wpt}){ print "\tNo Waypoints\n" if $opt_v; return; } my $aref=$xml->{wpt}; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('wpt'); foreach my $wref ( @$aref ){ my $snell=get_snell($wref); print_snell($snell) if $opt_v; @vertices=[ $snell->{lon}, $snell->{lat} ]; do_shape('wpt',$snell->{name},$snell->{cmt},$snell->{ele}); } save_shape(); } ################################################################# ################################################################# ################################################################# #cute "SNELL" is Symbol Name Elevation Latitude Longitude sub get_snell { my $ref=shift; my %val=(lat => "0.0", lon => "0.0", ele => "0.0", name => "NoName", sym => "Waypoint", cmt => "NoComment"); $val{lon}=$ref->{lon} if exists $ref->{lon}; $val{lat}=$ref->{lat} if exists $ref->{lat}; $val{name}=$ref->{name}->[0] if exists $ref->{name} and exists $ref->{name}->[0]; $val{sym}=$ref->{sym}->[0] if exists $ref->{sym}; $val{ele}=$ref->{ele}->[0] if exists $ref->{ele}; $val{cmt}=$ref->{cmt}->[0] if exists $ref->{cmt}; return \%val; } sub print_snell { my $snell=shift; print "\t\t$snell->{lon} $snell->{lat} $snell->{ele} $snell->{name} $snell->{sym}\n"; } ################################################################# ################################################################# ################################################################# Xastir-Release-2.2.2/scripts/icontable.pl.in000077500000000000000000000120531501463444000207430ustar00rootroot00000000000000#!/usr/bin/env perl # XASTIR icon table overview generator 20.02.01 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an overview graphics with all symbols used by Xastir # Output is as a XPM file to STDOUT # typical call: icontable.pl > symbols.xpm #-------------------------------------------------------------------------- use File::Basename; $prefix="@prefix@"; # symbols file from XASTIR V2.1, change the path for your environment $SYMBFILE = $prefix."/share/xastir/symbols/symbols.dat"; #-------------------------------------------------------------------------- %sympix = (); $lasttable = $table; $lastsymbol = $symbol; $tablist = "/\\"; @coltab = qw(#FFFF00 #CD6500 #A020F0 #CCCCCC #CD0000 #FF4040 #CD3333 #00008B #00BFFF #006400 #EE0000 #00CD00 #0000CD #FFFFFF #5A5A5A #878787 #454545 #000000 None); setuppics(); #storepics(); # store all icons as separate XPM files exit; #-------------------------------------------------------------------------- sub setuppics { my $table = ''; my $symbol = ''; my ($i,$j,$c); my $line; my $head; my $str; my $pix; my $pixstr; if (-f $SYMBFILE) { if (open(FH, "<$SYMBFILE")) { my %col = (); SYM: while() { last if (/DONE/); if (/TABLE (.)/) { $table = $1; if(length($_)>20) { $descr = 1 } next; } if (/APRS (.)/) { $symbol = $1; next if ($table ne '/' && $table ne '\\'); # ignore other $pixstr = ''; for ($i=0;$i<20;$i++) { $line = ; $line =~ s/\n//; $line =~ s/\r//; next SYM if (length($line) != 20); $pixstr .= $line; for ($j=0;$j<20;$j++) { $c = substr($line,$j,1); $col{$c} = $c; } } $sympix{$table.$symbol} = $pixstr; } } $str = ""; for ($i=0;$i<20;$i++) { $str .= "...................."; } $sympix{" "} = $str; $head = ''; $j = 0; foreach $c (keys %col) { $head .= colstr($c); $j++; } $head = "/* XPM */{\"337 258 $j 1 \",\n".$head; # 12 lines with 16 symbols each x 337 y $pix = ""; foreach $table ("/","\\") { for ($i=2;$i<8;$i++) { # symbol row $pix .= "\"".("q" x 337)."\",\n"; # black hor line for ($j=0;$j<20;$j++) { # scan line $pix .= "\""; # start of scan line for ($k=0;$k<16;$k++) { # symbol column $pix .= "q"; # vert line $symbol = chr($i*16+$k); $pix .= substr(getpic($table.$symbol),$j*20,20); } $pix .= "q\",\n"; # vert line } } if ($table eq "\\") { # { $pix .= "\"".("q" x 337)."\"};\n"; # black hor line } else { $pix .= "\"".("q" x 337)."\",\n"; # black hor line for ($i=0;$i<4;$i++) { $pix .= "\"".("." x 337)."\",\n"; # hor space } } } printf($head.$pix); close(FH); } } } #-------------------------------------------------------------------------- sub colstr { # setup string for color my ($c) = @_; if ($c eq '#') { # Yellow $cidx = 0; } elsif ($c ge 'a' && $c le 'q') { $cidx = ord($c)-ord('a')+1; } else { $cidx = @coltab-1; # Transparent } return("\"$c c $coltab[$cidx]\",\n"); } #-------------------------------------------------------------------------- sub getpic { my ($id) = @_; $str = $sympix{$id}; if (! $str) { $str = $sympix{" "}; # default } $str; } #-------------------------------------------------------------------------- sub storepics { # extract all icons to files foreach $cc (keys %sympix) { $fname = sprintf("Aprs%2.2X%2.2X.xpm",ord(substr($cc,0,1)),ord(substr($cc,1,1))); if (open(FH,">$fname")) { printf(FH "%s",getpic($cc)); close(FH); } } } #-------------------------------------------------------------------------- Xastir-Release-2.2.2/scripts/inf2geo.pl000077500000000000000000000151721501463444000177340ustar00rootroot00000000000000#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # # # Invoke this script against one or more info files by typing: # # inf2geo.pl filename.inf # -or- # inf2geo.pl *.inf # # To process all .inf files in that directory. # # Note: This script requires GraphicsMagick or ImageMagick packages # to be installed before it will function properly. Install one of # these via your package manager. # # # What the script does for you: # Read in .inf file (from Ui-View) # Convert the lat/long coordinates into dd.dddd format # Get the image extents via "identify -ping filename" or # "gm identify -ping filename". # Write out the .geo file # Note that this program assumes (and converts to) # lower-case for the filename. # # Note: It appears that .INF files store the lat/lon # in DD.MM.MMMM format. Converting the script to this # format. # # 2003-08-15 ZL2UMF: add processing multiple files in one go (masks and whot-not) # so you can convert all your ui-view maps in one step #use strict; use IO::File; #go through every filename passed to this script #printf("ARGV:%d\n",$#ARGV); if ($#ARGV == -1) { # No filenames on the command line printf("\n\n\nNo filenames specified. Invoke this script against one\n"); printf("or more .inf files by typing:\n\n"); printf(" inf2geo.pl filename.inf\n"); printf("-or-\n"); printf(" inf2geo.pl *.inf\n\n"); printf("To process all .inf files in that directory.\n\n"); exit; } else { foreach my $file (@ARGV) { print "*** $file ***\n"; #make a geo of this file makeGeo ($file); } } exit; #just in case sub makeGeo { my $inf_filename = shift; my $filename = $inf_filename; $filename =~ s/\.inf$//i; my $geo_filename = $filename . ".geo"; # $inf = IO::File->new("< $ARGV[0].inf") # or $inf = IO::File->new("< $ARGV[0].INF") # or $inf = IO::File->new("< $ARGV[0].Inf") #skip this file if geo already exists return print "$filename.geo already exists, will not overwrite\n" if( -e "$filename.geo" ); #read the inf file my $inf = IO::File->new ( "< $inf_filename" ) or return print "\nCouldn't open $inf_filename for reading:\n$!\n\n"; #make the new geo file $geo = IO::File->new("> $geo_filename") or return print "Couldn't open $geo_filename for writing: $!\n"; $upper_left = $inf->getline(); my ($tp0_lon, $tp0_lat) = split(',', $upper_left); chomp($tp0_lat); # Reverse them if ( ($tp0_lat =~ /E/) || ($tp0_lat =~ /W/) ) { $temp = $tp0_lat; $tp0_lat = $tp0_lon; $tp0_lon = $temp; } $lower_right = $inf->getline(); ($tp1_lon, $tp1_lat) = split(',', $lower_right); chomp($tp1_lat); # Reverse them if ( ($tp1_lat =~ /E/) || ($tp1_lat =~ /W/) ) { $temp = $tp1_lat; $tp1_lat = $tp1_lon; $tp1_lon = $temp; } #do some maths $tp0_lat2 = &convert($tp0_lat) or return; $tp0_lon2 = &convert($tp0_lon) or return; $tp1_lat2 = &convert($tp1_lat) or return; $tp1_lon2 = &convert($tp1_lon) or return; my ($final_filename, $string) = &findImageFile($filename) or return; # The format returned by string changed from this: # test.gif 1148x830+0+0 PseudoClass 256c 48kb GIF 1s # to this: # test.gif GIF 1148x830+0+0 PseudoClass 256c Palette 8-bit 48kb 0.4u 0:01 # in later versions of ImageMagick. # # GraphicsMagick returns a string like this: # i4-mo.gif GIF 1020x581+0+0 PseudoClass 256c 8-bit 475.8k 0.050u 0:01 # chomp($string); $string =~ s/.*\s(\d+x\d+).*/$1/; # Grab the 1148x830 portion #print "String: $string\n"; $x = $y = $string; $x =~ s/(\d+)x\d+/$1/; $y =~ s/\d+x(\d+)/$1/; #print "X: $x\nY: $y\n"; $x1 = $x - 1; # We start numbering pixels at zero, not 1 $y1 = $y - 1; # We start numbering pixels at zero, not 1 #print "X: $x\nY: $y\n"; #print "X1: $x1\nY1: $y1\n"; #write to the geo file printf $geo "FILENAME $final_filename\n"; printf $geo "TIEPOINT 0\t\t0\t$tp0_lon2\t$tp0_lat2\n"; printf $geo "TIEPOINT $x1\t$y1\t$tp1_lon2\t$tp1_lat2\n"; printf $geo "IMAGESIZE $x\t$y\n"; printf $geo "#$string\n"; printf $geo "#\n# Converted from a .INF file by WE7U's inf2geo.pl script\n#\n"; $inf->close(); $geo->close(); } sub convert { #print "$_[0] -> "; ($dd,$mm,$mm2) = split('\.', $_[0]); $mm2 =~ s/(\d+).*/$1/; $mm = $mm . "\." . $mm2; $number = $dd + ($mm / 60.0); if ( ($_[0] =~ /S/) || ($_[0] =~ /s/) || ($_[0] =~ /W/) || ($_[0] =~ /w/) ) { $number = -$number; } # Latitude bound checking if ( ($_[0] =~ /S/) || ($_[0] =~ /s/) || ($_[0] =~ /N/) || ($_[0] =~ /n/) ) { if ($dd > 90) { print "Latitude degrees out-of-bounds: $dd. Must be <= 90\n"; return; } if ($mm >= 60) { print "Latitude minutes out-of-bounds: $mm. Must be < 60\n"; return; } if (abs($number) > 90.0) { print "Latitude out-of-bounds: $number. Must be between -90 and +90\n"; return; } } # Longitude bounds checking else { if ($dd > 180) { print "Longitude degrees out-of-bounds: $dd. Must be <= 180\n"; return; } if ($mm >= 60) { print "Longitude minutes out-of-bounds: $mm. Must be < 60\n"; return; } if (abs($number) > 180.0) { print "Longitude out-of-bounds: $number. Must be between -180 and +180\n"; return; } } #print "$number\n"; #print "Temp = $temp\n"; return($number); } sub findImageFile { $filename = shift; @extensions = ("gif", "bmp", "jpg", "png", "emf"); foreach $xtn (@extensions) { $try_filename = "$filename.$xtn"; # print "Looking for $try_filename\n"; # Try GraphicsMagick's 'gm' first $string = `gm identify -ping $try_filename 2>/dev/null`; if ($string eq "") { # Else try ImageMagick's 'identify' $string = `identify -ping $try_filename 2>/dev/null`; } if ($string ne "") { # Found the file and GM or IM $filename = $try_filename; $image_size = $string; } } if ($image_size eq "") { print "Image file not found for $filename, may be be a case problem\n" ; print "or a problem finding GraphicsMagick's 'gm' or ImageMagick's 'identify' program\n"; print "Make sure that either GraphicsMagick or ImageMagick is installed.\n"; return; } print "Found this image: $image_size\n"; return ($filename, $image_size); } Xastir-Release-2.2.2/scripts/kiss-off.pl000077500000000000000000000023531501463444000201210ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2004-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will send the proper characters to STDOUT to command a # KISS TNC out of KISS mode. Redirect it to the port that the TNC # is connected to. Turn off the port in Xastir first. # It is assumed that the baud rate on the port and the baud rate of # the TNC match, if not, this won't work. If you've just been using # the TNC in Xastir, they probably match. # Use the script like this: # # ./kiss-off.pl >/dev/ttyS1 # sleep 1; printf("%c%c%c", 192, 255, 192); sleep 1; Xastir-Release-2.2.2/scripts/kml_snapshot_feed.kml000066400000000000000000000004371501463444000222330ustar00rootroot00000000000000 http://www.example.com/tracks/screenshot.kml onExpire Xastir-Release-2.2.2/scripts/kml_snapshot_to_web.sh000066400000000000000000000027101501463444000224320ustar00rootroot00000000000000#!/usr/bin/env bash # This shell script copies Xastir snapshots from the directory in which # they are created ~/.xastir/temp to a directory where a web server can deliver # them as a kml feed to overlay the current snapshot from on the terrain in a kml # capable application that is subscribed to the feed. # # You will need to set two parameters for this script: # 1. set DIR= to the directory into which you wish to copy the snapshot files. # This can be a directory on a remote webserver mounted using sshfs. # 2. change www.example.com to the address of your webserver. You will also # need to change the link specified in kml_snapshot_feed.kml # # You can copy the kml_snapshot_feed.kml into the web folder, and load the # http://www.example.com/tracks/kml_snapshot_feed.kml file into your KML # application instead of http://www.example.com/tracks/snapshot.kml, and run # this shell script with cron to periodically update the snapshot.kml file. # This should enable your KML application to refresh the snapshots in sync # with their creation by Xastir. # # Note: GE will load jpg files but not png files, so ImageMagick's # convert is used here to convert the snapshot.png produced by Xastir to # a snapshot.jpg file. # DIR=/var/www/htdocs/tracks cd ~/.xastir/tmp convert ./snapshot.png $DIR/snapshot.jpg cat snapshot.kml | gawk -- ' { gsub(//,"&http://www.example.com/tracks/") } { gsub(/snapshot.png/,"snapshot.jpg") } { print } ' > $DIR/snapshot.kml Xastir-Release-2.2.2/scripts/langElmerFudd.pl000077500000000000000000000045321501463444000211120ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langElmerFudd.pl -split language-ElmerFudd.sys # or # ../scripts/langElmerFudd.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://www.siafoo.net/snippet/133 # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-ElmerFudd.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/[rl]/w/g; s/[RL]/W/g; s/([Qq])u/$1w/g; s/th(\b)/f/g; s/TH(\b)/F/g; s/th/d/g; s/Th/D/g; s/([Nn])[.]/$1, uh-hah-hah-hah./g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.2/scripts/langMuppetsChef.pl000077500000000000000000000062721501463444000214710ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langMuppetsChef.pl -split language-MuppetsChef.sys # or # ../scripts/langMuppetsChef.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.siafoo.net/snippet/133 # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-MuppetsChef.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/An/Un/g; s/an/un/g; s/Au/Oo/g; s/au/oo/g; s/a\b/e/g; s/A\b/E/g; s/en\b/ee/g; s/\bew/oo/g; s/\be\b/e-a/g; s/\be/i/g; s/\bE/I/g; s/\bf/ff/g; s/\bir/ur/g; s/(\w*?)i(\w*?)$/$1ee$2/g; s/\bow/oo/g; s/\bo/oo/g; s/\bO/Oo/g; s/the/zee/g; s/The/Zee/g; s/th\b/t/g; s/\btion/shun/g; s/\bu/oo/g; s/\bU/Oo/g; s/v/f/g; s/V/F/g; s/w/w/g; s/W/W/g; s/([a-z])[.]/$&. Bork Bork Bork!/g; # From the text-filter-suite: s/(\w)ew/$1oo/g; s/(\w)ow/$1oo/g; s/(\W)o/$1oo/g; s/(\W)O/$1Oo/g; s/(\w)u/$1oo/g; s/(\w)U/$1Oo/g; s/a(\w)/e$1/g; s/A(\w)/E$1/g; s/en(\W)/ee$1/g; s/(\w)e(\W)/$1e-a$2/g; s/(\W)e/$1i/g; s/(\W)E/$1I/g; s/(\w)f/$1ff/g; s/(\w)ir/$1ur/g; s/([a-m])i/$1ee/g; s/([A-M])i/$1EE/g; s/(\w)o/$1u/g; s/the/zee/g; s/The/Zee/g; s/th(\W)/t$1/g; s/(\w)tion/$1shun/g; s/v/f/g; s/V/F/g; s/w/v/g; s/W/V/g; s/f{2,}/ff/g; s/o{2,}/oo/g; s/e{2,}/ee/g; # s/([\.!\?])\s*(]+>)?\s*$/$1 Bork Bork Bork!$2/g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.2/scripts/langOldeEnglish.pl000077500000000000000000000060151501463444000214360ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langOldeEnglish.pl -split language-OldeEnglish.sys # or # ../scripts/langOldeEnglish.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://www.siafoo.net/snippet/133 # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-OldeEnglish.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/i([bcdfghjklmnpqrstvwxyz])e\b/y$1/g; s/i([bcdfghjklmnpqrstvwxyz])e/y$1$1e/g; s/ick\b/yk/g; s/ia([bcdfghjklmnpqrstvwxyz])/e$1e/g; s/e[ea]([bcdfghjklmnpqrstvwxyz])/e$1e/g; s/([bcdfghjklmnpqrstvwxyz])y/$1ee/g; s/([bcdfghjklmnpqrstvwxyz])er/$1re/g; s/([aeiou])re\b/$1r/g; s/ia([bcdfghjklmnpqrstvwxyz])/i$1e/g; s/tion\b/cioun/g; s/ion\b/ioun/g; s/aid/ayde/g; s/ai/ey/g; s/ay\b/y/g; s/ay/ey/g; s/ant/aunt/g; s/ea/ee/g; s/oa/oo/g; s/ue/e/g; s/oe/o/g; s/ou/ow/g; s/ow/ou/g; s/\bhe/hi/g; s/ve\b/veth/g; s/se\b/e/g; s/\'s\b/es/g; s/ic\b/ick/g; s/ics\b/icc/g; s/ical\b/ick/g; s/tle\b/til/g; s/ll\b/l/g; s/ould\b/olde/g; s/own\b/oune/g; s/un\b/onne/g; s/rry\b/rye/g; s/est\b/este/g; s/pt\b/pte/g; s/th\b/the/g; s/ch\b/che/g; s/ss\b/sse/g; s/([wybdp])\b/$1e/g; s/([rnt])\b/$1$1e/g; s/from/fro/g; s/when/whan/g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.2/scripts/langPigLatin.pl000077500000000000000000000042251501463444000207510ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langPigLatin.pl -split language-PigLatin.sys # or # ../scripts/langPigLatin.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.perlmonks.org/?node_id=3586 # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-PigLatin.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/\b(qu|y(?=[^t])|[^\W\daeiouy]*)([a-z']+)/$2.($1||"w")."ay"/eg; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.2/scripts/langPirateEnglish.pl000077500000000000000000000335701501463444000220050ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # Look at the README for more information on the program. # # Run it like this: # # cd xastir/config # ../scripts/langPirateEnglish.pl -split language-PirateEnglish.sys # or # ../scripts/langPirateEnglish.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://userscripts.org/scripts/review/25998 # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show we translated the file. print "# language-PirateEnglish.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } # Custom for Xastir: s/\bham\b/matey/g; s/\bhi hi\b/it be a joke, matey/g; s/\bk7gps\b/Th\' Good Cap\'n/g; s/\bDave Dobbins\b/Th\' Good Cap\'n/g; s/\bAPRS\'er\b/Fellow Pirate/g; s/\b[Aa]prs\'er\b/fellow pirate/g; s/\bHerb Gerhardt\b/scurvy dog/g; s/\bkb7uvc\b/scurvy dog/g; s/\bwa7nwp\b/cabin boy/g; s/\b[Mm]ap(s*)\b/Treasure Map/g; s/\bXastir\b/HMS Xastir/g; s/\bxastir\b/HMS xastir/g; s/\bXASTIR\b/HMS XASTIR/g; s/\bStation/Ship/g; s/\bstation/ship/g; s/\bView/Gander/g; s/\bview/gander/g; s/\bFile/Scroll/g; s/\bfile/scroll/g; #s/\bFile/Parchment/g; #s/\bfile/parchment/g; s/\bMessage/Dispatch/g; s/\bmessage/dispatch/g; s/\bLogging/Scribblin'/g; s/\blogging/scribblin'/g; s/\bLog/Scribble/g; s/\blog/scribble/g; s/\bPrint/Affix to parchment/g; s/\bprint/affix to parchment/g; s/\bCancel/Nay/g; s/\bcancel/nay/g; s/Close/Nay/g; s/close/nay/g; s/\bOK/Aye/g; s/\bOk/Aye/g; s/\bok/aye/g; s/\bQuit/Nay/g; s/\bquit/nay/g; s/\bExit/Run Away!/g; s/\bexit/run away!/g; s/\bSelect/Choose 'yer Weapon!/g; s/\bselect/choose 'yer weapon!/g; s/\bCompressed/Scrawny/g; s/\bcompressed/scrawny/g; s/\bAudio/Racket/g; s/\baudio/racket/g; s/\bFont/Scribble/g; s/\bfont/scribble/g; s/\bSatellite/Heavenly Body/g; s/\bsatellite/heavenly body/g; s/\bSnapshot/Etching/g; s/\bsnapshot/etching/g; #s/\bObject//g; #s/\bobject//g; #s/\bItem//g; #s/\bitem//g; s/\bInterface/Grapple/g; s/\binterface/grapple/g; s/\bConfigure/Provision me' ship/g; s/\bconfigure/provision me' ship/g; # From userscripts: s/About/\'bout/g; s/\babout\b/\'bout/g; s/\ba lot\b/mightily/g; s/\bam\b/be/g; s/\bamputee\b/peg leg/g; s/\bafraid\b/lily-livered/g; s/\band\b/an\'/g; s/\baround\b/\'round/g; s/\battack\b/pillage/g; s/\battacked\b/raped and pillaged/g; s/\barrest\b/keelhaul/g; s/\bAIDS\b/scurvy/g; s/\baids\b/scurvy/g; s/\bATTN\b/AVAST/g; s/\bbad\b/scurvy/g; s/\bbeer\b/grog/g; s/\bvodka\b/grog/g; s/\bban him\b/make him walk the plank/g; s/\bcar\b/ship/g; s/\bBAN HIM\b/Make him walk the plank!/g; s/\bBan him\b/Make him walk the plank/g; s/\bale\b/grog/g; s/\bbetween\b/betwixt/g; s/\bwhiskey\b/grog/g; s/\bbeauty\b/gov\'nor\'s daughter/g; s/\bbefore\b/\'ere/g; s/\bbanned\b/forced t\' walk the plank/g; s/\bbetween\b/\'tween/g; s/\bboy\b/jim lad/g; s/\bboys\b/jim lads/g; s/\bbought\b/pilfered/g; s/\b4chan\b/House o\' Bilge Rats/g; s/\bAsia\b/Th\' Mystic East/g; s/\bJapan\b/Th\' Mystic East/g; s/\bChina\b/Th\' Mystic East/g; s/\bKorea\b/Th\' Mystic East/g; s/\basia\b/Th\' Mystic East/g; s/\bjapan\b/Th\' Mystic East/g; s/\bchina\b/Th\' Mystic East/g; s/\bkorea\b/Th\' Mystic East/g; s/\bIndia\b/Hindustan/g; s/\bIsrael\b/Th\' Holy Lands/g; s/\bindia\b/Hindustan/g; s/\bisrael\b/Th\' Holy Lands/g; s/\bIraq\b/Th\' Ottoman Empire/g; s/\bIran\b/Th\' Ottoman Empire/g; s/\bPakistan\b/Th\' Ottoman Empire/g; s/\bAfghanistan\b/Th\' Ottoman Empire/g; s/\biraq\b/Th\' Ottoman Empire/g; s/\biran\b/Th\' Ottoman Empire/g; s/\bpakistan\b/Th\' Ottoman Empire/g; s/\bafghanistan\b/Th\' Ottoman Empire/g; s/\bAfrica\b/Th\' Dark Continent/g; s/\bafrica\b/Th\' Dark Continent/g; s/\bcheat\b/hornswaggle/g; s/\bchild\b/wee one/g; s/\bchildren\b/wee ones/g; s/\bcoffee\b/grog/g; s/\bcondemn\b/keelhaul/g; s/\bconference\b/parlay/g; s/\bcrazy\b/addled/g; s/\bjapanophile\b/scurvy mutt/g; s/\bweeaboo\b/scurvy mutt/g; s/\boh crap\b/shiver me timbers!/g; s/\bover\b/o\'er/g; s/\bThe Token Shop\b/Honest Jack\'s Swag Shop/g; s/\bToken Shop\b/Honest Jack\'s Swag Shop/g; s/\bdamn\b/damn\'ed/g; s/\bdevil\b/Davy Jones/g; s/\bdie\b/head to Davy Jones\' Locker/g; s/\bdead\b/\'n Davy Jones\' Locker/g; s/\bdoesn\'t\b/don\'t/g; s/\bdollars\b/pieces o\' eight/g; s/\beveryone\b/all hands/g; s/\beyewear\b/eye patch/g; s/\bglasses\b/eye patches/g; s/\bfight\b/duel/g; s/\bgreatly\b/mightily/g; s/\bgold\b/dubloons/g; s/\bha\b/har har/g; s/\bhaha\b/har har/g; s/\bbase\b/port/g; s/\bfort\b/port/g; s/\bhah\b/har har/g; s/\bheh\b/har har/g; s/\bHa\b/Har har/g; s/\bflag\b/Jolly Roger/g; s/\bhouse\b/shanty/g; s/\bidiot\b/bilge rat/g; s/\bhit\b/flog/g; s/\btorrents\b/Blackbeard\'s treasure /g; s/\btorrent\b/Blackbeard\'s treasure/g; s/\bn00b\b/landlubber/g; s/\bnoob\b/landlubber/g; s/\btroll\b/blowhard/g; s/\bdrive\b/sail/g; s/\bcoins\b/pieces o\' eight/g; s/\bcorrect\b/right an\' true/g; s/\bfly\b/sail/g; s/\bfool\b/squiffy/g; s/\bfoolish\b/addled/g; s/\bfor\b/fer/g; s/\bFor\b/Fer/g; s/\bfriend\b/matey/g; s/\bfriends\b/hearties/g; s/\bgirl\b/lass/g; s/\bex-girlfriend\b/festerin\' harlot/g; s/\bex girlfriend\b/festerin\' harlot/g; s/\bgood\b/worthy/g; s/\byou\'re\b/yer/g; s/\byour\b/yer/g; s/\bhello\b/ahoy/g; s/\bHello\b/Ahoy/g; s/\bhey\b/avast!/g; s/\bHey\b/Avast/g; s/\bhey\b/avast!/g; s/\bhi\b/ahoy/g; s/\bHi\b/Ahoy/g; s/\bHiya\b/Ahoy/g; s/\bhiya\b/ahoy/g; s/\bmoney\b/booty/g; s/\bguy\b/feller/g; s/\bfellow\b/feller/g; s/\bidiot\b/scalawag/g; s/ing\b/in\'/g; s/\bin\b/\'n/g; s/\bis\b/be/g; s/\bit\'s\b/\'tis/g; s/\bit is\b/\'tis/g; s/\bkid\b/wee one/g; s/\bkids\b/wee ones/g; s/\bkill\b/keelhaul/g; s/\bis not\b/be not/g; s/\baren\'t\b/be not/g; s/\bare\b/be/g; s/\bam\b/be/g; s/\bAre\b/Be/g; s/\blol\b/yo ho ho!/g; s/\blolol\b/Me sides be splittin\'!/g; s/\bodd\b/addled/g; s/\bof\b/o\'/g; s/\bohmigod\b/begad!/g; s/\bomigod\b/begad!/g; s/\bomg\b/begad!/g; s/\bOMG\b/BEGAD!/g; s/\bo rly\b/be that right, sailor?/g; s/\borly\b/be that right, sailor?/g; s/\bya rly\b/Sailor, \'tis true/g; s/\byarly\b/Sailor, \'tis true/g; s/\bwhoamg\b/shiver me timbers!/g; s/\bmoney\b/booty/g; s/\bmy\b/me/g; s/\bprosecute\b/keelhaul/g; s/\bpants\b/britches/g; s/\bHello\b/Ahoy!/g; s/\bquick\b/smart/g; s/\bquickly\b/smartly/g; s/\bthe rules\b/the Pirate\'s Code/g; s/\bnice\b/fine/g; s/\bthe Internet\b/The Seven Seas/g; s/\bThe Internet\b/The Seven Seas/g; s/\binternet\b/Seven Seas/g; s/\bInternet\b/Seven Seas/g; s/\bsilly\b/addled/g; s/\bsword\b/cutlass/g; s/\bshe\b/the lass/g; s/\bshut up\b/pipe down/g; #s/\bspeech/parlance/g; #s/\bSpeech/Parlance/g; s/\bspeech/parley/g; s/\bSpeech/Parley/g; s/\bsteal\b/commandeer/g; s/\bdownload\b/plunder/g; s/\bDownload\b/Plunder/g; s/\bsexy\b/saucy/g; s/\btelescope\b/spyglass/g; s/\bterrorist\b/scourge o\' the seven seas/g; s/\bterrorists\b/scalawags/g; s/tion\b/tin\'/g; s/\bthere\b/thar/g; s/tions\b/tin\'s/g; s/\bto\b/t\'/g; s/\btomorrow\b/the morrow/g; s/\btruck\b/vessel/g; s/\bwasn\'t\b/weren\'t/g; s/\bwant to\b/wish t\'/g; s/\bwanna\b/wish t\'/g; s/\bYep\b/Aye/g; s/\byep\b/aye/g; s/\bwoman\b/buxom beauty/g; s/\bwomen\b/wenches/g; s/\bwin\b/triumph/g; s/\bwins\b/triumphs/g; s/\bwork\b/deck swabbing/g; s/\bwine\b/grog/g; s/\byes\b/aye/g; s/\bYes\b/Aye/g; s/\bno\b/nay/g; s/\bNo\b/Nay/g; s/\bnah\b/nay/g; s/\bNah\b/Nay/g; s/\bYeah\b/Aye/g; s/\byeah\b/Aye/g; s/\byou\b/ye/g; s/\byour\b/yer/g; s/\bwtf\b/what devilry!/g; s/\bWTF\b/Begad, what devilry be is?!/g; s/\bFacebook\b/PirateBook/g; s/\bThis message was deleted at the request of the original poster\b/This here message be taken back by a yellow-bellied pirate/g; s/\bThis message has been deleted by a moderator\b/This poor soul had a run-in with the authorities/g; s/\bGood Tokens\b/Pieces o\' Eight/g; s/\bBad Tokens\b/Black Marks/g; s/\byou\'re\b/yer/g; s/\bYou\'re\b/Yer/g; s/\bwins\b/triumphs/g; s/\bHome\b/Haven/g; s/\bAdd a link\b/Add plunder/g; s/\bRandom link\b/Who needs maps?/g; s/\bTop rated links\b/Quality grog/g; s/\bLinks o\' the week\b/Modern fashions/g; s/\bWiki\b/Wikis/g; s/\bAll links\b/All th\' plunder/g; s/\bFavorites\b/Treasures/g; s/\bSearch\b/Scour/g; s/\bStats\b/Specs/g; s/\bBoards\b/Th\' Tavern/g; s/\bUser List\b/Roster/g; s/\bLogout\b/Retreat/g; s/\bHelp\b/Aid/g; s/\bBoard List\b/Port/g; s/\bCreate New Topic\b/Parley/g; s/\bPost New Message\b/Parley/g; s/\bNext Page\b/Next Map/g; s/\bTagged\b/X\'d/g; s/\bTag\b/X/g; # From text-filter-suite/ s/\bmy\b/me/g; s/\bboss\b/admiral/g; s/\bmanager\b/admiral/g; s/\b[Cc]aptain\b/Cap\'n/g; s/\bmyself\b/meself/g; s/\byour\b/yer/g; s/\byou\b/ye/g; s/\bfriend\b/matey/g; s/\bfriends\b/maties/g; s/\bco[-]?worker\b/shipmate/g; s/\bco[-]?workers\b/shipmates/g; s/\bpeople\b/scallywags/g; s/\bearlier\b/afore/g; s/\bold\b/auld/g; s/\bthe\b/th\'/g; s/\bof\b/o'/g; s/\bdon\'t\b/dern\'t/g; s/\bdo not\b/dern\'t/g; s/\bnever\b/ne\'er/g; s/\bever\b/e\'er/g; s/\bover\b/o\'er/g; s/\bYes\b/Aye/g; s/\bNo\b/Nay/g; s/\bYeah\b/Aye/g; s/\byeah\b/aye/g; s/\bdon\'t know\b/dinna/g; s/\bdidn\'t know\b/did nay know/g; s/\bhadn\'t\b/ha\'nae/g; s/\bdidn\'t\b/di\'nae/g; s/\bwasn\'t\b/weren\'t/g; s/\bhaven\'t\b/ha\'nae/g; s/\bfor\b/fer/g; s/\bbetween\b/betwixt/g; s/\baround\b/aroun\'/g; s/\bto\b/t\'/g; s/\bit\'s\b/\'tis/g; s/\bwoman\b/wench/g; s/\bwomen\b/wenches/g; s/\blady\b/wench/g; s/\bwife\b/lady/g; s/\bgirl\b/lass/g; s/\bgirls\b/lassies/g; s/\bguy\b/lubber/g; s/\bman\b/lubber/g; s/\bfellow\b/lubber/g; s/\bdude\b/lubber/g; s/\bboy\b/lad/g; s/\bboys\b/laddies/g; s/\bchildren\b/little sandcrabs/g; s/\bkids\b/minnows/g; s/\bhim\b/that scurvey dog/g; s/\bher\b/that comely wench/g; s/\bhim\.\b/that drunken sailor/g; s/\bHe\b/The ornery cuss/g; s/\bShe\b/The winsome lass/g; s/\bhe\'s\b/he be/g; s/\bshe\'s\b/she be/g; s/\bwas\b/were bein\'/g; s/\bHey\b/Avast/g; s/\bher\.\b/that lovely lass/g; s/\bfood\b/chow/g; s/\bmoney\b/dubloons/g; s/\bdollars\b/pieces of eight/g; s/\bcents\b/shillings/g; s/\broad\b/sea/g; s/\broads\b/seas/g; s/\bstreet\b/river/g; s/\bstreets\b/rivers/g; s/\bhighway\b/ocean/g; s/\bhighways\b/oceans/g; s/\binterstate\b/high sea/g; s/\bprobably\b/likely/g; s/\bidea\b/notion/g; s/\bcar\b/boat/g; s/\bcars\b/boats/g; s/\btruck\b/schooner/g; s/\btrucks\b/schooners/g; s/\bSUV\b/ship/g; s/\bairplane\b/flying machine/g; s/\bjet\b/flying machine/g; s/\bmachine\b/contraption/g; s/\bdriving\b/sailing/g; s/\bunderstand\b/reckon/g; s/\bdrive\b/sail/g; s/\bdied\b/snuffed it/g; s/ing\b/in\'/g; s/ings\b/in\'s/g; # These next two do cool random substitutions #s/(\.\s)/e/avast("$0",3)/g; #s/([!\?]\s)/e/avast("$0",2)/g; # Greater chance after exclamation # Add an opening phrase to each line randomly (see below)? if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } # Randomize use of this array, both in order and in frequency of # use. Not currently used at all. #my @shouts = ( # ", avast$stub", # "$stub Ahoy!", # ", and a bottle of rum!", # ", by Blackbeard's sword$stub", # ", by Davy Jones' locker$stub", # "$stub Walk the plank!", # "$stub Aarrr!", # "$stub Yaaarrrrr!", # ", pass the grog!", # ", and dinna spare the whip!", # ", with a chest full of booty$stub", # ", and a bucket o' chum$stub", # ", we'll keel-haul ye!", # "$stub Shiver me timbers!", # "$stub And hoist the mainsail!", # "$stub And swab the deck!", # ", ye scurvey dog$stub", # "$stub Fire the cannons!", # ", to be sure$stub", # ", I'll warrant ye$stub", # ", on a dead man's chest!", # "$stub Load the cannons!", # "$stub Prepare to be boarded!", # ", I'll warrant ye$stub", # "$stub Ye'll be sleepin' with the fishes!", # "$stub The sharks will eat well tonight!", # "$stub Oho!", # "$stub Fetch me spyglass!", # ); # Randomize use of this array both in order and frequency of use. # Not currently used at all. my @openings = ( 'Avast! ', 'Yarrr! ', 'Blimey! ', 'Ahoy! ', 'Harrr! ', 'Aye aye! ', 'Shiver me timbers! ', 'Arrrr! ' ); Xastir-Release-2.2.2/scripts/listen_and_display.pl000077500000000000000000000016401501463444000222430ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # listen_and_display.pl: Create a listener port which dumps anything received to STDOUT $server_port = 2024; $| = 1; use Socket; use IO::Handle; use POSIX qw(:errno_h); # Make the socket socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')); # So we can restart our server quickly setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1); # Build up my socket address $my_addr = sockaddr_in($server_port, INADDR_ANY); bind(SERVER, $my_addr) or die "Couldn't bind to port $server_port : $!\n"; # Establish a queue for incoming connections listen(SERVER, SOMAXCONN) or die "Couldn't listen on port $server_port : $!\n"; # Accept and process connections while (accept(CLIENT, SERVER)) { printf("\n*** A client connected on port $server_port ***\n"); CLIENT->autoflush(1); while () { print; } printf("\n*** The client disconnected ***\n"); } close(SERVER); Xastir-Release-2.2.2/scripts/mapblast2geo.pl000077500000000000000000000161521501463444000207620ustar00rootroot00000000000000#!/usr/bin/env perl # XASTIR .geo file generator for mapblast pixel maps 16.10.2001 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- use POSIX; # provides acos() function # some default values: $width = 1280; # seems to be the maximum supported by mapblast $height = 1024; # seems to be the maximum supported by mapblast $pfx = "../../pixelmaps/"; # prefix for path $pfx = ""; # undefined values: $scale = 0; $lat = 9999; $lon = 9999; $help = 0; #-------------------------------------------------------------------------- while (@ARGV) { $arg = shift @ARGV; if ($arg =~ /^\-N(\d{1,2}(\.\d+)?)$/) { $lat = $1 } if ($arg =~ /^\-S(\d{1,2}(\.\d+)?)$/) { $lat = -$1 } if ($arg =~ /^\-E(\d{1,3}(\.\d+)?)$/) { $lon = $1 } if ($arg =~ /^\-W(\d{1,3}(\.\d+)?)$/) { $lon = -$1 } if ($arg =~ /^\-w(\d+)$/) { $width = $1 } if ($arg =~ /^\-h(\d+)$/) { $height= $1 } if ($arg =~ /^\-s(\d+)$/) { $scale = $1 } if ($arg =~ /^\-s(\d+)k$/) { $scale = $1 * 1000 } if ($arg =~ /^\-s(\d+)M$/) { $scale = $1 * 1000000 } if ($arg =~ /^\-p(.+)$/) { $pfx = $1 } if ($arg eq '-?') { $help = 1 } if ($arg eq '-h') { $help = 1 } if ($arg eq '--help') { $help = 1 } } if (!$help && $arg && $arg !~ /^\-/) { $file = $arg; # last arg is file name } else { print("ERROR: Map file name is missing\n"); $help = 1; } if (!$help) { if ($lat == 9999) { # we don't yet have a latitude if ($file =~ /N(\d{1,2}(\.\d+)?)/) { $lat = $1 } if ($file =~ /S(\d{1,2}(\.\d+)?)/) { $lat = -$1 } } if ($lon == 9999) { # we don't yet have a longitude if ($file =~ /E(\d{1,3}(\.\d+)?)/) { $lon = $1 } if ($file =~ /W(\d{1,3}(\.\d+)?)/) { $lon = -$1 } } if ($scale == 0) { # we don't yet have a map scale if ($file =~ /\-(\d+)/) { $scale = $1 } if ($file =~ /\-(\d+)k/) { $scale = $1 * 1000 } if ($file =~ /\-(\d+)M/) { $scale = $1 * 1000000 } } if ($lat == 9999) { # we need a latitude print("ERROR: Latitude is missing\n"); $help = 1; } if ($lon == 9999) { # we need a longitude print("ERROR: Longitude is missing\n"); $help = 1; } if ($scale == 0) { # we need a map scale print("ERROR: Map scale is missing\n"); $help = 1; } } if ($help) { usage(); exit 0; } if ($pfx && $pfx !~ /\/$/) { $pfx .= "/" } # add trailing '/' if missing #-------------------------------------------------------------------------- if ($scale >= 1000000) { printf("ERROR: Maps with scaling of 1M and above are not yet supported!\n"); printf(" They use a different projection...\n"); exit 1; } if (abs($lat) > 89) { printf("ERROR: Map center too near to the poles!\n"); exit 1; } # This scaling factor is just a wild guess! # But I need one, and this one is nice AND works quite well... ;-) $scale_y = 100.0 * pi(); # pixel/degree at 1M map scale $scale_x = $scale_y * calcScale($lat); # adjust horizontal scale for latitude $scale_y *= (1000000 / $scale); # adjust for current map scale $scale_x *= (1000000 / $scale); #-------------------------------------------------------------------------- # DK7IN: I'm not sure, if this formula is exact for what Xastir # is decoding, but in my region it works quite well # I need to do some further investigation for the best accuracy $latmin = $lat - ($height / 2.0 - 2.5) / $scale_y; $latmax = $lat + ($height / 2.0 - 0.5) / $scale_y; $lonmin = $lon - ($width / 2.0 - 0.5) / $scale_x; $lonmax = $lon + ($width / 2.0 - 2.5) / $scale_x; printf("FileName %s%s\n",$pfx,$file); printf("\n"); printf("ImageSize %4d %4d\n",$width,$height); printf("TiePoint %4d %4d %10.6f %11.6f\n",0,0,$lonmin,$latmax); printf("TiePoint %4d %4d %10.6f %11.6f\n",$width-1,$height-1,$lonmax,$latmin); printf("Datum WGS84\n"); printf("Projection LatLon\n"); printf("\n"); printf("# map from mapblast center %10.6f %11.6f, scale %d\n",$lat,$lon,$scale); printf("# created with mapblast2geo.pl (DK7IN)\n"); exit 0; #-------------------------------------------------------------------------- sub usage { my $name = $0; if ($name =~ /^.*\/(.+)$/) { $name = $1 } print("\n"); print("$name (c) 2001 Rolf Bleher \n"); print("create Xastir .geo files for mapblast pixel maps\n"); print("usage: $name [options] mapfile\n"); print(" -N52.5 -S10 define latitude\n"); print(" -E13.3 -W0.5 define longitude\n"); print(" -h1024 define map height in pixels (default 1024)\n"); print(" -w1280 define map width in pixels (default 1280)\n"); print(" -s50000 define map scale, 50k or 1M is ok\n"); print(" -p../pixmaps define prefix for path\n"); print(" -h -? --help print this help file\n"); print(" it tries to extract center Lat/Lon and map scale\n"); print(" from the filename like N52.5E13.3-50k.xpm\n"); print("\n"); } #-------------------------------------------------------------------------- sub pi { return(3.14159265358979323846); } #-------------------------------------------------------------------------- sub deg2rad { my ($deg) = @_; return($deg * pi()/180.0); } #-------------------------------------------------------------------------- # Calculate distance in meters between two locations sub dist { my ($lat1, $lon1, $lat2, $lon2) = @_; my $r_lat1 = deg2rad($lat1); my $r_lon1 = deg2rad($lon1); my $r_lat2 = deg2rad($lat2); my $r_lon2 = deg2rad($lon2); my $r_d = acos(sin($r_lat1) * sin($r_lat2) + cos($r_lat1) * cos($r_lat2) * cos($r_lon1-$r_lon2)); return($r_d*180.0*60.0/pi()*1852.0); } #-------------------------------------------------------------------------- sub calcScale { # EW / NS scaling my ($lat) = @_; return(dist($lat,-1.0/120.0,$lat,1.0/120.0) / 1852.0); } #-------------------------------------------------------------------------- Xastir-Release-2.2.2/scripts/mapfgd.pl000077500000000000000000000155331501463444000176420ustar00rootroot00000000000000#!/usr/bin/env perl # -*- perl -*- # Written by Derrick J Brashear, KB3EGH # Released to the public domain. # Usage: mapfgd # Creates fake fgd files for all correctly USGS-named maps which don't # already have them local (@dirlist) = @ARGV; local ($mapdir); foreach $mapdir (@dirlist) { opendir (DIR, $mapdir) || die "mapini: couldn't open directory \`$mapdir': $!\n"; local ($file, $fullfile, $expr, $mlat, $mlon, $mlats, $mlons); local ($nlat, $nlon, $nlats, $nlons); local ($dlat, $dlon, $inifile); local ($imgwidth, $imglength, $imgres, $imgdepth, $imgphotometric); local ($imgtimestamp); foreach $file (sort grep (! /^\./, readdir (DIR))) { # Only examine .tif files. next unless $file =~ /\.tif$/; next unless $file =~ /^[iIoOcCfFkKlLpPjJgG]/; $fullfile = $mapdir . '/' . $file; $inifile = $mapdir . '/' . $file; $inifile =~ s/\.tif$/.fgd/; next if (-f $inifile); open (INI, ">$inifile"); $file =~ /^([iIoOcCfFkKlLpPjJgG])([0-9][0-9])([0-9][0-9][0-9])([a-hA-H])([1-8])/; $letter = $1; $mlat = $2; $mlon = $3; $mlats = $4; $mlons = $5; if ($letter eq 'c') { $dlon = 0-$mlon-2; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+1; printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat; printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if (($letter eq 'f') || ($letter eq 'g')){ $dlon = 0-$mlon-1; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+.375+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if ($letter eq 'k') { $dlon = 0-$mlon-(.125*$mlons)-.125; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if ($letter eq 'i') { $dlon = 0-$mlon-(.125*$mlons)-.250; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { $dlon = 0-$mlon-(.125*$mlons); printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } } } } close (INI); } closedir (DIR); } sub lettonum { local ($let) = @_; if ($let eq 'a') {return 1;} if ($let eq 'b') {return 2;} if ($let eq 'c') {return 3;} if ($let eq 'd') {return 4;} if ($let eq 'e') {return 5;} if ($let eq 'f') {return 6;} if ($let eq 'g') {return 7;} if ($let eq 'h') {return 8;} } sub nextlet { local ($let,$scale) = @_; if ($scale eq 'c') {$nlat++;return 'a';} if ($scale eq 'f') { if ($let eq 'a') {return 'e';} if ($let eq 'e') {$nlat++;return 'a';} } if ($let eq 'a') {return 'b';} if ($let eq 'b') {return 'c';} if ($let eq 'c') {return 'd';} if ($let eq 'd') {return 'e';} if ($let eq 'e') {return 'f';} if ($let eq 'f') {return 'g';} if ($let eq 'g') {return 'h';} if ($let eq 'h') {$nlat++;return 'a';} } sub nextnum { local ($let,$scale) = @_; if ($scale eq 'c') { $nlon+=2; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($scale eq 'f') { $nlon++; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($let eq '1') {return '2';} if ($let eq '2') {return '3';} if ($let eq '3') {return '4';} if ($let eq '4') {return '5';} if ($let eq '5') {return '6';} if ($let eq '6') {return '7';} if ($let eq '7') {return '8';} if ($let eq '8') {$nlon++; if ($nlon < 100) { $nlon="0$nlon"; } return '1';} } sub oldlastnum { local ($let,$scale) = @_; if ($let = 1) {print INI "let was 1\n";$let=9; $nlon--; $nlon="0$nlon";} $let--; return $let; } sub lastnum { local ($let,$scale) = @_; if ($scale eq 'c') { $nlon-=2; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($scale eq 'f') { $nlon--; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($let eq '1') { $nlon--; if ($nlon < 100) { $nlon="0$nlon"; } return '8'; } if ($let eq '2') {return '1';} if ($let eq '3') {return '2';} if ($let eq '4') {return '3';} if ($let eq '5') {return '4';} if ($let eq '6') {return '5';} if ($let eq '7') {return '6';} if ($let eq '8') {return '7';} } sub lastlet { local ($let,$scale) = @_; if ($scale eq 'c') {$nlat--;return 'a';} if ($scale eq 'f') { if ($let eq 'a') {$nlat--;return 'e';} if ($let eq 'e') {return 'a';} } if ($let eq 'a') {$nlat--;return 'h';} if ($let eq 'b') {return 'a';} if ($let eq 'c') {return 'b';} if ($let eq 'd') {return 'c';} if ($let eq 'e') {return 'd';} if ($let eq 'f') {return 'e';} if ($let eq 'g') {return 'f';} if ($let eq 'h') {return 'g';} } Xastir-Release-2.2.2/scripts/object2shp.pl000077500000000000000000000076661501463444000204570ustar00rootroot00000000000000#!/usr/bin/env perl # # Copyright (C) 2006-2012 Tom Russo # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an ESRI point shapefile from the object.log file, # according to the "Rolling your own shapefile maps" section of README.MAPS # The point file will display using the TIGER Landmark Point dbfawk file # # This enables fast generation of point maps by using xastir to plop down # objects, then this script to turn the object.log file into a shapefile # # Typical usage: # object2shp.pl object.log myshape # # Remember to exit xastir and delete "object.log", otherwise xastir will # never forget your objects. #-------------------------------------------------------------------------- if ($#ARGV != 1) { print "Usage: $0 \n"; exit 1; } open(INOBJ,"<$ARGV[0]") || die "Cannot open input object file $ARGV[0]\n"; $cmd[0]="shpcreate $ARGV[1] point"; $cmd[1]="dbfcreate $ARGV[1] -n ID 8 0 -s CFCC 4 -s NAME 30"; $outfile=$ARGV[1]; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } # We now have the shapefile and dbf file created, start populating from the # objects file: $i=0; while () { chomp($_); $semicolon=substr($_,0,1); $name=substr($_,1,9); $live_or_dead=substr($_,10,1); $timestamp=substr($_,11,7); $lat=substr($_,18,8); $symtab=substr($_,26,1); $long=substr($_,27,9); $sym=substr($_,36,1); #sanity check --- don't try to convert if the line doesn't conform to what # it should, or if it represents a killed object. Sometimes objects get # commented out with #, etc. next if ($semicolon ne ";"); next if ($live_or_dead eq "_"); $i++; # bump the ID number so every point has a unique one $lat_deg=substr($lat,0,2); $lat_min=substr($lat,2,5); $lat_hem=substr($lat,7,1); $long_deg=substr($long,0,3); $long_min=substr($long,3,5); $long_hem=substr($long,8,1); $lat=$lat_deg+$lat_min/60; $lat *= -1 if ($lat_hem eq "S"); $long=$long_deg+$long_min/60; $long *= -1 if ($long_hem eq "W"); # Construct symbol if ($symtab ne "/" && $symtab ne "\\") { print "overlay symbol, symtab is $symtab\n"; $overlay=$symtab; $symtab="\\"; print " reset values symtab is $symtab, overlay is $overlay\n"; } else { $overlay=" "; } $cmd[0]="shpadd $outfile $long $lat"; $cmd[1]="dbfadd $outfile $i \'X$symtab$sym$overlay\' $name"; print $cmd[1]."\n"; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } } Xastir-Release-2.2.2/scripts/overlay.pl000077500000000000000000000141561501463444000200650ustar00rootroot00000000000000#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # # Script to create Xastir "Overlay" files from "CSV" files of the # proper format (comma-delimited files). # # 1) Creates files in Xastir "log" format if you enter a callsign # below. These files can then be put in your ~/.xastir/logs/ # directory and brought in via the File->Open Log File menu option. # If you start with the CSV files in the ~/.xastir/logs/ directory # and process them there with this script, the output files will be # placed into the proper place for Xastir to find them. # # 2) If no callsign is entered, this script will create files in # Xastir's "~/.xastir/config/object.log" format. You can then # replace or append the file to the object.log file, restart Xastir # or "Reload Object/Item History". # # NOTE: These APRS Items will become part of your locally # owned/transmitted objects, so if you don't want them transmitted, # turn of Object/Item transmit before bringing them in. # # Input: Directory name. If no directory name passed in, it will # operate on every CSV file in the current directory. # # Input format: # Name N/S lat E/W long // comment fields............. # SUPPLY,N,34.0000,W,78.0000,ICON,text1,text2,text3,text4,... # # # The name will have spaces removed if it is longer than nine # characters. If it is still too long, vowels will be removed, then # it will be truncated to nine characters if still needed. The full # name will be transmitted as a comment. All other text fields will # also be transmitted as comments, so that they will all appear in # the Station Info dialog. # # Icons will be a default small red circle unless '/' or '\' is the # leading character in that field and the next specifies the APRS # symbol. In that case the two-letter combination will get used as # the symbol for the Item. # Change this to match whatever callsign you're running Xastir as, # so that the APRS Items appear to have been generated locally. You # can then suck this file in as a "log" file from within Xastir. If # this field is empty, then instead write the packets out without a # header, as in Xastir's "object.log" format. $callsign = ""; if ($callsign ne "") { $callsign = uc($callsign) . '>APRS:'; } # Main program. Process every ".csv" file found in the directory. # $dirname = shift; if ($dirname == "") { $dirname = "."; } opendir(DIR, $dirname) or die "Can't opendir $dirname: %!"; while (defined($file = readdir(DIR))) { chomp $file; if ( $file =~ /\.csv$/ ) { # Do something with "$dirname/$file" &process_file($dirname, $file); } else { # printf("$dirname/$file\n"); } } # Process one file. Creates an output file that matches the # basename but changes the "csv" to "overlay". # sub process_file() { $output_file = $_[1]; $output_file =~ s/\.csv$/.overlay/; printf("$dirname/$file -> $output_file\n"); open(SOURCE, "< $_[1]") or die "Couldn't open $path for reading: $!\n"; open(OUTPUT, "> $output_file") or die "Couldn't open $output_file for writing: $!\n"; while () { &process_line($_); } close(SOURCE); close(OUTPUT); } # Process one line. Write the formatted data to the OUTPUT file. # sub process_line() { #printf("$_[0]"); # Parse the CSV line into an array @list = parse_csv($_[0]); if (!($list[0] =~ m/Location/i)) { #print OUTPUT @list; # As a temporary measure, create items out of each of the lines, # with a status line for each extra data object so that they # appear in the Station Info dialog. &create_items(@list); } } # Create an APRS Item out of each array. Create a status line for # each extra column associated with a line so that the info shows up # in the Station Info dialog. # # Examples. Name is 3-9 characters: # )AID #2!4903.50N/07201.75WA # )G/WB4APR!53 . N\002 . Wd # sub create_items { $name = $_[0]; if ($name eq "") { printf("Error, name column is empty\n"); } # If too long, try removing spaces first if (length($name) > 9) { $name =~ s/\s//ig; } # If still too long, remove vowels if (length($name) > 9) { $name =~ s/a//ig; $name =~ s/e//ig; $name =~ s/i//ig; $name =~ s/o//ig; $name =~ s/u//ig; } # Extend to three characters if short if (length($name) < 3) { $name = $name . " "; } $name = substr($name,0,9); $name[9] = "\0"; # Terminate name at 9 characters, minimum 3 $n_s = uc( substr($_[1],0,1) ); $latitude = $_[2]; $e_w = uc( substr($_[3],0,1) ); $longitude = $_[4]; if ($_[5] =~ /ICON/i) { $icon1 = "/"; $icon2 = "/"; } else { $icon1 = substr($_[5],0,1); $icon2 = substr($_[5],1,1); } # Convert lat/long to APRS format (or Base-91 Compressed format) $lat_deg = $latitude; $lat_deg =~ s/\.\d+$//; $lat_deg = sprintf("%02d", $lat_deg); $lat_min = $latitude; $lat_min =~ s/^\d+\./0./; $lat_min = $lat_min * 60.0; $lon_deg = $longitude; $lon_deg =~ s/\.\d+$//; $lon_deg = sprintf("%03d", $lon_deg); $lon_min = $longitude; $lon_min =~ s/^\d+\./0./; $lon_min = $lon_min * 60; # Create an APRS "Item" packet $line = sprintf("%s)%s!%s%05.2f%s%s%s%05.2f%s%s", $callsign, $name, $lat_deg, $lat_min, $n_s, $icon1, $lon_deg, $lon_min, $e_w, $icon2); # Go process the rest of the columns, if any. Create APRS Item # packets with comments from them. for ($i = 6; $i < 106; $i++) { chomp $_[$i]; if ($_[$i] ne "") { #printf("$_[$i]"); printf(OUTPUT "%s%s\n", $line, $_[$i]); } } # Write it out to the file, with the full name as a comment printf(OUTPUT "%s%s\n", $line, $_[0]); } # Parse CSV line into an array, removing double-quotes and such if # found. # sub parse_csv { my $text = shift; # Record containing comma-separated values my @new = (); push(@new, $+) while $text =~ m{ # The first part groups the phrase inside the quotes. # See explanation of this pattern in MRE "([^\"\\]*(?:\\.[^\"\\]*)*)",? | ([^,]+),? | , }gx; push(@new, undef) if substr($text, -1, 1) eq ','; return @new; # List of values that were comma-separated } Xastir-Release-2.2.2/scripts/ozi2geo.pl000077500000000000000000000122011501463444000177470ustar00rootroot00000000000000#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # Modified from the earlier inf2geo.pl script. # # Read in .map file (an OziExplorer file in this case). # Check the version of the map format (1st line). My example is # version 2.2. # Get the filename from the 2nd line of the file. # Check that "WGS 84" or "NAD 83" are present in the file (5th # line?). # Check the "Map Projection". # Grab the first four points, which hopefully are the corners. # Snag the MMPXY lines and the MMPLL lines. These are the X/Y and # Lat/Long of the corners in the example I have. # Write out the .geo file # # 2003-08-15 ZL2UMF: add processing multiple files in one go (masks # and whot-not) so you can convert all your maps in one step. #use strict; use IO::File; #go through every filename passed to this script foreach my $file (@ARGV) { print "*** $file ***\n"; #make a geo of this file makeGeo ($file); } exit; #just in case sub makeGeo { my $ozimap_filename = shift; # Snag the filename out of the .map file instead? Here we # create it from the.map filename. # my $filename = $ozimap_filename; $filename =~ s/\.map$//i; my $geo_filename = $filename . ".geo"; # $ozimap = IO::File->new("< $ARGV[0].map") # or $ozimap = IO::File->new("< $ARGV[0].MAP") # or $ozimap = IO::File->new("< $ARGV[0].Map") #skip this file if geo already exists return print "$filename.geo already exists, will not overwrite\n" if( -e "$filename.geo" ); #read the map file my $ozimap = IO::File->new ( "< $ozimap_filename" ) or return print "\nCouldn't open $ozimap_filename for reading:\n$!\n\n"; #make the new geo file $geo = IO::File->new("> $geo_filename") or return print "Couldn't open $geo_filename for writing: $!\n"; # First line should be something like: # "OziExplorer Map Data File Version 2.2" # $tmp = $ozimap->getline(); print "\t$tmp"; $final_filename = $ozimap->getline(); chomp($final_filename); #print $final_filename; # Check that the filename we just read matches the filename we # created from the .map filename. $tmp = $ozimap->getline(); #print $tmp; $tmp = $ozimap->getline(); # Get the datum $tmp = $ozimap->getline(); #print $tmp; # Check that the datum is "WGS 84", "WGS84", "NAD 83", or "NAD83". if ($tmp =~ /WGS 84/i || $tmp =~ /WGS84/i || $tmp =~ /NAD 83/i || $tmp =~ /NAD83/i) { } else { print "***Datum is not WGS84 or NAD83: Results will be inaccurate***\n"; } # Read until we find "Map Projection" at the start of a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); #print $tmp; if ($tmp=~ /Map Projection/) { $done++; } } if ($tmp =~ /UTM/i) { print "***Found UTM projection: Results will be inaccurate***\n"; #print "$tmp"; } # We have the map projection. Check it. Issue a warning if it's # not what we can handle easily. # Read until we find "MMPXY" at the start of a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); if ($tmp=~ /MMPXY/) { $done++; } } $MMPXY1 = $tmp; #print $MMPXY1; $MMPXY2 = $ozimap->getline(); #print $MMPXY2; $MMPXY3 = $ozimap->getline(); #print $MMPXY3; $MMPXY4 = $ozimap->getline(); #print $MMPXY4; $MMPLL1 = $ozimap->getline(); #print $MMPLL1; $MMPLL2 = $ozimap->getline(); #print $MMPLL2; $MMPLL3 = $ozimap->getline(); #print $MMPLL3; $MMPLL4 = $ozimap->getline(); #print $MMPLL4; # If the corners are always listed in circular order, we can choose # to use corners 1 and 3 for our tiepoints. Try this. # Read until we find "Map Image Width" inside a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); if ($tmp=~ /Map Image Width/) { $done++; } } #print $tmp; $image_size = $tmp; # That should be all that we need to read from the file. # Get the X/Y for the tiepoints my ($a, $b, $x0, $y0) = split(',', $MMPXY1); chomp($x0); chomp($y0); # Convert to numbers $x0 = $x0 * 1; $y0 = $y0 * 1; #print "$x0 $y0\n"; my ($a, $b, $x1, $y1) = split(',', $MMPXY3); chomp($x1); chomp($y1); # Convert to numbers $x1 = $x1 * 1; $y1 = $y1 * 1; #print "$x1 $y1\n"; # Get the lat/long for the tiepoints my ($a, $b, $tp0_lon, $tp0_lat) = split(',', $MMPLL1); chomp($tp0_lon); chomp($tp0_lat); #print "$tp0_lon $tp0_lat\n"; my ($a, $b, $tp1_lon, $tp1_lat) = split(',', $MMPLL3); chomp($tp1_lon); chomp($tp1_lat); #print "$tp1_lon $tp1_lat\n"; # Split out the imagesize string my ($a, $b, $width, $height) = split(',', $image_size); chomp($width); chomp($height); #write to the geo file printf $geo "FILENAME $final_filename\n"; printf $geo "TIEPOINT $x0\t\t$y0\t$tp0_lon\t$tp0_lat\n"; printf $geo "TIEPOINT $x1\t$y1\t$tp1_lon\t$tp1_lat\n"; printf $geo "IMAGESIZE $width\t$height\n"; printf $geo "#\n# Converted from an OziExplorer .MAP file by WE7U's ozi2geo.pl script\n#\n"; $ozimap->close(); $geo->close(); } Xastir-Release-2.2.2/scripts/permutations.pl000077500000000000000000000257551501463444000211450ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # Written by Paul Lutt, KE7XT & Curt Mills, WE7U. # Released to the public domain. # # # # Finds the different lat/long representations corresponding to the # input numbers. A space is required between the degrees portion # and the rest of the input. Writes out a log file containing APRS # objects suitable for importing into Xastir, to graphically plot # the locations of the objects. Now that Xastir has a server port # we could directly inject them into the program via that route as # well, but we currently don't do that. # # Converts between different lat/lon formats. Will also give UMS # position if the lat/lon resides somewhere inside the Seattle area # aeronautical map. # # UMS coordinates have been used in the past by King County, WA SAR. # It can be useful for plotting positions on Green Trails maps and # perhaps other maps. The maps must be 15' topo maps and marked in # tenths of miles along the edge in order to make use of this # coordinate system. # # Web pages which discuss UMS format: # http://www.impulse.net/~mlynch/land_nav.html # http://www.logicsouth.com/~lcoble/dir9/land_nav.htm # http://www.aasar.org/training/academy/navigation.pdf # use lib "/usr/local/lib"; use Coordinate; # WE7U's Coordinate.pm module # Get the username $user = getlogin; chomp $user; $filename = "/var/tmp/PERMUTATIONS-$user.log"; sub convert { # Snag the input $_ = $_[0]; print "\n"; # If the first item has 2 digits and one character and there are # three "words" in the input, we're starting with a UTM value. if (/^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { # printf("Found a UTM value\n"); # We'll convert it to the standard format first and then run # through the rest of the code. $zone = $_; $easting = $_; $northing = $_; $zone =~ s/^(\d\d[a-zA-Z])\s+\w+\s+\w+\s*$/$1/; $easting =~ s/^\d\d[a-zA-Z]\s+(\w+)\s+\w+\s*$/$1/; $northing =~ s/^\d\d[a-zA-Z]\s+\w+\s+(\w+)\s*$/$1/; if ($easting > 999999) { printf("Easting value is too high!\n"); return; } $position->zone($zone); $position->easting($easting); $position->northing($northing); # Convert to lat/lon values $position->utm_to_lat_lon(); # printf("Calculated Lat, Long position(Lat, Long): %f %f\n", # $position->latitude(), # $position->longitude() ); $latitude = $position->latitude(); $longitude = $position->longitude(); $lat_dir = "N"; $long_dir = "E"; if ($latitude < 0.0) { $latitude = abs($latitude); $lat_dir = "S" } if ($longitude < 0.0) { $longitude = abs($longitude); $long_dir = "W"; } # printf("%f%s %f%s\n", $latitude,$lat_dir,$longitude,$long_dir); $_ = sprintf("%f%s %f%s", $latitude,$lat_dir,$longitude,$long_dir); } # Look for lat/long value in the input # Check for N/S/E/W characters in the input. Set the # appropriate flags if found. $lat_dir = "N"; $long_dir = "E"; if (/S/ || /s/) { $lat_dir = "S"; } if (/W/ || /w/) { $long_dir = "W"; } # Filter out these characters from the input tr/nsewNSEW//d; # Convert to DD MM SS format ($lat_deg, $lat_min, $lat_sec, $long_deg, $long_min, $long_sec) = split(' '); # Decimal Degrees? if ($lat_deg =~ /\./) { $long_deg = $lat_min; # Save long_degrees in proper place $temp = $lat_deg; $lat_deg = int $temp; $lat_min = int ((abs($temp) * 60.0) % 60); # Modulus converts to integers, so we bump up by 10 and then # back down. $lat_sec = (abs($temp) * 36000.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_deg; $long_deg = int $temp; $long_min = int ((abs($temp) * 60.0) % 60); $long_sec = (abs($temp) * 36000.0) % 600; $long_sec = $long_sec / 10; } # Decimal Minutes? elsif ($lat_min =~ /\./) { $long_min = $long_deg; # Save long_minutes in proper place $long_deg = $lat_sec; # Save long_degrees in proper place $temp = $lat_min; $lat_min = int abs($temp); $lat_sec = (abs($temp) * 60.0) % 60; $lat_sec = $lat_sec / 10; $temp = $long_min; $long_min = int abs($temp); $long_sec = (abs($temp) * 600.0) % 600; $long_sec = $long_sec / 10; } # Decimal Seconds else { # Already in DD MM SS format, don't convert } # Print out the three lat/long formats printf(" Decimal Degrees: %8.5f%s %8.5f%s\n", $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0), $lat_dir, $long_deg + ($long_min/60.0) + ($long_sec/3600.0), $long_dir ); printf(" Degrees/Decimal Minutes: %02d %06.3f%s %02d %06.3f%s\n", $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); printf(" Degrees/Minutes/Dec. Seconds: %02d %02d %4.1f%s %02d %02d %4.1f%s\n", $lat_deg, $lat_min, $lat_sec, $lat_dir, $long_deg, $long_min, $long_sec, $long_dir); # Dump out the coordinate in APRS Item format: printf(FH "TEST>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s/\n", $_[1], $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); # Fill in the coordinate object with the current lat/lon. # Assuming WGS84 datum if ($lat_dir =~ /S/) { $position->latitude( -( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ) ); } else { $position->latitude( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ); } if ($long_dir =~ /W/) { $position->longitude( -( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ) ); } else { $position->longitude( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ); } #printf("%f %f\n",$position->latitude,$position->longitude); $position->lat_lon_to_utm(); printf(" Universal Transverse Mercator: %s %07.0f %07.0f\n", $position->zone(), $position->easting(), $position->northing() ); # Check whether the coordinates are within the SEA aeronautical # map area $lat_err = 0; if ($lat_dir =~ /S/ || $lat_deg < 44 || $lat_deg > 49 || ($lat_deg == 44 && ($lat_min < 30 || ($lat_min == 30 && $lat_sec == 0))) || ($lat_deg == 49 && ($lat_min > 0 || $lat_sec > 0))) { print " lat. out of range "; $lat_err = 1; } $long_err = 0; if ($long_dir =~ /E/ || $long_deg < 117 || $long_deg > 125 || ($long_deg == 117 && ($long_min == 0 && $long_sec == 0)) || ($long_deg == 125 && ($long_min > 0 || $long_sec > 0))) { print " long. out of range"; $long_err = 1; } return if ( $lat_err || $long_err); # Compute UMS coordinates $y_sec = 3600 * ($lat_deg - 44) + 60 * $lat_min + $lat_sec; $y_sec = 18000 - $y_sec; $x_sec = 3600 * ($long_deg - 117) + 60 * $long_min + $long_sec; $x_sec = 28800 - $x_sec; $quad = 32 * int($y_sec / 900) + int($x_sec / 900) + 1; # print "\tx_sec= $x_sec, y_sec= $y_sec, quad= $quad\n"; $y_subquad_offset = int($y_sec / 450); $x_subquad_offset = int($x_sec / 450); if (&even($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} A "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&odd($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} B "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&even($x_subquad_offset) && &odd($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} C "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } else { print " UMS (Green Trails Maps): SEA ${quad} D "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } } sub even { return (($_[0] & 1) == 0); } sub odd { return (($_[0] & 1) == 1); } sub s2m_y { return (int((0.1917966 * $_[0]) + 0.5)); } sub s2m_x { return (int((cos(($lat_deg + ($lat_min / 60.0) + ($lat_sec / 3600.0)) / 57.29578) * (0.1917966 * $_[0])) + 0.5)); } ############## # Main Program ############## open (FH, ">$filename") || die "Couldn't open file for writing:$!\n"; # Create new Coordinate object $position = Coordinate->new(); $position->datum("WGS 84"); # Datum print "\n"; print "Examples: 48 07228N 122 07228W\n"; print " 48 08N 122 07W\n"; print " 10U 0565264 5330343\n"; print "\nAPRS Items will be written to: $filename\n"; print "Enter a Lat/Long value or UTM value:\n"; # Snag the input $input = <>; # Get rid of whitespace at the beginning $input =~ s/\s*//; # UTM value? if ($input =~ /^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { $input2 = $input; &convert($input2, "UTM"); print "\n"; # Swap Easting/Northing values and convert again. Leave the # zone in it's original spot. $input2 = $input; $input2 =~ s/^(\d\d[a-zA-Z])\s+(\w+)\s+(\w+)\s*$/$1 $3 $2\n/; print $input2; &convert($input2, "UTM2"); } # else must be lat/lon value else { # Need to break up the input into several possible formats, # possibly including swapping lat/long pieces and plotting N/S # and E/W variants. # I'm going to assume that the user knows his/her approximate # lat/lon, so they can input it in roughly the proper format to # begin with. All that's left then is to determine which of the # three lat/lon formats it's in. # 48 07228N 122 07228W $input =~ s/^(\w+)\s+(\d)(\w)\s+(\w+)\s+(\d)(\w)\s*$/$1 0$2$3 $4 0$5$6\n/; # DD.DDD $input2 = $input; $input2 =~ s/^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s*$/$1.$2 $3.$4\n/; print $input2; &convert($input2, "DD.DDD"); print "\n"; # DD MM.MMM $input2 = $input; $input2 =~ s/^(\w+)\s+(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\w+)\s*$/$1 $2.$3 $4 $5.$6\n/; $input2 =~ s/(\.N)/.00N/; $input2 =~ s/(\.S)/.00S/; $input2 =~ s/(\.E)/.00E/; $input2 =~ s/(\.W)/.00W/; print $input2; &convert($input2, "DD MM.MM"); print "\n"; # DD MM SS.S $input2 = $input; $input2 =~ s/^(\w+)\s+(\d\d)(\w)\s+(\w+)\s+(\d\d)(\w)\s*$/$1 $2 00.$3 $4 $5 00.$6\n/; $input2 =~ s/^(\w+)\s+(\d\d)(\d)(\w)\s+(\w+)\s+(\d\d)(\d)(\w)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/; $input2 =~ s/^(\w+)\s+(\d\d)(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\d\d)(\w+)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/; $input2 =~ s/(\.N)/.0N/; $input2 =~ s/(\.S)/.0S/; $input2 =~ s/(\.E)/.0E/; $input2 =~ s/(\.W)/.0W/; $input2 =~ s/\s(\d)(\.\d)/ 0$1$2/g; print $input2; &convert($input2, "DD MM SS"); } close(FH); Xastir-Release-2.2.2/scripts/planesships.pl000077500000000000000000000057201501463444000207320ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # Enable various functions below. $start_xastir = 0; $enable_planes = 1; # Requires 1 SDR dongle $enable_plane_logging = 0; # Can fill up hard drive $enable_plane_alternate = 0; # Must also set $enable_planes. Requires another SDR dongle $enable_ships = 0; # Requires 1 SDR dongle $enable_ship_long_range = 0; # Requires 1 SDR dongle # Set RTL-SDR device numbers below (Starts at device 0). Set the numbers # based on how the SDR dongles get enumerated and how your antennas are # connected. You'll need a separate RTL-SDR dongle for each. $plane1090_SDR = 0; # Used with "enable_planes" above $plane978_SDR = 1; # Used with "enable_plane_alternate" above $ship_SDR = 2; # Used with "enable_ships" above $ship_long_range_SDR = 3; # Used with "enable_ship_long_range" above # Paths to executables: Set to match where things reside on your system. $XTERM = "/usr/bin/xterm"; $DUMP1090 = "~/src/dump1090/mutability/dump1090"; $ADSBPL = "/usr/local/share/xastir/scripts/ads-b.pl"; $RTLSDR = "/usr/local/bin/rtl_sdr"; $DUMP978 = "~/src/dump978/dump978"; $UAT2ESNT = "~/src/dump978/uat2esnt"; $NC = "/usr/bin/nc"; $XASTIR = "/usr/local/bin/xastir"; $RTLAIS = "~/src/rtl-ais/rtl-ais/rtl_ais"; $AISPL = "/usr/local/share/xastir/scripts/ais.pl"; #---------------------------------------------------- if ($start_xastir == 1) { system("$XASTIR &"); sleep(5); } if ($enable_planes == 1) { # SDR on main ADS-B frequency/protocol of 1.09 GHz: system("$XTERM -T ADS-B -e $DUMP1090 --interactive --net --interactive-ttl 86400 --net-sbs-port 30003 --phase-enhance --oversample --fix --ppm -1.2 --gain -10 --device-index $plane1090_SDR &"); if ($enable_plane_alternate == 1) { sleep(3); # Wait after starting dump1090 before dump978 connects to it # SDR on alternate ADS-B frequency of 978 MHz (and alternate ADS-B protocol): system("$XTERM -T ADS-B-Alternate -e $RTLSDR -f 978000000 -s 2083334 -g 0 -d $plane978_SDR - | $DUMP978 | $UAT2ESNT | $NC -q1 localhost 30001 &"); } sleep(3); # Give time to start programs above before Perl script connects if ($enable_plane_logging) { system("$XTERM -T ads-b.pl -geometry 175x25 -e $ADSBPL planes 10163 --logging &"); } else { system("$XTERM -T ads-b.pl -geometry 175x25 -e $ADSBPL planes 10163 &"); } } if ( ($enable_ships == 1) || ($enable_ship_long_range == 1) ) { if ($enable_ships == 1) { # SDR receiving the two normal AIS frequencies: system("$XTERM -T AIS -e $RTLAIS -h 127.0.0.1 -P 10110 -d $ship_SDR -l 161.975M -r 162.025M -n -p -2 &"); } if ($enable_ship_long_range == 1) { # SDR receiving the two long-range AIS frequencies: system("$XTERM -T AISLongRange -e $RTLAIS -h 127.0.0.1 -P 10110 -d $ship_long_range_SDR -l 156.775M -r 156.825M -n -p -2 &"); } sleep(3); # Give time to start programs above before Perl script connects system("$XTERM -T ais.pl -e $AISPL boats 9209 &"); } Xastir-Release-2.2.2/scripts/pos2shp.pl000077500000000000000000000102531501463444000177740ustar00rootroot00000000000000#!/usr/bin/env perl # # # Copyright (C) 2006-2012 Tom Russo # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an ESRI point shapefile from an APRS overlay # file (*.pos), according to the "Rolling your own shapefile maps" # section of README.MAPS The point file will display using the TIGER # Landmark Point dbfawk file. # # This enables fast generation of point maps in Shapefile format # from APRS overlay files. # # Typical usage: # pos2shp.pl file.pos myshape #-------------------------------------------------------------------------- if ($#ARGV != 1) { print "Usage: $0 \n"; exit 1; } open(INOBJ,"<$ARGV[0]") || die "Cannot open input overlay file $ARGV[0]\n"; $cmd[0]="shpcreate $ARGV[1] point"; $cmd[1]="dbfcreate $ARGV[1] -n ID 8 0 -s CFCC 4 -s NAME 30"; $outfile=$ARGV[1]; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } # We now have the shapefile and dbf file created, start populating from the # overlay file: $i=0; $first_line = 1; while () { chomp($_); # Skip the first line if it starts with a '*' (comment line). next if ($first_line && (substr($_,0,1) eq '*') ); $first_line = 0; $temp = $_; @bits = split('!', $temp); # Sanity check --- don't try to convert if the line doesn't # conform to what we expect. We should have two items in the # array at this point. next if (length(@bits) < 1); $name2 = $bits[0]; $rest = $bits[1]; $name = substr($name2,0,9); # Chop at 9 chars $name =~ s/\w+\s+$//; # Remove trailing spaces $lat=substr($rest,0,8); $symtab=substr($rest,8,1); $long=substr($rest,9,9); $sym=substr($rest,18,1); # TODO: Do something with the comment field? It appears that if we # add too much here we get strange results when displayed in Xastir. $comment=substr($rest,19,100); # $name = $name . ":" . $comment; $i++; # bump the ID number so every point has a unique one $lat_deg=substr($lat,0,2); $lat_min=substr($lat,2,5); $lat_hem=substr($lat,7,1); $long_deg=substr($long,0,3); $long_min=substr($long,3,5); $long_hem=substr($long,8,1); $lat=$lat_deg+$lat_min/60; $lat *= -1 if ($lat_hem eq "S"); $long=$long_deg+$long_min/60; $long *= -1 if ($long_hem eq "W"); # Construct symbol if ($symtab ne "/" && $symtab ne "\\") { print "overlay symbol, symtab is $symtab\n"; $overlay=$symtab; $symtab="\\"; print " reset values symtab is $symtab, overlay is $overlay\n"; } else { $overlay=" "; } $cmd[0]="shpadd $outfile $long $lat"; $cmd[1]="dbfadd $outfile $i \'X$symtab$sym$overlay\' $name"; print $cmd[1]."\n"; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } } Xastir-Release-2.2.2/scripts/ridge_radar.pl000077500000000000000000000033161501463444000206430ustar00rootroot00000000000000#!/usr/bin/env perl # # # Contributed to the public domain. Authored by Jeremy McDermond # (NH6Z). # # This script takes a single argument: The abbreviation of the # radar station off of the NWS site, and outputs to STDOUT a .geo # file that should be correct. # NOTE: You'll need to install "LWP::UserAgent" and "Image::Size" # from CPAN to make it work. # # Here's a typical invocation which creates a NYC Ridge Radar .geo # file called OKX_NOR.geo: # # ./ridge_radar.pl OKX > OKX_NOR.geo # # Of course you'd typically put the resulting file in your Xastir # maps directory and reindex maps to make it available for use. use strict; use LWP::UserAgent; use Image::Size; my $station = uc($ARGV[0]); my $gif_url = 'https://radar.weather.gov/ridge/RadarImg/N0R/' . $station . '_N0R_0.gif'; my $response = LWP::UserAgent->new->request( HTTP::Request->new( GET => $gif_url ) ); unless($response->is_success) { die "Couldn't get radar image: ", $response->status_line, "\n"; } my ($img_x, $img_y) = imgsize(\$response->content); my $response = LWP::UserAgent->new->request( HTTP::Request->new( GET => 'https://radar.weather.gov/ridge/RadarImg/N0R/' . $station . '_N0R_0.gfw' ) ); unless($response->is_success) { die "Couldn't get radar descriptor: ", $response->status_line, "\n"; } my ( $yscale, undef, undef, $xscale, $lon, $lat ) = split(/\r\n/, $response->content); my $tiepoint_lat = $lat - ($yscale * $img_y); my $tiepoint_lon = $lon - ($xscale * $img_x); print "URL\t\t$gif_url\n"; print "TIEPOINT\t0\t0\t$lon\t$lat\n"; print "TIEPOINT\t$img_x\t$img_y\t$tiepoint_lon\t$tiepoint_lat\n"; print "IMAGESIZE\t$img_x\t$img_y\n"; print "REFRESH\t\t60\n"; print "TRANSPARENT\t0x0\n"; print "PROJECTION\tLatLon\n"; Xastir-Release-2.2.2/scripts/slideshow.pl000077500000000000000000000063671501463444000204120ustar00rootroot00000000000000#!/usr/bin/env perl # # Script to create a slideshow from Xastir snapshot images. Note # that this script is Unix/Linux-centric due to the use of the $HOME # variable and the use of the "cp" command. # # Written 20090415 by Curt Mills, WE7U # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # # Copies/renames ~/.xastir/tmp/snapshot.png files so that a # slideshow can be created from the images at a later date. The # script monitors the input directory. Any new snapshot.png file # that appears is allowed to age for a few seconds to make sure that # Xastir is done writing the file, then the file is copied to the # ~/.xastir/tmp/slideshow/ directory as a numbered file. See below # for one method for turning these files into an animated GIF, or # else bring them up in some slideshow program and display them in # numerical order. The name of the file contains the Unix Epoch # timestamp (the exact second that the file was made). # # # A note from Carl Makin, vk1kcm, modified slightly by Curt, we7u, # regarding creation of an animated GIF from the slideshow images: # # ------------------------------------------------------------------- # This will create an animated gif that loops in your browser. # gm convert -delay 20 -loop snapshot*.png animation.gif # See: # http://www.graphicsmagick.org/FAQ.html#how-do-i-create-a-gif-animation-sequence-to-display-within-netscape # I think you can also great mpegs by changing the filename to "animation.mpg". # ------------------------------------------------------------------- # $home = $ENV{"HOME"}; $input_dir = "$home/.xastir/tmp"; $output_dir = "$input_dir/slideshow"; # Create the slideshow directory if it doesn't exist mkdir $output_dir; chdir $input_dir; while (1) { $current_time = time; # Snag the age of the existing snapshot.png file $number = (stat("snapshot.png"))[9]; $difference = $current_time - $number; # If the age of the file is more than 15 seconds but less than 31 # minutes, copy the file to the slideshow directory and rename it # along the way. Note that Xastir can produce snapshots at a rate # of between one per minute, and one per 30 minutes. # if ( ($difference > 15) && ($difference < (31 * 60)) ) { # Copy the snapshot image to the slideshow directory, renaming # it with the Unix Epoch time, something like: "1239897417.png". # Only copies the file if the source file is newer than the # destination, which prevents copying the file again and again # if it's the last file in your sequence. # `cp -u snapshot.png $output_dir/$number.png`; } sleep 30; } Xastir-Release-2.2.2/scripts/split_gnis.bash000077500000000000000000000041031501463444000210500ustar00rootroot00000000000000#!/usr/bin/env bash # script created 14-MAR-04 by William Baguhn, kc9asi # This script is in the public domain. # Comments or suggestions to kc9asi@arrl.net # This script uses the "fromdos" program. You may need to change # that line to use "dos2unix" instead, depending on what utilities # are available on your system. # This will take a GNIS datapoint file (typically for a whole state, 8+Mb), # break it down into smaller chunks (typically for a county, 30-200k) # it will also throw away the stupid trailing spaces and 's at EOL. # My short experiment: the state of wisconsin. # Started with a 12.5Mb file. # ended with 93 files, totaling 6.7Mb. # and, the data files run a whole lot faster, especially when zoomed in. test -e $1 || (echo Try calling $0 with a file as an argument.; exit) # field 4 isn't just counties, but it's an acceptable label # as it's usually counties cut -f4 -d, <$1 >$1.counties # remove duplicates (sort, uniq) # the cut here gets rid of any "quirks" because of commas that came earlier # than were expected, as cut doesn't recognize quoting depths sort <$1.counties | uniq | cut -f2 -d\" >$1.counties.uniq # now we want to replace spaces with periods, so that counties with # spaces in their names work appropriately both for grep and filenaming tr " " . <$1.counties.uniq >$1.counties rm $1.counties.uniq # OK, now we should have a file with a list of the various divisions # SO, split each one apart # the regexp for grep assures that we just get "county" and not county, # hopefully this will make more sensible breaks as county names are # sometimes found in other names as well. # (i.e. Grant county, and Grant Community Park) # the \"county\" should get the former, and ignore the latter. # the fromdos/sed call will drop any dead whitespace at the end of a line # the test/rm call will delete files if they are zero length. for foo in `cat $1.counties` ; do rm -f $1.$foo echo Extracting $foo grep ,\"$foo\", $1 | fromdos | sed -e 's/[ ]*$//g' >>$1.$foo.gnis test -s $1.$foo.gnis || rm $1.$foo.gnis done # clean up after ourselves rm $1.counties Xastir-Release-2.2.2/scripts/split_gnis.pl000077500000000000000000000014101501463444000205440ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # # split_gnis.pl -- 2004 Mar 15 -- jmt@twilley.org # This script is designed to break large GNIS datapoint files # into smaller chunks and will dispose of extra whitespace properly. # It is based on a bash script written by kc9asi@arrl.net. # The filenames used as input should be put on the command line. while (<>) { next unless /[A-Z][a-z]/; s/\s+$//; my $line = $_; my @fields = split /\|/, $line; # print "Fields is @fields\n"; # key is "state county" my $key = $fields[1] . " " . $fields[4]; $key =~ s/ /_/g; push @{$county{$key}}, $line; } foreach $elem (keys %county) { my $name = $elem . ".gnis"; open(OUT,">$name"); foreach $line (@{$county{$elem}}) { print OUT $line, "\n"; } close(OUT); } Xastir-Release-2.2.2/scripts/test_coord.pl000077500000000000000000000122451501463444000205460ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # test_coord.pl: Perl code to test out the Coordinate.pm # module. # # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # # TODO: # ----- # #------------------------------------------------------------------------------------------------ use lib "/usr/local/lib"; use Coordinate; # Snag WE7U's Coordinate module &test(); # # Routine for testing out the module. # # Need to add in tests for each method and object type. # sub test { my $to_WGS84 = 0; my $from_WGS84 = 1; my $position = Coordinate->new(); $position->latitude(48.125); $position->longitude(-122.500); $position->datum("NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri"); # Datum printf("Starting position(Lat, Long): %s %s\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS format printf("Starting position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); $position->lat_lon_to_utm(); printf("Calculated UTM position(Easting, Northing, Zone): %f %f %s\n", $position->easting(), $position->northing(), $position->zone() ); $position->utm_to_lat_lon(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "Changing from NAD27 to WGS84 datum...\n"; $position = $position->datum_shift_to_wgs84(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS printf("Calculated Lat, Long position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); print "Changing from WGS84 to NAD27 datum...\n"; $position = $position->datum_shift_from_wgs84_to( "NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri" ); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "\n0\n"; my $temp = CoordinateFormat->new( "0" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( ) ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( ) ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds() ); print "180\n"; $temp->raw( "180" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180") ); print "180 30\n"; $temp->raw( "180 30" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30") ); print "180.50\n"; $temp->raw( "180.50" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180.50") ); $temp->raw( "180 30.50" ); print "180 30.50\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30.50") ); $temp->raw( "180 30 30" ); print "180 30 30\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30 30") ); $temp->raw( "180 30 30.5" ); print "180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("180 30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("180 30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30 30.5") ); $temp->raw( "-180 30 30.5" ); print "-180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("-180 30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("-180 30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("-180 30 30.5") ); EllipsoidTable->enumerate(); DatumTable->enumerate(); } Xastir-Release-2.2.2/scripts/toporama250k.pl000077500000000000000000000172521501463444000206300ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # Copyright (C) 2000-2023 The Xastir Group. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # This will retrieve the 1:250k map images from the "Department of # Natural Resources Geomatics Canada" site. These are topographic # map files for the whole of Canada! # # # - "cd /usr/local/share/xastir/maps" # # - Assure you have write privileges in the directory above either # by becoming root using the "su" command, using "sudo", or # temporarily changing ownership and/or privileges on the # "maps" directory. # # - "/usr/local/lib/xastir/toporama250k.pl" # # - The script will create/populate this directory hierarchy: # .../maps/toporama/images/ # .../maps/toporama/images/b250k/ # # - Move/rename directories/contents as you wish. # # - In Xastir: "Map->Configure->Index: Reindex ALL Maps!" # # # Note that the same map files are also available from Steve Dimse's # site: "http://mm.aprs.net/maps/geo/toporama" # # # Code for this script contributed by Adi Linden, VA3ADI. # Modifications for latitudes above 67 degrees north contributed by Tom Tessier, VE4TRT # Create the "toporama" directory mkdir "toporama"; chdir "toporama"; # Retrieve the 1:250,000 map images. Skipping those that we've # already downloaded. `wget -nv -np -nH -N -r -m -l 0 -T 10 http://toporama.cits.rncan.gc.ca/images/b250k/`; # Remove index.html files `rm -rf \`find ./images -type f -name index.html\*\``; # Remove *.asc files `rm -rf \`find ./images -type f -name \*.asc\``; # Define some stuff $base_dir = "images/b250k"; # This defines the top left corner of the 0 grid up to 67 degrees north latitude. $basex = '-56'; $basey = '44'; %offsetx = ( 'a' => 3, 'b' => 2, 'c' => 1, 'd' => 0, 'e' => 0, 'f' => 1, 'g' => 2, 'h' => 3, 'i' => 3, 'j' => 2, 'k' => 1, 'l' => 0, 'm' => 0, 'n' => 1, 'o' => 2, 'p' => 3, '1' => 3, '2' => 2, '3' => 1, '4' => 0, '5' => 0, '6' => 1, '7' => 2, '8' => 3, '9' => 3, '10' => 2, '11' => 1, '12' => 0, '13' => 0, '14' => 1, '15' => 2, '16' => 3 ); %offsety = ( 'a' => 3, 'b' => 3, 'c' => 3, 'd' => 3, 'e' => 2, 'f' => 2, 'g' => 2, 'h' => 2, 'i' => 1, 'j' => 1, 'k' => 1, 'l' => 1, 'm' => 0, 'n' => 0, 'o' => 0, 'p' => 0, '1' => 3, '2' => 3, '3' => 3, '4' => 3, '5' => 2, '6' => 2, '7' => 2, '8' => 2, '9' => 1, '10' => 1, '11' => 1, '12' => 1, '13' => 0, '14' => 0, '15' => 0, '16' => 0 ); # This defines the top left corner of the 0 grid between 68 and 84 degrees north latitude. %offsetx68 = ( 'a' => 4, 'b' => 0, 'c' => 0, 'd' => 4, 'e' => 4, 'f' => 0, 'g' => 0, 'h' => 4, '1' => 4, '2' => 0, '3' => 0, '4' => 4, '5' => 4, '6' => 0, '7' => 0, '8' => 4 ); %offsety68 = ( 'a' => 3, 'b' => 3, 'c' => 2, 'd' => 2, 'e' => 1, 'f' => 1, 'g' => 0, 'h' => 0, '1' => 3, '2' => 3, '3' => 2, '4' => 2, '5' => 1, '6' => 1, '7' => 0, '8' => 0 ); #def use File::Find; print "Writing .geo files\n"; find(\&process, $base_dir); print "\nDone.\n"; # Run for each file found sub process { # Only look for .gif files if ( /.gif$/ ) { # Get the map sheet designation from the file name $file = "$_"; $grida = substr($file, 0, 3); $gridb = substr($file, 3, 1); $hilat = substr($file, 2, 1); # .geo calculations for lattitudes greater than 78 degrees north latitude. if ( $grida > 119 ) { # Calculate top left coordinates of the map sheet use integer; $topx = $basex - ((($grida/10) +10 ) / 22 * 16) + $offsetx68{$gridb} * 2; $topy = 84 - $offsety68{$gridb} * 1; $botx = $topx + 8; $boty = $topy - 2; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t6399\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t6400\t1600\n"; close OUT; print "."; next; } # .geo calculations for lattitudes between 68 and 78 degrees north latitude. if ( $hilat > 6 ) { # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx68{$gridb} * 1; $topy = $basey + ($grida % 10) * 4 - $offsety68{$gridb} * 1; $botx = $topx + 4; $boty = $topy - 1; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t6399\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t6400\t1600\n"; close OUT; print "."; next; } # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx{$gridb} * 2; $topy = $basey + ($grida % 10) * 4 - $offsety{$gridb} * 1; $botx = $topx + 2; $boty = $topy - 1; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t3199\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t3200\t1600\n"; close OUT; print "."; } } Xastir-Release-2.2.2/scripts/toporama50k.pl000077500000000000000000000120461501463444000205420ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # Copyright (C) 2000-2023 The Xastir Group. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # This will retrieve the 1:50k map images from the "Department of # Natural Resources Geomatics Canada" site. These are topographic # map files for the whole of Canada! # # # - "cd /usr/local/share/xastir/maps" # # - Assure you have write privileges in the directory above either # by becoming root using the "su" command, using "sudo", or # temporarily changing ownership and/or privileges on the # "maps" directory. # # - "/usr/local/lib/xastir/toporama50k.pl" # # - The script will create/populate this directory hierarchy: # .../maps/toporama/images/ # .../maps/toporama/images/b50k/ # # - Move/rename directories/contents as you see fit. # # - In Xastir: "Map->Configure->Index: Reindex ALL Maps!" # # # Note that the same map files are also available from Steve Dimse's # site: "http://mm.aprs.net/maps/geo/toporama" # # # Code for this script contributed by Adi Linden, VA3ADI. # Create the "toporama" directory mkdir "toporama"; chdir "toporama"; # Retrieve the 1:50,000 map images. Skipping those that we've # already downloaded. `wget -nv -np -nH -N -r -m -l 0 -T 10 http://toporama.cits.rncan.gc.ca/images/b50k/`; # Remove index.html files `rm -rf \`find ./images -type f -name index.html\*\``; # Remove *.asc files `rm -rf \`find ./images -type f -name \*.asc\``; # Define some stuff $base_dir = "images/b50k"; # This defines the top left corner of the 0 grid. $basex = '-56'; $basey = '44'; %offsetx = ( 'a' => 3, 'b' => 2, 'c' => 1, 'd' => 0, 'e' => 0, 'f' => 1, 'g' => 2, 'h' => 3, 'i' => 3, 'j' => 2, 'k' => 1, 'l' => 0, 'm' => 0, 'n' => 1, 'o' => 2, 'p' => 3, '01' => 3, '02' => 2, '03' => 1, '04' => 0, '05' => 0, '06' => 1, '07' => 2, '08' => 3, '09' => 3, '10' => 2, '11' => 1, '12' => 0, '13' => 0, '14' => 1, '15' => 2, '16' => 3 ); %offsety = ( 'a' => 3, 'b' => 3, 'c' => 3, 'd' => 3, 'e' => 2, 'f' => 2, 'g' => 2, 'h' => 2, 'i' => 1, 'j' => 1, 'k' => 1, 'l' => 1, 'm' => 0, 'n' => 0, 'o' => 0, 'p' => 0, '01' => 3, '02' => 3, '03' => 3, '04' => 3, '05' => 2, '06' => 2, '07' => 2, '08' => 2, '09' => 1, '10' => 1, '11' => 1, '12' => 1, '13' => 0, '14' => 0, '15' => 0, '16' => 0 ); use File::Find; print "Writing .geo files\n"; find(\&process, $base_dir); print "\nDone.\n"; # Run for each file found sub process { # Only look for .gif files if ( /.gif$/ ) { # Get the map sheet designation from the file name $file = "$_"; $grida = substr($file, 0, 3); $gridb = substr($file, 3, 1); $gridc = substr($file, 4, 2); if ( $grida > 119 ) { next; } # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx{$gridb} * 2; $topy = $basey + ($grida % 10) * 4 - $offsety{$gridb} * 1; no integer; $topx = $topx + $offsetx{$gridc} * 0.5; $topy = $topy - $offsety{$gridc} * 0.25; $botx = $topx + 0.5; $boty = $topy - 0.25; # Create the output file $out = substr($file, 0, 6) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama50k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t3199\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t3200\t1600\n"; close OUT; print "."; } } Xastir-Release-2.2.2/scripts/track-get.pl000077500000000000000000000106031501463444000202560ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will ask for an item designator, then create a file # with that name + ".log" in the ~/.xastir/logs directory. The # file will contain APRS items created from the downloaded Garmin # tracklog. Reading that log file with Xastir will result in an # object with a track being displayed on the map screen. # You may wish to bump up MAX_TRACKS in db.h to 1024 in order to see # the entire log, but be careful with Xastir's memory image growing # too fast if you're connected to the 'net after making this change. # This script uses the GPS::Garmin module which can be obtained # from http://sourceforge.net/projects/perl-gps/ use GPS::Garmin; use IO::File; # Flush STDOUT $| = 1; # Hard-coded "from" callsign name. This becomes the "sending" # callsign for the APRS Items. $from = "SAR"; # Ask for the item name. This will turn into the 3-9 character APRS # item name. printf("\n\nEnter item designator: Length 1-9, all except '!' and '_' allowed, case respected:\n\n"); printf("\t123456789\n\t"); $name = <>; chomp $name; if (length($name) < 1) { die "Must be at least one character!\n"; } if (length($name) > 9) { $name =~ s/(.{9}).*/\1/; # Terminate it at 9 chars } if (length($name) < 3) { $name = $name . " "; # Pad the name with spaces $name =~ s/(.{3}).*/\1/; # Terminate it at 3 chars } # We need to enforce the naming restrictions for APRS Items. '!' # and '_' are not allowed, anything else that's printable ASCII is # ok. @j = split(//, $name); for ($i = 0; $i < length($name); $i++) { #printf("$i $j[$i]\n"); if ( ($j[$i] lt ' ') || ($j[$i] gt '~') || ($j[$i] eq '!') || ($j[$i] eq '_') ) { $j[$i] = ' '; } } $name = join("",@j); $filename = "~/.xastir/logs/$name.log"; # Get rid of spaces in the filename $filename =~ s/\s+//g; # Expand the tilde into the home directory $filename =~ s{ ^ ~ ( [^/]* ) } { $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7] ) }ex; printf("\nThe item designator will be: ($name)\n"); printf("The output filename will be: ($filename)\n\n"); printf("Connect Garmin GPS to /dev/ttyS0 (COM1), set it to Garmin/Garmin mode.\n"); printf("Press to proceed with download, Ctrl-C to abort\n"); <>; # Create a file to hold the data $output = IO::File->new("> $filename") or die "Couldn't open $filename for writing: $!\n"; $gps = new GPS::Garmin( 'Port' => '/dev/ttyS0', 'Baud' => 9600, ) or die "Unable to connect to receiver: $!"; # Transfer trackpoints: $i = 0; $gps->prepare_transfer("trk"); while ($gps->records) { ($lat,$lon,$time) = $gps->grab; # printf("%f %f %d\n",$lat,$lon,$time); if ($lon < 0) { $londeg = sprintf("%d",-$lon); $lonmin = (-$lon - $londeg) * 60; $lonchar = "W"; } else { $londeg = sprintf("%d",$lon); $lonchar = "E"; $lonmin = ($lon - $londeg) * 60; } if ($lat < 0) { $latdeg = sprintf("%d",-$lat); $latmin = (-$lat - $latdeg) * 60; $latchar = "S"; } else { $latdeg = sprintf("%d",$lat); $latmin = ($lat - $latdeg) * 60; $latchar = "N"; } # Write an APRS Item for each trackpoint printf($output "%s>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s%s\n", $from, $name, $latdeg, $latmin, $latchar, $londeg, $lonmin, $lonchar, "/"); if (! ($i % 10) ) { printf("$i "); } $i++; } printf("\n\nThe data has been saved in: ($filename)\n"); printf("Please open this logfile with Xastir to display the track\n"); printf("!!!Remember to set your GPS back to NMEA mode for APRS!!!\n"); Xastir-Release-2.2.2/scripts/update_langfile.pl000077500000000000000000000112071501463444000215210ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # Update utility for XASTIR language files 17.04.2001 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This program adds missing entries to the translated language files and # deletes obsolete entries. # If a translated comment before an entry block is found it will be preserved. # There might be problems with the comment with a changed block sequence. # I assume that you start it in the directory with the language files, # call it with the translated language file as parameter. # DK7IN: for now it assumes that the language files reside # in the current directory #-------------------------------------------------------------------------- $LF1 = "language-English.sys"; # original language file $LF2 = "language-German.sys"; # translated language file $LFOUT = "language-new.sys"; # modified translated language file if (@ARGV) { $LF2 = shift @ARGV; } #-------------------------------------------------------------------------- open(IN1,$LF1) or die "ERROR: could not open $LF1!\n"; open(IN2,$LF2) or die "ERROR: could not open $LF2!\n"; open(OUT,">$LFOUT") or die "ERROR: could not write to $LFOUT!\n"; #-------------------------------------------------------------------------- %token = (); # translated tokens @cmt1 = (); # original comment @cmt2 = (); # translated comment # collect all available translated tokens while () { next if (/^#/); # skip comment lines if (/^([A-Z]+[0-9]+)(|.+|.?|.*)$/) { $token{$1} = $2; # store translated text entry } } # process language file while () { # original language file if (/^#/) { # comment line push(@cmt1,$_); # store comment } else { if (/^([A-Z]+)([0-9]+)(|.+|.?|.*)$/) { # data line $name = $1; $numb = $2; $arg = $3; if (@cmt1) { # pending comment # try to find the translation seek IN2, 0, 0; # reposition to begin of file @cmt2 = (); # translated comment $match = 0; while () { $line = $_; if (/^([A-Z]+)([0-9]+)(|.+|.?|.*)$/) { $curr = $1; if ($name eq $curr) { # same block $match = 1; last; } else { @cmt2 = (); # clear wrong comment } } else { if (/^#/) { # store comment push(@cmt2,$_); } } } if ($match && @cmt2) { # found translated comment foreach $line (@cmt2) { print(OUT $line); # translated comment } } else { foreach $line (@cmt1) { print(OUT $line); # original comment } } @cmt1 = (); } if ($token{$name.$numb}) { # found translation $arg = $token{$name.$numb}; } printf(OUT "%s%s%s\n",$name,$numb,$arg); } else { print("ERROR: $_"); # bad line format } } } close(IN1); close(IN2); close(OUT); exit; #-------------------------------------------------------------------------- Xastir-Release-2.2.2/scripts/waypoint-get.pl000077500000000000000000000104111501463444000210210ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will ask for a name, then create a file # with that name + ".log" in the ~/.xastir/logs directory. The # file will contain APRS items created from the downloaded Garmin # waypoints. Reading that log file with Xastir will result in one # item appearing on the map screen for each waypoint, labeled with # the name of that waypoint. # This script uses the GPS::Garmin module which can be obtained # from http://sourceforge.net/projects/perl-gps/ use GPS::Garmin; use IO::File; # Flush STDOUT $| = 1; # Hard-coded "from" callsign name. This becomes the "sending" # callsign for the APRS Items. $from = "SAR"; # Ask for the name. This gets changed into the complete log file name. printf("\n\nEnter name for file: '.log' will get added to the end:\n\n"); $name = <>; chomp $name; if (length($name) < 1) { die "Must be at least one character!\n"; } $filename = "~/.xastir/logs/$name.log"; # Get rid of spaces in the filename $filename =~ s/\s+//g; # Expand the tilde into the home directory $filename =~ s{ ^ ~ ( [^/]* ) } { $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7] ) }ex; printf("\nThe output filename will be: ($filename)\n\n"); printf("Connect Garmin GPS to /dev/ttyS0 (COM1), set it to Garmin/Garmin mode.\n"); printf("Press to proceed with download, Ctrl-C to abort\n"); <>; # Create a file to hold the data $output = IO::File->new("> $filename") or die "Couldn't open $filename for writing: $!\n"; $gps = new GPS::Garmin( 'Port' => '/dev/ttyS0', 'Baud' => 9600, ) or die "Unable to connect to receiver: $!"; # Transfer waypoints: $i = 0; $gps->prepare_transfer("wpt"); while ($gps->records) { ($title,$lat,$lon,$desc) = $gps->grab; #printf("%f\t%f\t%s\t%s\n",$lat,$lon,$desc,$title); if ($lon < 0) { $londeg = sprintf("%d",-$lon); $lonmin = (-$lon - $londeg) * 60; $lonchar = "W"; } else { $londeg = sprintf("%d",$lon); $lonchar = "E"; $lonmin = ($lon - $londeg) * 60; } if ($lat < 0) { $latdeg = sprintf("%d",-$lat); $latmin = (-$lat - $latdeg) * 60; $latchar = "S"; } else { $latdeg = sprintf("%d",$lat); $latmin = ($lat - $latdeg) * 60; $latchar = "N"; } chomp $title; if (length($title) < 1) { die "Must be at least one character!\n"; } if (length($title) > 9) { $title =~ s/(.{9}).*/\1/; # Terminate it at 9 chars } if (length($title) < 3) { $title = $title . " "; # Pad the title with spaces $title =~ s/(.{3}).*/\1/; # Terminate it at 3 chars } # We need to enforce the naming restrictions for APRS Items. '!' # and '_' are not allowed, anything else that's printable ASCII is # ok. @j = split(//, $title); for ($k = 0; $k < length($title); $k++) { #printf("$k $j[$k]\n"); if ( ($j[$k] lt ' ') || ($j[$k] gt '~') || ($j[$k] eq '!') || ($j[$k] eq '_') ) { $j[$k] = ' '; } } $title = join("",@j); # Write an APRS Item for each waypoint printf($output "%s>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s%s\n", $from, $title, $latdeg, $latmin, $latchar, $londeg, $lonmin, $lonchar, "/"); if (! ($i % 10) ) { printf("$i "); } $i++; } printf("\n\nThe data has been saved in: ($filename)\n"); printf("Please open this logfile with Xastir to display the waypoints.\n"); printf("!!!Remember to set your GPS back to NMEA mode for APRS!!!\n"); Xastir-Release-2.2.2/scripts/wms.pl000077500000000000000000000102541501463444000172050ustar00rootroot00000000000000#!/usr/bin/env perl use warnings; # # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # Run this as "./wms.pl URL", where URL = a "GetCapabilities" link, but # with a backslash added before each '&' character. The script will # download the XML file at that URL and parse it. It will then attempt # to find the map layer names and list them at the end of the run. #my $xml_text = `wget -O - "http://geogratis.gc.ca/maps/CBMT?service=wms\&version=1.1.1\&request\=GetCapabilities"`; #my $xml_text = `wget -O - "http://nowcoast.noaa.gov/arcgis/services/nowcoast/radar_meteo_imagery_nexrad_time/MapServer/WMSServer?request=GetCapabilities\&service=WMS\&version=1.3.0"`; # # Once you have the map layer names it is relatively easy to construct a # .geo file for Xastir that uses one of those map layers. Here's an example # from README.MAPS. Both lines are required in the .geo file: # ----------------------- # WMSSERVER # URL http://geogratis.gc.ca/maps/CBMT?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Sub_regional&STYLES=&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE # ----------------------- # #Here's the info from Dumper that we're interested in (Name): #$VAR1 = { # 'Capability' => [ # { # 'Layer' => [ # { # 'Layer' => [ # { # 'Name' => [ # 'National' # # -or- # #$VAR1 = { # 'Capability' => { # 'Layer' => { # 'Layer' => { # 'Layer' => [ # { # 'Name' => '1', use strict; use XML::Simple; use Getopt::Std; use Data::Dumper; use Scalar::Util 'reftype'; my $url; $url = shift; if (!defined $url || $url eq "") { print "Please enter GetCapabilities URL with '\' before each '&' character.\n"; $url = <>; } my $xml_text= `wget -O - $url`; my $xml = XMLin( $xml_text ); print Dumper($xml); print "\n----------------------------------------------------------\n\n"; my $version = $url; $version =~ s/.*version=(\d+\.\d+\.\d+).*/$1/; if ($version =~ /\d+\.\d+\.\d+/) { } else { $version = "1.0.0"; } my $url_filtered = $url; $url_filtered =~ s/\\//g; # Get rid of backslashes $url_filtered =~ s/(.*\?).*/$1/; # Remove everything after '?' $url_filtered = "URL " . $url_filtered . "SERVICE=wms&VERSION=$version&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=false&STYLES=&LAYERS="; print "POSSIBLE .GEO FILE CONTENTS:\n\n"; my $ii; my $reftype = reftype $xml->{Capability}->{Layer}->{Layer}; if ( (defined $reftype) && ($reftype eq 'ARRAY') ) { for ($ii = 0; $ii < 15; $ii++) { if ( defined($xml->{Capability}->{Layer}->{Layer}->[$ii]->{Name}) ) { print "-----\n"; print "WMSSERVER\n"; print $url_filtered; print "$xml->{Capability}->{Layer}->{Layer}->[$ii]->{Name}\n"; } } } if ( (defined $reftype) && ($reftype eq 'HASH') ) { for ($ii = 0; $ii < 15; $ii++) { if ( defined($xml->{Capability}->{Layer}->{Layer}->{Layer}->[$ii]->{Name}) ) { print "-----\n"; print "\nWMSSERVER\n"; print $url_filtered; print "$xml->{Capability}->{Layer}->{Layer}->{Layer}->[$ii]->{Name}\n"; } } } Xastir-Release-2.2.2/scripts/wxnowsrv.pl000077500000000000000000000115741501463444000203220ustar00rootroot00000000000000#!/usr/bin/env perl # Copyright (C) 2000-2023 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # This script is used to feed weather data from a "Wxnow.txt" file # into Xastir as if it were a networked weather station. Wxnow.txt is # a standard file format that is created by a number different types # of weather station control software, and Xastir is unable to read # this file directly. # # The command line arguments are the path to the Wxnow.txt file, and # a polling period in seconds (this should be chosen to be the same period # that the Wxnow.txt file is updated by whatever tool is creating it. # An optional third argument allows the user to specify an alternate # server port other than 5500. # The script works by polling the Wxnow.txt file each $POLLTIME, and if # anything changes, flagging the change. This is done in one thread. # For each client that connects to the port, a new thread is created for # communicating with that client over a socket. Each time the polling thread # flags that data has changed, a string of weather data is sent to all connected # clients. # This script leverages the "Davis METEO" code in Xastir that implements # the networked weather station interface. As such, all weather stations # connected in this way to Xastir are assumed to be Davis weather stations, # no matter what type of weather station is connected. # Once this script is running, add a "Networked WX" interface to your Xastir # config, and provide the IP address on which the script is running and the # port number (default 5500) in the interface properties. # Once Xastir connects to the script, "View->Own Weather Data" should show # the current weather data in Wxnow.txt, and be updated every time Wxnow.txt # changes. use threads; use threads::shared; use IO::Socket; use Net::hostent; # for OO version of gethostbyaddr sub read_wxnow { my ($pathname,$lastwxref,$wxchangedref,$POLLTIME) = @_; my $slash="/"; while ( -e $pathname) { open (WXNOWFILE, "<$pathname") || die "Cannot open wxnow file $pathname\n"; my $firstline=1; while () { if ($firstline==1) { $firstline=0; next; } else { $newwx=$_; chomp($newwx); $newwx =~ s/^([0-9]{3})$slash([0-9]{3})g/c$1s$2g/; $newwx = $newwx . "xDvs"; if ($newwx ne $$lastwxref) { $$lastwxref=$newwx; $$wxchangedref =1; } else { $$wxchangedref=0; } } } close (WXNOWFILE); sleep $POLLTIME; } } sub handle_connection { my ($socket,$lastwxref,$wxchangedref,$POLLTIME) = @_; my $disconn = 0; my $firsttime=1; $socket->autoflush(1); my $hostinfo = gethostbyaddr($socket->peeraddr); while (1) { $foobar=getpeername($socket) or $disconn=1; if ($socket->connected()) { $disconn=0; } else { $disconn=1; } if ($disconn==0) { if ($$wxchangedref==1 || $firsttime==1) { send($socket,"$$lastwxref\n",0); $firsttime=0; } sleep $POLLTIME/2; } last if $disconn==1; } } if ( $#ARGV < 1) { print STDERR "Usage: $0 wxnowpath pollsecs [port]\n"; print STDERR " where wxnowpath is the full path to your wxnow.txt file\n"; print STDERR " and pollsecs is how often we should check this file for changes (in seconds)\n"; print STDERR " If given, the third argument is the port number on which to listen. Default=5500"; exit(1); } $SERVER_PORT=5500; if ( $#ARGV >1) { $SERVER_PORT=$ARGV[2]; } my $listen = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $SERVER_PORT, ReuseAddr => 1, Listen => SOMAXCONN ); my $lastwx : shared =""; my $wxchanged : shared =0; my $POLLTIME =$ARGV[1]; $pathname=$ARGV[0]; async(\&read_wxnow, $pathname,\$lastwx,\$wxchanged,$POLLTIME)->detach; while (my $socket = $listen->accept) { async(\&handle_connection, $socket,\$lastwx,\$wxchanged,$POLLTIME)->detach; } Xastir-Release-2.2.2/src/000077500000000000000000000000001501463444000151355ustar00rootroot00000000000000Xastir-Release-2.2.2/src/.vimrc000066400000000000000000000014331501463444000162570ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/src/LICENSE.geocoder000066400000000000000000000476271501463444000177500ustar00rootroot00000000000000 The enclosed material (the "Material") is copyrighted 2002 by me, Daniel Egnor. I certify that I am the sole copyright holder of the Material, excluding material derived from the original Google contest materials ("Contest Materials"). Contest materials are used under the terms of the license included below as "Original Google License". Google, Inc. is hereby granted a worldwide, perpetual, fully paid-up, non-exclusive license to make, sell, or use the technology related to the Material, including but not limited to the software, algorithms, techniques, concepts, etc. associated with the Material. The public is hereby granted rights to the Material under the terms of the GNU General Public License, also included below. Any necessary exemptions required to redistribute the Material along with the contest materials are hereby granted. ------------------------------------------------------------------------------- Original Google License (applies to all files "goo-*") follows: ------------------------------------------------------------------------------- This repository of web page information is being provided to you by Google Inc. solely for academic and research purposes related to the Google programming contest. You may not modify, distribute, or make any commercial use of the repository. This source code is copyrighted 2002 by Google Inc. All rights reserved. You are given a limited license to use this source code for purposes of participating in the Google programming contest. If you choose to use or distribute the source code for any other purpose, you must either (1) first obtain written approval from Google, or (2) prominently display the foregoing copyright notice and the following warranty and liability disclaimer on each copy used or distributed. The source code and repository (the "Software") is provided "AS IS", with no warranty, express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular use. In no event shall Google Inc. be liable for any damages, direct or indirect, even if advised of the possibility of such damages. ------------------------------------------------------------------------------- GNU General Public License (applies to all other files) follows: ------------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Xastir-Release-2.2.2/src/Makefile.am000066400000000000000000000044041501463444000171730ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # bin_PROGRAMS = xastir xastir_udp_client testdbfawk SUBDIRS = rtree DIST_SUBDIRS = rtree EXTRA_DIST=icon.xbm XASTIR_SRC = \ alert.c alert.h \ awk.c awk.h \ bulletin_gui.c bulletin_gui.h \ color.c color.h \ datum.c datum.h \ db.c database.h \ db_gis.c db_gis.h \ dbfawk.c dbfawk.h \ dlm.c dlm.h \ draw_symbols.c draw_symbols.h \ fcc_data.c fcc_data.h \ festival.c festival.h \ fetch_remote.c fetch_remote.h \ forked_getaddrinfo.c forked_getaddrinfo.h \ geo-find.c geo.h \ geocoder_gui.c \ gps.c gps.h \ hashtable.c hashtable_private.h hashtable.h \ hashtable_itr.c hashtable_itr.h \ igate.c igate.h \ interface.c interface.h \ interface_gui.c \ io-common.c io-mmap.c io.h \ lang.c lang.h \ leak_detection.h \ list_gui.c list_gui.h \ locate_gui.c \ location.c \ location_gui.c \ main.c main.h \ maps.c maps.h \ map_cache.c map_cache.h \ map_dos.c \ map_geo.c \ map_gnis.c \ map_OSM.c map_OSM.h \ map_pop.c \ map_shp.c \ map_tif.c \ map_WMS.c \ messages.c messages.h \ messages_gui.c \ objects.h objects.c \ popup.h \ popup_gui.c \ rac_data.c rac_data.h \ rotated.c rotated.h \ rpl_malloc.c rpl_malloc.h \ shp_hash.c shp_hash.h \ snprintf.c snprintf.h \ sound.c symbols.h \ tile_mgmnt.c tile_mgmnt.h \ track_gui.c track_gui.h \ util.c util.h \ view_message_gui.c \ wx.c wx.h \ wx_gui.c \ x_spider.c x_spider.h \ xa_config.c xa_config.h \ xastir.h xastir_SOURCES = $(XASTIR_SRC) compiledate.c xastir_udp_client_SOURCES = \ xastir_udp_client.c testdbfawk_SOURCES = \ testdbfawk.c \ awk.c \ dbfawk.c \ rpl_malloc.c rpl_malloc.h .PHONY: compiledate.c compiledate.c: $(XASTIR_SRC) rm -f compiledate.c compiledate.o echo 'char gitstring[] = "'"`$(top_srcdir)/scripts/XastirGitStamp.sh $(top_srcdir)`"'";' >> compiledate.c remove_compiledate: rm -f compiledate.c compiledate.o xastir_LDADD=-Lrtree -lrtree xastir_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ xastir_udp_client_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ testdbfawk_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.2/src/alert.c000066400000000000000000002307201501463444000164140ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // alert_redraw_on_update will cause refresh_image to get called. // alert_add_entry sets it. // In the alert structure, flags[] is size 16. Only the first two // positions in the array are currently used. // // alert_entry.flags[0] // on_screen // ? Initial state or ready-to-recompute state // - Expired between 1 sec and 1 hour // Y Active alert within viewport // N Active alert outside viewport // // alert_entry.flags[1] // source // DATA_VIA_TNC // DATA_VIA_LOCAL // // alert_entry.to alert_entry.alert_level // CANCL C // Colors of alerts????? // TEST T // Colors of alerts????? // WARN R // Colors of alerts????? // CIVIL R // Colors of alerts????? // WATCH Y // Colors of alerts????? // ADVIS B // Colors of alerts????? // Other G // Colors of alerts????? // Unset ? // // // Here's how Xastir breaks down an alert into an alert struct: // // SFONPW>APRS::NWS-ADVIS:191700z,WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // |----| |-------| |-----| |--| |-----| |-----| |-| // | | | | | | | // from to | | title title issue_date // | alert_tag // activity (expiration) // // // The code should also handle the case where the packet looks like // this (it's the same as the above packet except for no expiration // date): // // SFONPW>APRS::NWS-ADVIS:WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // // // Expiration is then computed from the activity field. Alert_level // is computed from "to" and/or "alert_tag". // // // Stuff from Dale, paraphrased by Curt: // // WATCH - weather of some type is possible or probable for a geographic // area- at present I cannot do watches because they can cover huge areas // with hundreds of counties across many states. I have a prototye of a // polygon generator - but that is a whole other can of worms // // WARN - warning - Severe or dangerous weather is occurring or is about to // occur in a geographical area. This we do a pretty good job on output. // // ADVIS - advisory - this can be trivial all the way to a tornado report. // If a tornado warning is issued and another tornado sighting happens in // the same county/zone during the valid time of the first- the info is // transmitted as an advisory. Most of the time is is updates for other // messages. // // CANCL - cancelation- discussed in earlier e-mail // // I would add CIVIL for terrorist earthquake catostrophic type stuff - // the D7 and D&)) have special alarms built in so that a message to // NWS-CIVIL would alert folks no matter what there filters are set for. // // // The clue to which shapefile to use is in the 4th char in the // title (which is the first following an '_') // // ICTSVS>APRS::NWS-ADVIS:120145z,SEVERE_WEATHER,KS_Z091, {C14AA // TSASVR>APRS::NWS-WARN :120230z,SVRTSM,OK_C113, OSAGE COUNTY {C16AA // // C = county file (c_mmddyy.dbf) // A = County Warning File (w_mmddyy.dbf) // Z = Zone File (z_mmddyy.dbf or mz_mmddyy.dbf) // F = Fire zone file (fz_mmddyy.dbf) // A = Canadian Area (a_mmddyy.dbf) // R = Canadian Region (r_mmddyy.dbf) // // Alerts are comma-delimited on the air s.t. after the // :NWS-?????: the first field is the time in zulu (or local // with no 'z'), the 2nd is the warning type // (severe_thunderstorm etc.), the 3rd and up to 7th are s.t. // the first 2 letters are the state or marine zone (1st field // in both the county and zone .dbf files) followed by an // underline char '_', the area type as above (C, Z, or A), // then a 3 digit numerical code derived from: // // Counties: the fips code (4th field in the .dbf) // // Zones: the zone number (2nd field in the .dbf) // // Marine Zones: have proper code in 1st field with addition of '_' in correct place. // // CWA: 2nd field has cwa-, these are always "CW_A" plus the cwa // // You must ignore anything after a space in the alert. // // We will probably want to add the "issue time" to the alert record // and parse that out if it's present. Change the view dialog to // show expiration time, issue time, who the alert is apparently // from, and the stuff after the curly brace. Some of that info // will be useful soon in a finger command to the weather server. // // New compressed-mode weather alert packets: // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ003>007-012>016-021>025-030>034-037>047-052>057-062>069{LLSAA // // The trick is to step thru the data base contained in the // shapefiles to determine what areas to light up. In the above // example read ">" as "thru" and "-" as "and". // // More from Dale: // It occurs to me you might need some insight into what shapefile to look // through for a zone/county. The current shape files are c_22mr02, // z_16mr02, and mz21fe02. // // ICTSVS>APRS::NWS-ADVIS:120145z,SEVERE_WEATHER,KS_Z091, {C14AA // would be in z_ file // // TSASVR>APRS::NWS-WARN :120230z,SVRTSM,OK_C113, OSAGE COUNTY {C16AA // would be in c_ file // // problem comes with marine warnings- // // AM,AN,GM,PZ,PK,PM,LS,LM,LH,LO,LE,SL will look like states, but will all // come from the mz file. // // so AM_Z686 looks like a state zone, but is a marine zone. // Aprs Plus requires the exact file name to be specified - winaprs just // looks for a file in the nwsshape folder starting c_ z_ and mz. Someone // in the middle of Kansas might not need the marine at all- but here I am // closer to marine zones than land. The fact there is an index file for // the shapes should help the speed in a lookup. // // More from Dale: // The CWA areas themselves were included for just one product- generally // called the "Hazardous Weather Outlook". The idea was to be able to // click on your region and get a synopsis as a Skywarn Heads-up. In // winaprs it turned out that you would get (unwanted) the CWA outline // instead of some other data about a specific station. It makes more // sense to have three or 4 "home CWA'S" that are defined in the config // file - and have a dialog box to view the Hazardous WX Outlook and // watches and warnings just for that CWA. One step futher- I assume there // is something that trips alarms when a warning is received for a county // or zone right around you - the cwa or cwa's of interest could be derived // from that if it already exists. A long way to say don't worry about CWA // maps as far as watches/warnings. // // I think the easy coding for determining which shapefile to use would // look like; // // char sevenCharStr[8]; // seven character string in warning or derived // // from compressed string i. e. AL_Z001 // // if the 4th char == 'C' then use "c_shapefile" // if the 4th char == 'Z'; // if the first two char == 'AN' || // if the first two char == 'AM' || // if the first two char == 'GM' || // If the first two char == 'PZ' || // if the first two char == 'LH' || // if the first two char == 'LO' || // if the first two char == 'LS' || // if the first two char == 'SL' || // if the first two char == 'LM' || // then use the "mzshapefile" // else use the "z_shapefile" // // I am running out of time but that should be all there is to it- I // will send you a complete list of marine zones later today- I // think there are no more than 13 or 14 to search through - better // that the 54 "states"- could be hard coded. // We now have fire weather alerts also. From Dale: // "Ok I think we can use this to solve a problem with the Fire // Watches and Warnings taking over the map of someone not // interested. Roger, I had to take Fire warnings off the regular // aprs-is feeds and send it to firenet.us server only because of // complaints of the maps getting cluttered-- with data most people // didn't want. Even though the NWS sends "AZZ148" just as if it // were to be found in the z_mmddyy.dbf (warning zone) type file, // wxsvr knows it is coming out of a "Fire Weather" type product and // can substitute "AZF148" . Client software (read xastir & // Ui-view) would know to look in the fireweather shapefile. If // someone doesn't have the fire shapefile loaded, it would just be // ignored (I think)." // Found on the AWIPS web pages so far: // AWIPS Counties C // County Warning Areas A // Zone Forecast Areas Z // Coastal Marine Zones Z // Offshore Marine Zones Z // High Seas Marine Zones Z (Says "Not for operational use") // Fire Weather Zones FZ // // Don't forget about the Canadian Areas and Regions, which are // created by Dale Huguley from Environment Canada data. // // // AWIPS Counties: // ----------------------------- // STATE character 2 // CWA character 9 // COUNTYNAME character 24 // FIPS character 5 // TIME_ZONE character 2 // FE_AREA character 2 // LON numeric 10,5 // LAT numeric 9,5 // // // County Warning Areas: // ----------------------------- // WFO character 3 // CWA character 3 // LON numeric 10,5 // LAT numeric 9,5 // // // Zone Forecast Areas: // ----------------------------- // STATE character 2 // ZONE character 3 // CWA character 3 // NAME character 254 // STATE_ZONE character 5 // TIME_ZONE character 2 // FE_AREA character 2 // LON numeric 10,5 // LAT numeric 9,5 // // // Coastal and Offshore Marine Zones: // ---------------------------------- // ID character 6 // WFO character 3 // NAME character 250 // LON numeric 10,5 // LAT numeric 9,5 // WFO_AREA character 200 // // // High Seas Marine Zones: // ----------------------------- // WFO character 3 // LON numeric 10,5 // LAT numeric 9,5 // HEADING character 250 #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "xastir.h" #include "alert.h" #include "util.h" #include "snprintf.h" #include "wx.h" #include "hashtable.h" #include "hashtable_itr.h" // Must be last include file #include "leak_detection.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } // New method for weather alerts, using a hash // #define ALERT_HASH_SIZE 4096 static struct hashtable *wx_alert_hash = NULL; int alert_redraw_on_update = 0; ///////////////////////////////////////////////////////////////////// // The following group of functions implement hash storage for // weather alerts. This makes the code very fast, which is good // because we run through these alerts often. ///////////////////////////////////////////////////////////////////// // Starting with an alert_entry, create a concatenated string // containing: // // *) "From" callsign // *) Zone // *) First four chars after the '{' char (the "issue date" field // plus one more character). // // These items should make the alert unique or nearly unique whether // it was received from the WXSVR software or from hand-entered // alerts. WXSVR is where all of the machine-readable alerts come // from and is run by Dale Huguley. // // This function takes a mostly filled-in alert_entry and fills in // the unique_string variable portion with values from other // variables in the record. // void alert_fill_unique_string(alert_entry *alert) { xastir_snprintf(alert->unique_string, sizeof(alert->unique_string), "%s%s%c%c%c%c", alert->from, alert->title, alert->seq[0], alert->seq[1], alert->seq[2], alert->seq[3]); //fprintf(stderr,"'%s'\t'%s'\t'%s'\n", alert->from, alert->title, alert->seq); //fprintf(stderr,"Unique string:'%s'\n", alert->unique_string); } // Add the chars (multiplied by a function of their index number to // weight them) then truncate the final number to ALERT_HASH_SIZE. // This should spread them nicely over the entire hash table. // unsigned int wx_alert_hash_from_key(void *key) { alert_entry *temp = key; char *jj = temp->unique_string; unsigned int hash = 1; int ii = 1; while (*jj != '\0') { hash = hash + ((unsigned int)*jj++ * ii); ii += 4; } hash = hash % ALERT_HASH_SIZE; //fprintf(stderr,"%d\n", hash); return ((unsigned int)hash); } // According to Dale Huguley the FROM callsign plus the first four // chars after the curly brace (at the end) should make the record // unique. Whether or not CANCEL messages get assigned to the // proper live record is another matter. They may, or may not match // using this scheme, but it's probably better than other schemes. // Multiple types of alerts can come out in the same message for the // same zone/county. In this case the fourth character will change // from an 'A' to a 'B' or other char to denote the different // messages with the same FROM and timestamp chars. This again // keeps each alert unique. // int wx_alert_keys_equal(void *key1, void *key2) { alert_entry *t1 = key1; alert_entry *t2 = key2; // These fprintf's allow us to see how many cache hits we get // and what the results were of the match. If different // unique_string's hash to the same value, we run through this // compare once for each already-inserted record that also has // the same hash value. // fprintf(stderr,"Comparing %s to %s\t",(char *)key1,(char *)key2); if (strlen((char *)t1->unique_string) == strlen((char *)t2->unique_string) && strncmp((char *)t1->unique_string, (char *)t2->unique_string, strlen((char *)t1->unique_string))==0) { //fprintf(stderr," match %s = %s\n", t1->unique_string, t2->unique_string); return(1); } else { //fprintf(stderr," no match\n"); return(0); } } // Creates the wx_alert_hash if it doesn't exist yet. If clobber is // non-zero, destroys any existing hash then creates a new one. // void init_wx_alert_hash(int clobber) { // fprintf(stderr," Initializing wx_alert_hash \n"); // make sure we don't leak //fprintf(stderr,"init_wx_alert_hash\n"); if (wx_alert_hash) { //fprintf(stderr,"Already have one!\n"); if (clobber) { //fprintf(stderr,"Clobbering hash table\n"); hashtable_destroy(wx_alert_hash, 1); wx_alert_hash = create_hashtable(ALERT_HASH_SIZE, wx_alert_hash_from_key, wx_alert_keys_equal); } } else { //fprintf(stderr,"Creating hash table from scratch\n"); wx_alert_hash = create_hashtable(ALERT_HASH_SIZE, wx_alert_hash_from_key, wx_alert_keys_equal); } } // Fetch an alert from the wx_alert_hash based on the from call // concatenated with the first four chars after the '{' character. // This concatenated string should be unique across weather alerts // if the alert came from the WXSVR. // // If it was a hand-entered alert, it won't have the '{' string at // the end. In that case use the from call and zone concatenated // together instead for matching purposes. // alert_entry *get_wx_alert_from_hash(char *unique_string) { alert_entry *result = NULL; if (unique_string == NULL || *unique_string == '\0') { fprintf(stderr,"Empty unique_string passed to get_wx_alert_from_hash()\n"); return(NULL); } if (!wx_alert_hash) { // no table to search //fprintf(stderr,"Creating hash table\n"); init_wx_alert_hash(1); // so create one return NULL; } //fprintf(stderr," searching for %s...",unique_string); result = hashtable_search(wx_alert_hash, unique_string); return (result); } // Add a wx alert to the hash. // This function checks whether there already is something in the // hash table that matches. If a match found, it skips the record, // else it inserts a new wx alert record into the hash. // // Unfortunately it appears that any unique_string that hashes to // the same value causes us to think it's a duplicate. // void add_wx_alert_to_hash(char *unique_string, alert_entry *alert_record) { alert_entry *temp; // alert_record alert_entry *new_record; char *new_unique_str; if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash start\n"); } if (unique_string == NULL || unique_string[0] == '\0' || alert_record == NULL) { if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash finish\n"); } return; } if (!wx_alert_hash) { // no table to add to //fprintf(stderr,"init_wx_alert_hash\n"); init_wx_alert_hash(1); // so create one } // Remove any matching entry to avoid duplicates temp = hashtable_remove(wx_alert_hash, unique_string); if (temp) { // If value found, free the storage space for it as // the hashtable_remove function doesn't. It does // however remove the key (callsign) ok. free(temp); } //fprintf(stderr, "\t\t\tAdding %s...\n", unique_string); // Allocate new space for the key and the record new_unique_str = (char *)malloc(50); CHECKMALLOC(new_unique_str); new_record = (alert_entry*)malloc(sizeof(alert_entry)); CHECKMALLOC(new_record); xastir_snprintf(new_unique_str, 50, "%s", unique_string); memcpy(new_record, alert_record, sizeof(alert_entry)); // hash title alert_record if (!hashtable_insert(wx_alert_hash, new_unique_str, new_record)) { fprintf(stderr,"Insert failed on wx alert hash --- fatal\n"); free(new_unique_str); free(new_record); // exit(1); } // Yet another check to see whether hash insert/update worked // properly temp = get_wx_alert_from_hash(unique_string); if (!temp) { fprintf(stderr,"***Failed wx alert hash insert/update***\n"); } else { //fprintf(stderr,"Current: %s -> %s\n", // unique_string, // temp); } if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash finish\n"); } } // Create the wx alert hash table iterator so that we can iterate // through the entire hash table and draw the alerts. // struct hashtable_itr *create_wx_alert_iterator(void) { if (wx_alert_hash && hashtable_count(wx_alert_hash) > 0) { return(hashtable_iterator(wx_alert_hash)); } else { return(NULL); } } // Get the wx alert entry that the iterator is pointing to. Advance // the iterator to the following wx alert. // alert_entry *get_next_wx_alert(struct hashtable_itr *iterator) { alert_entry *temp = NULL; if (wx_alert_hash && iterator && hashtable_count(wx_alert_hash) > 0) { // Get record temp = hashtable_iterator_value(iterator); // Advance to the next record hashtable_iterator_advance(iterator); } return(temp); } // alert_print_list() // // Debug routine. Currently attached to the Test() function in // main.c, but the button in the file menu is normally grey'ed out. // This function prints the current weather alert list out to the // xterm. // void alert_print_list(void) { } // Needed by alert_expire() below static time_t last_alert_expire = 0; // alert_expire() // // Function which iterates through the wx alert hash table, removing // expired alerts as it goes. Makes sure that the expired alert // doesn't get drawn or shown in the View->WX Alerts dialog. // // Returns the quantity of alerts that were just expired. // int alert_expire(int curr_sec) { // int ii; int expire_count = 0; struct hashtable_itr *iterator; alert_entry *temp; // Check only every 60 seconds if ( (last_alert_expire + 60) > curr_sec ) { return(0); } last_alert_expire = curr_sec; if (debug_level & 2) { fprintf(stderr,"Checking for expired alerts...\n"); } iterator = create_wx_alert_iterator(); while (iterator) { // Get current record temp = hashtable_iterator_value(iterator); if (!temp) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 1\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return(expire_count); } // If wx alert has expired, remove the record from the hash. if (temp->expiration < time(NULL)) { if (debug_level & 2) { fprintf(stderr, "alert_expire: Clearing %s, current: %lu, alert: %lu\n", temp->unique_string, (unsigned long)time(NULL), (unsigned long)temp->expiration); } // Free the storage space free(temp); // Delete the entry and advance to the next hashtable_iterator_remove(iterator); expire_count++; } else { if (temp && iterator) { // Else advance to the next entry hashtable_iterator_advance(iterator); } } } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 2\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC // Cause a screen redraw if we expired some alerts if (expire_count) { // Schedule a screen update 'cuz we have a new alert alert_redraw_on_update = redraw_on_new_data = 2; } return(expire_count); } // alert_add_entry() // // This function adds a new alert to our alert list. // // Returns address of new entry or NULL. // Called from alert_build_list() function. // /*@null@*/ static alert_entry *alert_add_entry(alert_entry *entry) { // alert_entry *ptr; // int i; set_dangerous("alert.c:alert_add_entry()"); if (debug_level & 2) { fprintf(stderr,"alert_add_entry\n"); } if (strlen(entry->title) == 0) { if (debug_level & 2) { fprintf(stderr,"alert_add_entry: Empty title!\n"); } clear_dangerous(); return(NULL); } // Skip NWS_SOLAR and -NoActivationExpected alerts, they don't // interest us. if ( (strcmp(entry->to, "NWS-SOLAR") == 0) || (strcmp(entry->to, "NWS_SOLAR") == 0) ) { if (debug_level & 2) { fprintf(stderr,"NWS-SOLAR, skipping\n"); } clear_dangerous(); return(NULL); } if (strcasecmp(entry->title, "-NoActivationExpected") == 0) { if (debug_level & 2) { fprintf(stderr,"NoActivationExpected, skipping\n"); } clear_dangerous(); return(NULL); } // Check whether this new alert has already expired. If so, // don't add it. if (entry->expiration < time(NULL)) { if (debug_level & 2) { fprintf(stderr, "Newest Alert Expired->Clearing, current: %lu, alert: %lu\n", (unsigned long)time(NULL), (unsigned long)entry->expiration ); } clear_dangerous(); return(NULL); } // Check for non-zero alert title, non-expired alert time in new // alert. if (entry->title[0] != '\0' && entry->expiration >= time(NULL)) { // Schedule a screen update 'cuz we have a new alert alert_redraw_on_update = redraw_on_new_data = 2; //WE7U set_dangerous("alert.c:add_wx_alert_to_hash()"); add_wx_alert_to_hash(entry->unique_string, entry); clear_dangerous(); return(entry); } // If we got to here, the title was empty or the alert has // already expired? Figure out why we might ever get here. if (debug_level & 2) { fprintf(stderr,"Exiting alert_add_entry() without actually adding the alert:\n"); fprintf(stderr,"%s %s %lu\n", entry->to, entry->title, (unsigned long)entry->expiration); } clear_dangerous(); return(NULL); } // alert_active() // // Here's where we get rid of expired alerts in the list. Called // from alert_display_request(), alert_on_screen(), // and alert_build_list() functions. Also called from // maps.c:load_alert_maps() function. // // Returns the alert level. // // Alert Match Levels: // 0 = ? // 1 = R // 2 = Y // 3 = B // 4 = T // 5 = G // 6 = C // int alert_active(alert_entry *alert, alert_match_level UNUSED (match_level) ) { alert_entry *a_ptr; char l_list[] = {"?RYBTGC"}; int level = 0; time_t now; if (strlen(alert->title) == 0) { if (debug_level & 2) { fprintf(stderr,"alert_active:NULL\n"); } return(0); } if (debug_level & 2) { fprintf(stderr,"alert_active:%s\n",alert->title); } (void)time(&now); // if ((a_ptr = alert_match(alert, match_level))) { if ((a_ptr = get_wx_alert_from_hash(alert->unique_string))) { if (a_ptr->expiration >= now) { for (level = 0; a_ptr->alert_level != l_list[level] && level < (int)sizeof(l_list); level++) { //do nothing } } else if (a_ptr->expiration < (now - 3600)) { // More than an hour past the expiration, a_ptr->title[0] = '\0'; // so delete it from list by clearing // out the title. //WE7U // Schedule an update 'cuz we need to delete an expired // alert from the list. alert_redraw_on_update = redraw_on_new_data = 2; } else if (a_ptr->flags[on_screen] == '?') { // Expired between 1sec and 1hr and found '?' a_ptr->flags[on_screen] = '-'; // Schedule a screen update 'cuz we have an expired alert alert_redraw_on_update = redraw_on_new_data = 2; } } return (level); } // alert_display_request() // // Function which checks whether an alert should be displayed. // Called from maps.c:load_alert_maps() function. // int alert_display_request(void) { // int i; int alert_count; static int last_alert_count; if (debug_level & 2) { fprintf(stderr,"alert_display_request\n"); } //WE7U if (wx_alert_hash) { alert_count = hashtable_count(wx_alert_hash); } else { return((int)FALSE); } // If we found any, return TRUE. if (alert_count != last_alert_count) { last_alert_count = alert_count; return ((int)TRUE); } return ((int)FALSE); } // alert_list_count int alert_list_count(void) { int count = 0; if (wx_alert_hash) { return(hashtable_count(wx_alert_hash)); } else { return count; } } // alert_on_screen() // // Returns a count of active weather alerts in the list which are // within our viewport. // Called from main.c:UpdateTime() function. Used for sounding // alarm if a new weather alert appears on screen. // int alert_on_screen(void) { // int i; int alert_count = 0; struct hashtable_itr *iterator; alert_entry *temp; if (debug_level & 2) { fprintf(stderr,"alert_on_screen\n"); } //WE7U iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { if (alert_active(temp, ALERT_ALL) && temp->flags[on_screen] == 'Y') { alert_count++; } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 3\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return (alert_count); } // alert_build_list() // // This function builds alert_entry structs from message entries that // contain NWS alert messages. // // Called from alert_data_add() function. // // // Here's how Xastir breaks down an alert into an alert struct: // // SFONPW>APRS::NWS-ADVIS:191700z,WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // |----| |-------| |-----| |--| |-----| |-----| |-| // | | | | | | | // from to | | title title issue_date // | alert_tag // activity (expiration) // // // The code should also handle the case where the packet looks like // this (same except no expiration date): // // SFONPW>APRS::NWS-ADVIS:WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // // We also have compressed NWS alerts, signified by NWS_ADVIS // (underline instead of dash). Note that Pete Loveall, AE5PL, is // also sending out alerts and sending the "compressed" zone format // with "NWS-" which is different than how Dale Huguley was sending // them out. Pete's change is to support Kenwood radios. // // // Expiration is then computed from the activity field. Alert_level // is computed from "to" and/or "alert_tag". There can be up to // five titles in this original format. // // Here are some real examples captured over the 'net (may be quite old): // // TAEFFS>APRS::NWS-ADVIS:181830z,FLOOD,FL_C013,FL_C037,FL_C045,FL_C077, {HHEAA // ICTFFS>APRS::NWS-ADVIS:180200z,FLOOD,KS_C035, {HEtAA // JANFFS>APRS::NWS-ADVIS:180200z,FLOOD,MS_C049,MS_C079,MS_C089,MS_C099,MS_C121, {HEvAA // DSMFFS>APRS::NWS-ADVIS:180500z,FLOOD,IA_Z086, {HHGAA // EAXFFS>APRS::NWS-ADVIS:180500z,FLOOD,MO_Z023,MO_Z024,MO_Z028,MO_Z030,MO_Z031, {HHIAA // SECIND>APRS::NWS-SOLAR:Flx134 A004 BK0001232. PlnK0000232.Ep............Ee........ {HLaAA // SHVFFS>APRS::NWS-ADVIS:181800z,FLOOD,TX_C005,TX_C073,TX_C347,TX_C365,TX_C401, {HF2AA // FWDFFS>APRS::NWS-ADVIS:180200z,FLOOD,TX_C379,TX_C467, {HF5AA // LCHFFS>APRS::NWS-ADVIS:180400z,FLOOD,LA_C003,LA_C079, {HIdAA // GIDFFS>APRS::NWS-ADVIS:180200z,FLOOD,NE_C125, {H2uAA // FWDSWO>APRS::NWS-ADVIS:181100z,SKY,CW_AFWD, -NO Activation Expected {HLqAA // BGMWSW>APRS::NWS-ADVIS:180500z,WINTER_WEATHER,NY_Z015,NY_Z016,NY_Z017,NY_Z022,NY_Z023, {HKYAA // AMAWSW>APRS::NWS-WARN :180400z,WINTER_STORM,OK_Z001,OK_Z002,TX_Z001,TX_Z002,TX_Z003, {HLGBA // // New compressed-mode weather alert packets: // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ003>007-012>016-021>025-030>034-037>047-052>057-062>069{LLSAA // // or perhaps (leading zeroes removed): // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ3>7-12>16-21>25-30>34-37>47-52>57-62>69{LLSAA // // This one's real: // DVNFFS>APRS,qAO,WXSVR::NWS_ADVIS:022300z,FLOOD,IAC57-95-103-111-115-163-171-ILC1-67-71-131-MOC45 {2FsAA // // The trick is to step thru the data base contained in the // shapefiles to determine what areas to light up. In the above // example read ">" as "thru" and "-" as "and". // // // RIWWSW>APRS::NWS-WARN :191800z,WINTER_STORM,WY_Z014, GREEN MOUNTAINS {JBNBA // RIWWSW>APRS::SKYRIW :WINTER STORM WARNING CONTINUING TODAY {JBNBB // RIWWSW>APRS::SKYRIW :THROUGH SATURDAY {JBNBC // // // We'll create and fill in "entry", then copy various "titles" into // is such as "ID_C001", then insert that alert into the system. // // // VK2XJG - November 2011: // Here are some examples of strings from the new WXSVR-AU for the Aussie Bureau of Meteorology (BOM) alerts: // // NECMWW>APRS::BOM_WARN :141300z,WIND,TAS_MW002>003-005>007-009 {D55AG // YKPMWW>APRS::BOM_ADVIS:131330z,WIND,SA_MW005 {D5aAA // // For the BOM alerts note that the STATE portion of the zone can be two or three characters - valid state // prefixes are "NSW,VIC,QLD,TAS,NT,WA,SA". The two characters following the underscore denote the shapefile to use // These will be one of "CW,MW,PW,FW or ME". // // WXSVR-AU also does NOT strip leading zeros from the zone strings, however the existing NWS code allows for this, so // it should be supported if WXSVR-AU strips the zeros in the future. // // // #define TITLE_SIZE 64 void alert_build_list(Message *fill) { alert_entry entry, *list_ptr; char title[5][TITLE_SIZE+1]; // Storage place for zone/county titles int ii, jj; char *ptr; DataRow *p_station; int compressed_wx_packet = 0; char uncompressed_wx[10000]; struct hashtable_itr *iterator; int tmp_size; //fprintf(stderr,"Message_line:%s\n",fill->message_line); if (debug_level & 2) { fprintf(stderr,"alert_build_list:%s>%s:%s\n", fill->from_call_sign, fill->call_sign, fill->message_line); } // Empty this string first uncompressed_wx[0] = uncompressed_wx[1] = '\0'; // Check for "SKY" text in the "call_sign" field. if (strncmp(fill->call_sign,"SKY",3) == 0) { // Special handling for SKY messages only. if (debug_level & 2) { fprintf(stderr,"Sky Message: %s\n",fill->message_line); } // Find a matching alert_record, check whether or not it is // expired. If not, add this additional text into the // "desc[0123]" fields, in order. Check that the // FROM callsign and the first four chars after the curly // brace match. The next character specifies which message // block to fill in. In order they should be: // // B = "desc0" // C = "desc1" // D = "desc2" // E = "desc3". // // A matching alert record would have the same "from" field // and the first four characters of the "seq" field would // match. // // Need to make this SKY data expire from the message list // somehow? // // Remember to blank out these fields when we expire an // alert. Check that all other fields are cleared in this // case as well. // // Run through the alert list looking for a match to the // FROM and first four chars of SEQ //WE7U iterator = create_wx_alert_iterator(); for (list_ptr = get_next_wx_alert(iterator); iterator != NULL && list_ptr; list_ptr = get_next_wx_alert(iterator)) { if ( (strcasecmp(list_ptr->from, fill->from_call_sign) == 0) && ( strncmp(list_ptr->seq,fill->seq,4) == 0 ) ) { if (debug_level & 2) { fprintf(stderr,"%s:Found a matching alert to a SKY message:\t",list_ptr->seq); } switch (fill->seq[4]) { case 'B': tmp_size = sizeof(list_ptr->desc0); memcpy(list_ptr->desc0, fill->message_line, tmp_size); list_ptr->desc0[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc0: %s\n",fill->message_line); } break; case 'C': tmp_size = sizeof(list_ptr->desc1); memcpy(list_ptr->desc1, fill->message_line, tmp_size); list_ptr->desc1[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc1: %s\n",fill->message_line); } break; case 'D': tmp_size = sizeof(list_ptr->desc2); memcpy(list_ptr->desc2, fill->message_line, tmp_size); list_ptr->desc2[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc2: %s\n",fill->message_line); } break; case 'E': default: tmp_size = sizeof(list_ptr->desc3); memcpy(list_ptr->desc3, fill->message_line, tmp_size); list_ptr->desc3[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc3: %s\n",fill->message_line); } break; } } } if (debug_level & 2) { fprintf(stderr,"alert_build_list return 1\n"); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator a4\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } if (debug_level & 2) { fprintf(stderr,"1\n"); } if (fill->active == RECORD_ACTIVE) { int ignore_title = 0; #define MAX_SUB_ALERTS 5000 char *title_ptr[MAX_SUB_ALERTS]; int ret; if (debug_level & 2) { fprintf(stderr,"2\n"); } memset(&entry, 0, sizeof(entry)); // flags[0] specifies whether it's onscreen or not memset(entry.flags, (int)'?', sizeof(entry.flags)); // flags[source] specifies source of the alert DATA_VIA_TNC or // DATA_VIA_LOCAL entry.flags[source] = fill->heard_via_tnc; p_station = NULL; if (search_station_name(&p_station,fill->from_call_sign,1)) { entry.flags[source] = p_station->data_via; } // Zero the title strings. We can have up to five alerts in // a non-compressed weather alert. title[0][0] = '\0'; title[1][0] = '\0'; title[2][0] = '\0'; title[3][0] = '\0'; title[4][0] = '\0'; // This fills in the zone numbers (title) for uncompressed // alerts with up to five alerts per message. This doesn't // handle filling in the title for compressed alerts though. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%32[^,],%32[^,],%32[^,],%32[^,],%32[^,]", entry.activity, // 191700z entry.alert_tag, // WIND &title[0][0], // CA_Z007 &title[1][0], // ... &title[2][0], // ... &title[3][0], // ... &title[4][0]); // ... if (ret < 3) { fprintf(stderr,"sscanf parsed %d values in alert.c (3-7 ok) %s->%s: %s\n", ret, fill->from_call_sign, fill->call_sign, fill->message_line); } // Force a termination for each entry.activity[20] = '\0'; entry.alert_tag[20] = '\0'; title[0][TITLE_SIZE] = '\0'; title[1][TITLE_SIZE] = '\0'; title[2][TITLE_SIZE] = '\0'; title[3][TITLE_SIZE] = '\0'; title[4][TITLE_SIZE] = '\0'; // Check for "NWS_" in the call_sign field. Underline // signifies compressed alert format. Dash signifies // non-compressed format. // K2DLS 08/25/17 // Also check for NWS- where title[0] does not contain // an underscore. This is to identify AE5PL's compressed // alerts in uncompressed clothing. if ((strncmp(fill->call_sign,"NWS_",4) == 0) | ((strncmp(fill->call_sign,"NWS-",4) == 0) & (strstr(title[0], "_") == NULL))) { char compressed_wx[512]; char *ptr; ///////////////////////////////////////////////////////////////////// // Compressed weather alert special code ///////////////////////////////////////////////////////////////////// compressed_wx_packet++; // Set the flag //fprintf(stderr, "Found compressed alert packet via NWS_!\n"); //fprintf(stderr,"Compressed Weather Alert:%s\n",fill->message_line); //fprintf(stderr,"Compressed alerts are not fully implemented yet.\n"); // Create a new weather alert for each of these and then // call this function on each one? Seems like it might // work fine if we watch out for global variables. // Another method would be to create an incoming message // for each one and add it to the message queue, or just // a really long new message and add it to the queue, // in which case we'd exit from this routine as soon as // it was submitted. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%255[^, ]", entry.activity, entry.alert_tag, compressed_wx); // Stick the long string in here if (ret != 3) { fprintf(stderr,"sscanf parsed %d/3 values in alert.c\n", ret); compressed_wx[0] = '\0'; // Remove stale compressed alerts. compressed_wx_packet = 0; //Clear flag in error condition. } compressed_wx[255] = '\0'; //fprintf(stderr,"Line:%s\n",compressed_wx); // Snag alpha characters (should be three) at the start // of the string. Use those until we hit more alpha // characters. First two characters of each 3-letter // alpha group are the state, last character is the // zone/county/marine-zone indicator. // Need to be very careful here to validate the letters/numbers, and // to not run off the end of the string. Need more code here to do // this validation. // Scan through entire string ptr = compressed_wx; while (ptr < (compressed_wx + strlen(compressed_wx))) { char prefix[5]; char suffix[4]; char temp_suffix[4]; char ending[4]; int iterations = 0; // Snag the ALPHA portion xastir_snprintf(prefix, sizeof(prefix), "%s", ptr); ptr += 2; prefix[2] = '_'; prefix[3] = ptr[0]; prefix[4] = '\0'; // Terminate the string ptr += 1; // prefix should now contain something like "MN_Z" // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); temp_suffix[3] = '\0'; // Terminate the string if (temp_suffix[1] == '-' || temp_suffix[1] == '>') { temp_suffix[1] = '\0'; ptr += 1; } else if (temp_suffix[1] != '\0' && (temp_suffix[2] == '-' || temp_suffix[2] == '>')) { temp_suffix[2] = '\0'; ptr += 2; } else { ptr += 3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } // Make sure suffix is terminated properly suffix[3] = '\0'; // We have our first zone (of this loop) extracted! if (debug_level & 2) { fprintf(stderr,"1Zone:%s%s\n",prefix,suffix); } // Add it to our zone string. In this case we know // that the lengths of the strings we're working // with are quite short. Little danger of // overrunning our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; if (debug_level & 2) { fprintf(stderr,"uncompressed_wx:%s\n",uncompressed_wx); } // Here we keep looping until we hit another alpha // portion. We need to look at the field separator // to determine whether we have another separate // field coming up or a range to enumerate. while ( (ptr < (compressed_wx + strlen(compressed_wx))) && ( is_num_chr(ptr[1]) ) ) { iterations++; // Break out of this loop if we don't find an // alpha character fairly quickly. That way the // Xastir main thread can't hang in this loop // forever if the input string is malformed. if (iterations > 30) { break; } // Look for '>' or '-' character. If former, we // have a numeric sequence to ennumerate. If the // latter, we either have another zone number or // another prefix coming up. if (ptr[0] == '>' || ptr[0] == '<') { // Numeric zone sequence int start_number; int end_number; int kk; ptr++; // Skip past the '>' or '<' characters // Snag the NUMERIC portion. May be between // 1 and three digits long. xastir_snprintf(ending, sizeof(ending), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(ending[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(ending[1])) { ending[1] = '\0'; ptr++; } else if (!is_num_chr(ending[2])) { ending[2] = '\0'; ptr+=2; } else { ending[3] = '\0'; ptr+=3; } // ending should now contain something like // "046" or "35" or "2" if (debug_level & 2) { fprintf(stderr,"Ending:%s\n",ending); } start_number = (int)atoi(suffix); end_number = (int)atoi(ending); for ( kk=start_number+1; kk<=end_number; kk++) { xastir_snprintf(suffix,4,"%03d",kk); if (debug_level & 2) { fprintf(stderr,"2Zone:%s%s\n",prefix,suffix); } // And another zone... Ennumerate // through the sequence, adding each // new zone to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } } // Wasn't a '>' character, so check for a '-' else if (ptr[0] == '-') { // New zone number, not a numeric sequence. ptr++; // Skip past the '-' character if ( is_num_chr(ptr[0]) ) { // Found another number. Use the prefix // stored from last time. // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(temp_suffix[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(temp_suffix[1])) { temp_suffix[1] = '\0'; ptr++; } else if (!is_num_chr(temp_suffix[2])) { temp_suffix[2] = '\0'; ptr+=2; } else { temp_suffix[3] = '\0'; ptr+=3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } if (debug_level & 2) { fprintf(stderr,"3Zone:%s%s\n",prefix,suffix); } // And another zone... // Add it to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } else { // New prefix (not a number) // Start at the top of the outer loop again } } } // Skip past '-' character, if any, so that we can // get to the next prefix // RZG:Added the ptr check, so we don't read a byte off the end if ( (ptr < (compressed_wx + strlen(compressed_wx))) && (ptr[0] == '-') ) { ptr++; } } if (debug_level & 2) { fprintf(stderr,"Uncompressed: %s\n", uncompressed_wx); } } ///////////////////////////////////////////////////////////////////// // End of compressed weather alert special code ///////////////////////////////////////////////////////////////////// // Australian Buerau of Meeorology alerts (BOM) // Geoff VK2XJG // Check for "BOM_" in the call_sign field. // WXSVR-AU delivers messages in this format, keeping the protocol as close to // the NWS WXSVR as possible. // Underline signifies compressed alert format. Dash signifies // non-compressed format, although this has not been implemented on the server. if ( (strncmp(fill->call_sign,"BOM_",4) == 0) || (strncmp(fill->call_sign,"BOM-",4) == 0) ) { char compressed_wx[512]; char *ptr; ///////////////////////////////////////////////////////////////////// // Compressed weather alert (BOM) special code ///////////////////////////////////////////////////////////////////// compressed_wx_packet++; // Set the flag //fprintf(stderr, "Found compressed alert packet via BOM_!\n"); //fprintf(stderr,"Compressed Weather Alert:%s\n",fill->message_line); //fprintf(stderr,"Compressed alerts are not fully implemented yet.\n"); // Create a new weather alert for each of these and then // call this function on each one? Seems like it might // work fine if we watch out for global variables. // Another method would be to create an incoming message // for each one and add it to the message queue, or just // a really long new message and add it to the queue, // in which case we'd exit from this routine as soon as // it was submitted. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%255[^, ]", entry.activity, entry.alert_tag, compressed_wx); // Stick the long string in here if (ret != 3) { fprintf(stderr,"sscanf parsed %d/3 values in alert.c\n", ret); compressed_wx[0] = '\0'; // Remove stale compressed alerts. compressed_wx_packet = 0; //Clear flag in error condition. } compressed_wx[255] = '\0'; //fprintf(stderr,"Line:%s\n",compressed_wx); // Snag alpha characters (should be five) at the start // of the string. Use those until we hit more alpha // characters. First two/three characters of each 5-letter // alpha group are the state, last two characters are the // zone/county/marine-zone indicator. // Need to be very careful here to validate the letters/numbers, and // to not run off the end of the string. Need more code here to do // this validation. // Scan through entire string ptr = compressed_wx; while (ptr < (compressed_wx + strlen(compressed_wx))) { char prefix[7]; char suffix[4]; char temp_suffix[4]; char ending[4]; int iterations = 0; // Snag the ALPHA portion xastir_snprintf(prefix, sizeof(prefix), "%s", ptr); ptr += 3; // Handle a 2 letter state abbreviation (SA/WA/NT) if (prefix[2] == '_' ) { prefix[3] = ptr[0]; prefix[5] = '\0'; // Terminate the string ptr += 3; } // All other cases are 3 letter states (NSW/VIC/TAS/QLD) else { prefix[3] = ptr[0]; prefix[6] = '\0'; // Terminate the string ptr += 3; } // prefix should now contain something like "TAS_CW" or "SA_PW" // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); temp_suffix[3] = '\0'; // Terminate the string if (temp_suffix[1] == '-' || temp_suffix[1] == '>') { temp_suffix[1] = '\0'; ptr += 1; } else if (temp_suffix[1] != '\0' && (temp_suffix[2] == '-' || temp_suffix[2] == '>')) { temp_suffix[2] = '\0'; ptr += 2; } else { ptr += 3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } // Make sure suffix is terminated properly suffix[3] = '\0'; // We have our first zone (of this loop) extracted! if (debug_level & 2) { fprintf(stderr,"1Zone:%s%s\n",prefix,suffix); } // Add it to our zone string. In this case we know // that the lengths of the strings we're working // with are quite short. Little danger of // overrunning our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; if (debug_level & 2) { fprintf(stderr,"uncompressed_wx:%s\n",uncompressed_wx); } // Here we keep looping until we hit another alpha // portion. We need to look at the field separator // to determine whether we have another separate // field coming up or a range to enumerate. while ( (ptr < (compressed_wx + strlen(compressed_wx))) && ( is_num_chr(ptr[1]) ) ) { iterations++; // Break out of this loop if we don't find an // alpha character fairly quickly. That way the // Xastir main thread can't hang in this loop // forever if the input string is malformed. if (iterations > 30) { break; } // Look for '>' or '-' character. If former, we // have a numeric sequence to ennumerate. If the // latter, we either have another zone number or // another prefix coming up. if (ptr[0] == '>' || ptr[0] == '<') { // Numeric zone sequence int start_number; int end_number; int kk; ptr++; // Skip past the '>' or '<' characters // Snag the NUMERIC portion. May be between // 1 and three digits long. xastir_snprintf(ending, sizeof(ending), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(ending[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(ending[1])) { ending[1] = '\0'; ptr++; } else if (!is_num_chr(ending[2])) { ending[2] = '\0'; ptr+=2; } else { ending[3] = '\0'; ptr+=3; } // ending should now contain something like // "046" or "35" or "2" if (debug_level & 2) { fprintf(stderr,"Ending:%s\n",ending); } start_number = (int)atoi(suffix); end_number = (int)atoi(ending); for ( kk=start_number+1; kk<=end_number; kk++) { xastir_snprintf(suffix,4,"%03d",kk); if (debug_level & 2) { fprintf(stderr,"2Zone:%s%s\n",prefix,suffix); } // And another zone... Ennumerate // through the sequence, adding each // new zone to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } } // Wasn't a '>' character, so check for a '-' else if (ptr[0] == '-') { // New zone number, not a numeric sequence. ptr++; // Skip past the '-' character if ( is_num_chr(ptr[0]) ) { // Found another number. Use the prefix // stored from last time. // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(temp_suffix[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(temp_suffix[1])) { temp_suffix[1] = '\0'; ptr++; } else if (!is_num_chr(temp_suffix[2])) { temp_suffix[2] = '\0'; ptr+=2; } else { temp_suffix[3] = '\0'; ptr+=3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } if (debug_level & 2) { fprintf(stderr,"3Zone:%s%s\n",prefix,suffix); } // And another zone... // Add it to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } else { // New prefix (not a number) // Start at the top of the outer loop again } } } // Skip past '-' character, if any, so that we can // get to the next prefix // RZG:Added the ptr check, so we don't read a byte off the end if ( (ptr < (compressed_wx + strlen(compressed_wx))) && (ptr[0] == '-') ) { ptr++; } } if (debug_level & 2) { fprintf(stderr,"Uncompressed: %s\n", uncompressed_wx); } } ///////////////////////////////////////////////////////////////////// // End of compressed weather (BOM) alert special code ///////////////////////////////////////////////////////////////////// if (debug_level & 2) { fprintf(stderr,"3\n"); } // Terminate the strings entry.activity[20] = entry.alert_tag[20] = '\0'; // If the expire time is missing, shift fields to the right // by one field. Evidently we can have an alert come across // that doesn't have an expire time. The code shuffles the // titles to the next record before fixing up the title and // alert_tag for entry. if (!isdigit((int)entry.activity[0]) && entry.activity[0] != '-') { if (title[0][0] == '\0') { // No alerts in this message } // If it's a trashed packet, we may have entries here // that are too long. Assure that we don't overwrite // the strings. for (jj = 4; jj > 0; jj--) { xastir_snprintf(&title[jj][0], TITLE_SIZE, "%s", &title[jj-1][0]); } xastir_snprintf(&title[0][0], TITLE_SIZE, "%s", entry.alert_tag); xastir_snprintf(entry.alert_tag, sizeof(entry.alert_tag), "%s", entry.activity); entry.alert_tag[20] = '\0'; // Shouldn't we clear out entry.activity in this // case??? We've determined it's not a date/time value. xastir_snprintf(entry.activity,sizeof(entry.activity),"------z"); entry.expiration = sec_now() + (24 * 60 * 60); // Add a day } else { // Compute expiration time_t from zulu time entry.expiration = time_from_aprsstring(entry.activity); } if (debug_level & 2) { fprintf(stderr,"4\n"); } // Copy the sequence (which contains issue_date_time and // message sequence) into the record. memcpy(entry.seq, fill->seq, sizeof(entry.seq)); entry.seq[sizeof(entry.seq)-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"5\n"); } // Now compute issue_date_time from the first three characters of // the sequence number: // 0-9 = 0-9 // 10-35 = A-Z // 36-61 = a-z // The 3 characters are Day/Hour/Minute of the issue date time in // zulu time. if (strlen(fill->seq) == 5) { // Looks ok so far // Could add another check to make sure that the first two // chars are a digit or a capital letter. char c; char date_time[10]; char temp[3]; date_time[0] = '\0'; for ( ii = 0; ii < 3; ii++ ) { c = fill->seq[ii]; // Snag one character if (is_num_chr(c)) { // Found numeric char temp[0] = '0'; temp[1] = c; temp[2] = '\0'; // Terminate the string } else if (c >= 'A' && c <= 'Z') { // Found upper-case letter // Need to take ord(c) - 55 to get the number char temp_string[5]; xastir_snprintf(temp_string, sizeof(temp_string), "%02d", (int)c - 55); memcpy(temp, temp_string, 2); temp[2] = '\0'; // Terminate the string } else if (c >= 'a' && c <= 'z') { // Found lower-case letter // Need to take ord(c) - 61 to get the number char temp_string[5]; xastir_snprintf(temp_string, sizeof(temp_string), "%02d", (int)c - 61); memcpy(temp, temp_string, 2); temp[2] = '\0'; // Terminate the string } strncat(date_time,temp,sizeof(date_time)-strlen(date_time)-1); // Concatenate the strings } strncat(date_time,"z",sizeof(date_time)-strlen(date_time)-1); // Add a 'z' on the end. if (debug_level & 2) { fprintf(stderr,"Seq: %s,\tIssue_time: %s\n",fill->seq,date_time); } xastir_snprintf(entry.issue_date_time, sizeof(entry.issue_date_time), "%s", date_time); //entry.issue_date_time = time_from_aprsstring(date_time); } else { xastir_snprintf(entry.issue_date_time, sizeof(entry.issue_date_time), "%s", "312359z"); } if (debug_level & 2) { fprintf(stderr,"6\n"); } /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Iterate through up to five uncompressed alerts, or // through the string of now-uncompressed "compressed" // alerts, creating an alert out of each. // if (compressed_wx_packet) { // Handle compressed packet. // Skip the first character of our uncompressed_wx // string, as it's a leading comma. Snag out each // string in turn and use that as the title for a // weather alert. // Feed &uncompressed_wx[1] to split_string to fill in // an array with the various zone names. split_string(&uncompressed_wx[1], title_ptr, MAX_SUB_ALERTS, ','); } else { // Handle non-compressed packet // We have up to five alerts to process. // Set up an array of char pointers so that we can use // the same code for either compressed or uncompressed // weather alerts. title_ptr[0] = &title[0][0]; title_ptr[1] = &title[1][0]; title_ptr[2] = &title[2][0]; title_ptr[3] = &title[3][0]; title_ptr[4] = &title[4][0]; title_ptr[5] = NULL; // Make sure we terminate } // We now have all of our titles pointed to by the title_ptr[] // array. Either type of alert can be processed identically now. // Try to create alerts out of each one. for (ii = 0; ii < MAX_SUB_ALERTS && title_ptr[ii]; ii++) { // Copy into our entry.title variable xastir_snprintf(entry.title, sizeof(entry.title), "%s", title_ptr[ii]); // Terminate title string entry.title[sizeof(entry.title)-1] = '\0'; //fprintf(stderr,"Title: %s\n",entry.title); // This one removes spaces from the title. //while ((ptr = strpbrk(entry.title, " "))) // memmove(ptr, ptr+1, strlen(ptr)+1); // Instead we should blank out the title and any // following alert titles if a space is encountered, as // we're to disregard anything after a space in the // information field. if (ignore_title) // Blank out title if flag is set { entry.title[0] = '\0'; } // If we found a space in a title, this signifies that // we hit the end of the current list of zones. if ( (ptr = strpbrk(entry.title, " ")) ) { ignore_title++; // Set flag for following titles entry.title[0] = '\0'; // Blank out title } if ((ptr = strpbrk(entry.title, "}>=!:/*+;"))) { if (debug_level & 2) { fprintf(stderr, "Warning: Weird Weather Message: %ld:%s>%s:%s!\n", (long)fill->sec_heard, fill->from_call_sign, fill->call_sign, fill->message_line); } *ptr = '\0'; } // Skip loop iterations if we don't have a title for an // entry if (entry.title[0] == '\0') { continue; } xastir_snprintf(entry.from, sizeof(entry.from), "%s", fill->from_call_sign); xastir_snprintf(entry.to, sizeof(entry.to), "%s", fill->call_sign); memcpy(entry.seq, fill->seq, sizeof(entry.seq)); entry.seq[sizeof(entry.seq)-1] = '\0'; // Terminate string // NWS_ADVIS or NWS_CANCL normally appear in the "to" // field. ADVIS can appear in the alert_tag field on a // CANCL message though, and we want CANCL to have // priority. if (strstr(entry.alert_tag, "CANCL") || strstr(entry.to, "CANCL")) { entry.alert_level = 'C'; } else if (!strncmp(entry.alert_tag, "TEST", 4) || strstr(entry.to, "TEST")) { entry.alert_level = 'T'; } else if (strstr(entry.alert_tag, "WARN") || strstr(entry.to, "WARN")) { entry.alert_level = 'R'; } else if (strstr(entry.alert_tag, "CIVIL") || strstr(entry.to, "CIVIL")) { entry.alert_level = 'R'; } else if (strstr(entry.alert_tag, "WATCH") || strstr(entry.to, "WATCH")) { entry.alert_level = 'Y'; } else if (strstr(entry.alert_tag, "ADVIS") || strstr(entry.to, "ADVIS")) { entry.alert_level = 'B'; } else { entry.alert_level = 'G'; } // Kludge for fire zones if (!strncmp(entry.alert_tag,"RED_FLAG",8)) { // Replace "Z" in the zone field with "F" if (entry.title[3] == 'Z') { entry.title[3] = 'F'; } } // Look for a similar alert // We need some improvements here. We compare these fields: // // from SFONPW SFONPW // to NWS-ADVIS NWS-CANCL // alert_tag WIND WIND_ADVIS_CANCEL // title CA_Z007 CA_Z007 // // Of these, "from" and "title" should remain the same between an // alert and a cancelled alert. "to" and "alert_tag" change. Since // we're comparing all four fields, the cancels don't match any // existing alerts. //WE7U // Fill in the unique_string variable. We need this for // our hash code. alert_fill_unique_string(&entry); if ((list_ptr = get_wx_alert_from_hash(entry.unique_string))) { //fprintf(stderr,"alert_build_list: found match: %s\n",entry.unique_string); // We found a match! We probably need to copy some more data across // between the records: seq, alert_tag, alert_level, from, to, // issue_date_time, expiration? // If it's a CANCL or CANCEL, we need to make sure the cancel // packet's information is kept and the other's info is tossed, so // that the alert doesn't get drawn anymore. // If we're not trying to replace a cancelled alert with // a new non-cancelled alert, go ahead and copy the // fields across. if ( (list_ptr->alert_level != 'C') // Stored alert is _not_ a CANCEL || (entry.alert_level == 'C') ) { // Or new one _is_ a CANCEL list_ptr->expiration = entry.expiration; xastir_snprintf(list_ptr->activity, sizeof(list_ptr->activity), "%s", entry.activity); xastir_snprintf(list_ptr->alert_tag, sizeof(list_ptr->alert_tag), "%s", entry.alert_tag); list_ptr->alert_level = entry.alert_level; xastir_snprintf(list_ptr->seq, sizeof(list_ptr->seq), "%s", entry.seq); xastir_snprintf(list_ptr->from, sizeof(list_ptr->from), "%s", entry.from); xastir_snprintf(list_ptr->to, sizeof(list_ptr->to), "%s", entry.to); xastir_snprintf(list_ptr->issue_date_time, sizeof(list_ptr->issue_date_time), "%s", entry.issue_date_time); } else { // Don't copy the info across, as we'd be making a // cancelled alert active again if we did. } } else { // No similar alert, add a new one to the list entry.index = -1; // Haven't found it in a file yet (void)alert_add_entry(&entry); } if (alert_active(&entry, ALERT_ALL)) { // Empty "if" body here????? LCLINT caught this. } } // End of for loop // Signify that we're done processing the NWS message fill->active = RECORD_CLOSED; } if (debug_level & 2) { fprintf(stderr,"alert_build_list return 2\n"); } } Xastir-Release-2.2.2/src/alert.h000066400000000000000000000050071501463444000164170ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_ALERT_H #define __XASTIR_ALERT_H #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "database.h" //#include "maps.h" // How many alerts we add storage for each time we're short. #define ALERT_COUNT_INCREMENT 200 typedef enum { ALERT_TITLE, ALERT_TAG, ALERT_TO, ALERT_FROM } alert_match_level; #define ALERT_ALL ALERT_FROM enum flag_list { on_screen, source, max_flag=16 }; typedef struct { char unique_string[50]; double top_boundary, left_boundary, bottom_boundary, right_boundary; time_t expiration; // In local time (secs since epoch) char activity[21]; char alert_tag[21]; char title[33]; char alert_level; char from[10]; char to[10]; /* referenced flags 0 - on screen 1 - source */ char flags[max_flag]; char filename[64]; int index; // Index into shapefile char seq[10]; char issue_date_time[10]; char desc0[68]; // Space for additional text. char desc1[68]; // Spec allows 67 chars per char desc2[68]; // message. char desc3[68]; // } alert_entry; extern void alert_print_list(void); extern int alert_active(alert_entry *alert, alert_match_level match_level); extern int alert_display_request(void); extern int alert_on_screen(void); extern int alert_redraw_on_update; extern int alert_expire(int curr_sec); extern void alert_build_list(Message *fill); extern struct hashtable_itr *create_wx_alert_iterator(void); extern alert_entry *get_next_wx_alert(struct hashtable_itr *iterator); extern int alert_list_count(void); #endif /* __XASTIR_ALERT_H */ Xastir-Release-2.2.2/src/awk.c000066400000000000000000000705701501463444000160740ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ // // These functions allocate new memory: // ------------------------------------ // awk_new_symtab // awk_declare_sym // awk_compile_action // awk_new_rule // awk_new_program // awk_load_program_file // awk_load_program_array // // These functions free memory: // ---------------------------- // awk_free_symtab // awk_free_action // awk_free_rule // awk_free_program // awk_uncompile_program (indirectly) // /* * This is a library of Awk-like functions to facilitate, for example, * canonicalizing DBF attributes for shapefiles into internal Xastir * values when rendering shapefile maps, or rewriting labels * (e.g. callsigns into tactical calls), etc. * * Uses Philip Hazel's Perl-compatible regular expression library (pcre). * See www.pcre.org. * * Alan Crosswell, n2ygk@weca.org * * TODO * permit embedded ;#} inside string assignment (balance delims) * implement \t, \n, \0[x]nn etc. * instantiate new symbols instead of ignoring them? */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #include #include "awk.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" #define min(a,b) ((a)<(b)?(a):(b)) /* * Symbol table * * Symbols $0-$9 are set by the results of the pcre pattern match. * Other symbols are declared by the caller and bound to variables * in the caller's program. Make sure they are still in scope when * the pattern matcher is invoked! * * This assumes a very small symbol table, so it is searched linearly. * No fancy hash table lookups are needed. * XXX YES THEY ARE! */ #define MAXSUBS 10 /* $0 thru $9 should be plenty */ /* * awk_new_symtab: alloc a symbol table with $0-$9 pre-declared. */ awk_symtab *awk_new_symtab(void) { awk_symtab *n = calloc(1,sizeof(awk_symtab)); static char sym[MAXSUBS][2]; int i; if (!n) { fprintf(stderr, "Couldn't allocate memory in awk_new_symtab()\n"); return(NULL); } for (i = 0; i < MAXSUBS; i++) { sym[i][0] = i+'0'; sym[i][1] = '\0'; awk_declare_sym(n,sym[i],STRING,NULL,0); /* just reserve the name */ } return n; } void awk_free_symtab(awk_symtab *s) { int i; for (i = 0; i < AWK_SYMTAB_HASH_SIZE; i++) { awk_symbol *p,*x; for (x = s->hash[i]; x ; x = p) { p = x->next_sym; free(x); } } } /* * awk_declare_sym: declare a symbol and bind to storage for its value. */ int awk_declare_sym(awk_symtab *this, const char *name, enum awk_symtype type, const void *val, const int size) { awk_symbol *s = calloc(1,sizeof(awk_symbol)); awk_symbol *p; u_int i; if (!s) { fprintf(stderr, "Couldn't allocate memory in awk_declare_sym()\n"); return -1; } s->name = name; s->namelen = strlen(name); s->type = type; s->val = (void *)val; s->size = size; s->len = 0; i = AWK_SYM_HASH(s->name,s->namelen); if ((p = this->hash[i]) != NULL) { s->next_sym = p; /* insert at top of bucket */ } this->hash[i] = s; /* make (new) top of bucket */ return 0; } /* * awk_find_sym: search symtab for symbol */ awk_symbol *awk_find_sym(awk_symtab *this, const char *name, const int len) { awk_symbol *s; char c; // Create holding spot for first character in order to speed up // the loop below. Note that "toupper()" is very slow on some // systems so we took it out of this function to speed things // up. We evidently don't need case insensitive behavior here // anyway. // c = name[0]; // Check through the hash // for (s = this->hash[AWK_SYM_HASH(name,len)]; s; s = s->next_sym) { // Check length first (fast operation) if (s->namelen == len) { // Check first char next (fast operation) if (s->name[0] == c) { // Ok so far, test the entire string (slow // operation, case sensitive) if (len == 1) { return s; } if (len > 1 && strncmp(s->name+1,name+1,len-1) == 0) { return s; } } } } return NULL; } /* * awk_set_sym: set a symbol's value (writes into bound storage). * Returns -1 if it was unable to (symbol not found). */ /* int awk_set_sym(awk_symbol *s, const char *val, const int len) { int l = len + 1; int minlen = min(s->size-1,l); if (!s) { return -1; } switch(s->type) { case STRING: if (minlen > 0) { // Change this to an xastir_snprintf() function if we // need to use this awk_set_sym() function later. // strncpy won't null-terminate the string if there's no // '\0' in the first minlen bytes. strncpy(s->val,val,minlen); s->len = l - 1; } break; case INT: *((int *)s->val) = atoi(val); s->len = sizeof(int); break; case FLOAT: *((double *)s->val) = atof(val); s->len = sizeof(double); break; default: return -1; break; } return 0; } */ /* * awk_get_sym: copy (and cast) symbol's value into supplied string buffer */ int awk_get_sym(awk_symbol *s, /* symbol */ char *store, /* store result here */ int size, /* sizeof(*store) */ int *len) { /* store length here */ int minlen; char cbuf[128]; /* conversion buffer for int/float */ int cbl; if (!s) { return -1; } *store = '\0'; *len = 0; switch(s->type) { case STRING: if (s->len > 0) { minlen = min(s->len,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", (char *)(s->val)); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; case INT: if (s->len > 0) { sprintf(cbuf,"%d",*((int *)s->val)); cbl = strlen(cbuf); minlen = min(cbl,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", cbuf); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; case FLOAT: if (s->len > 0) { sprintf(cbuf,"%f",*((double *)s->val)); cbl = strlen(cbuf); minlen = min(cbl,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", cbuf); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; } return 0; } /* * Action compilation and interpretation. * * Action grammar is: * := "=" value * := "next" | "skip" (next skips to next field; skip skips to next * record.) * := | * := ";" | * := * * It's a trivial grammar so no need for yacc/bison. */ /* * awk_compile_stmt: "Compiles" a single action statement. */ int awk_compile_stmt(awk_symtab *this, awk_action *p, const char *stmt, int len) { const char *s = stmt, *op, *ep; while (isspace((int)*s)) { /* clean up leading white space */ ++s; --len; } ep = &s[len]; if ((op = strchr(s,'=')) != NULL) { /* it's either an assignment */ const char *val = op+1; while (isspace((int)*val)) { val++; len--; } --op; while (isspace((int)*op) && op>s) { op--; } p->opcode = ASSIGN; p->dest = awk_find_sym(this,s,(op-s+1)); if (!p->dest) { return -1; } p->expr = val; p->exprlen = (ep-val); } else { /* or the "next" keyword */ const char *r; for (r=&s[len-1]; isspace((int)*r); r--,len--) { /* trim trailing white space */ } if (len == 4 && strncmp(s,"next",4) == 0) { p->opcode = NEXT; } else if (len == 4 && strncmp(s,"skip",4) == 0) { p->opcode = SKIP; } else { /* failed to parse */ return -1; } } return 0; } /* * awk_compile_action: Break the action up into stmts and compile them * and link them together. */ awk_action *awk_compile_action(awk_symtab *this, const char *act) { awk_action *p, *first = calloc(1,sizeof(awk_action)); const char *cs,*ns; /* current, next stmt */ p = first; if (!p) { fprintf(stderr,"Couldn't allocate memory in awk_compile_action()\n"); return NULL; } for (cs = ns = act; ns && *ns; cs = (*ns==';')?ns+1:ns) { ns = strchr(cs,';'); if (!ns) /* end of string */ { ns = &cs[strlen(cs)]; } if (awk_compile_stmt(this,p,cs,(ns-cs)) >= 0) { p->next_act = calloc(1,sizeof(awk_action)); if (!p->next_act) { fprintf(stderr,"Couldn't allocate memoryin awk_compile_action (2)\n"); } p = p->next_act; } } return first; } /* * awk_free_action: Free the compiled action */ void awk_free_action(awk_action *a) { while (a) { awk_action *p = a; a = p->next_act; free(p); } } /* * awk_eval_expr: expand $vars into dest and do type conversions as * needed. For strings, just write directly into dest->val. For * ints/floats, write to a temp buffer and then atoi() or atof(). */ void awk_eval_expr(awk_symtab *this, awk_symbol *dest, const char *expr, int exprlen) { int i,dmax,dl,newlen; char c,delim; char *dp; const char *symname; int done; char tbuf[128]; awk_symbol *src; if (dest && expr) { if (dest->type == STRING) { dp = dest->val; /* just expand directly to result buffer */ dmax = dest->size; } else { dp = tbuf; /* use temp buffer */ dmax = sizeof(tbuf); } for (done = 0, i = 0, dl = 0; !done && i < dmax && exprlen > 0; i++) { switch (c = *expr) { case '"': case '\'': /* trim off string delims */ ++expr; --exprlen; if (expr[exprlen-1] == c) /* look for matching close delim */ { --exprlen; } break; case '$': /* $... look for variable substitution */ if (--exprlen < 0) { done = 1; break; } c = *++expr; /* what's after the $? */ switch (c) { case '{': /* ${var}... currently broken (see TODO) */ delim='}'; ++expr; /* skip the open delim */ --exprlen; break; case '(': /* $(var)... */ delim=')'; ++expr; --exprlen; break; default: /* $var ... */ delim='\0'; break; } /* now search for the var name using closing delim */ symname = expr; if (delim == '\0') { /* no close delim */ while (!isspace((int)*expr) && !ispunct((int)*expr) && exprlen > 0) { ++expr; --exprlen; } } else { /* search for close delim */ while (*expr != delim && exprlen > 0) { ++expr; --exprlen; } } src = awk_find_sym(this,symname,(expr-symname)); if (delim) { /* gotta skip over the close delim */ ++expr; --exprlen; } /* make sure src and dest of string copy don't overlap */ if (src && src->type == STRING && dp >= (char *)src->val && dp <= &((char *)src->val)[src->size]) { char *sp; int free_it = 0; if ((int)sizeof(tbuf) >= src->size) { /* tbuf big enuf */ sp = tbuf; } else { /* tbuf too small */ free_it++; sp = malloc(src->size); if (!sp) { /* oh well! */ fprintf(stderr,"Couldn't allocate memory in awk_eval_expr()\n"); break; } } awk_get_sym(src,sp,src->size,&newlen); bcopy(sp,dp,newlen); /* now copy it in */ // We only want to free it if we malloc'ed it. if (free_it) { free(sp); } } else { awk_get_sym(src,dp,(dmax-dl),&newlen); } dl += newlen; dp += newlen; break; case '\\': /* \... quote next char */ /* XXX TODO: implement \n,\t,\0[x].. etc. */ if (--exprlen < 0) { done = 1; } else { if (dl < dmax) { *dp++ = *expr++; /* copy the quoted char */ ++dl; } } break; default: /* just copy the character */ if (--exprlen < 0) { done = 1; } else { if (dl < dmax) { *dp++ = *expr++; /* copy the char */ ++dl; } } break; } /* end switch (*expr) */ } /* end for loop */ *dp = '\0'; /* null terminate the string */ switch(dest->type) { case INT: if (dest->size >= (int)sizeof(int)) { *((int *)dest->val) = atoi(tbuf); dest->len = sizeof(int); } break; case FLOAT: if (dest->size >= (int)sizeof(double)) { *((double *)dest->val) = atof(tbuf); dest->len = sizeof(double); } break; case STRING: /* already filled val in */ dest->len = dl; /* just update len */ break; default: break; } } } /* * awk_exec_action: interpret the compiled action. */ int awk_exec_action(awk_symtab *this, const awk_action *code) { const awk_action *p; int done = 0; for (p = code; p && !done; p = p->next_act) { switch (p->opcode) { case NEXT: done = 1; break; case SKIP: done = 2; break; case ASSIGN: awk_eval_expr(this,p->dest,p->expr,p->exprlen); break; case NOOP: break; default: break; } } return done; } /* * Rules consists of pcre patterns and actions. A program is * the collection of rules to apply as a group. */ /* * awk_new_rule: alloc a rule */ awk_rule *awk_new_rule(void) { awk_rule *n = calloc(1,sizeof(awk_rule)); if (!n) { fprintf(stderr,"Couldn't allocate memory in awk_new_rule()\n"); } return n; } void awk_free_rule(awk_rule *r) { if (r) { if (r->flags&AR_MALLOC) { if (r->act) { free((char *)r->act); } if (r->pattern) { free((char *)r->pattern); } if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } if (r->re) { #ifdef XASTIR_LEGACY_PCRE pcre_free(r->re); #else pcre2_code_free(r->re); #endif } #ifdef XASTIR_LEGACY_PCRE if (r->pe) { pcre_free(r->pe); } #endif } if (r->code) { awk_free_action(r->code); } free(r); } } /* * awk_new_program: alloc a program */ awk_program *awk_new_program(void) { awk_program *n = calloc(1,sizeof(awk_program)); if (!n) { fprintf(stderr,"Couldn't allocate memory in awk_new_program()\n"); } return n; } void awk_free_program(awk_program *rs) { awk_rule *r; if (rs) { for (r = rs->head; r; ) { awk_rule *x = r; r = r->next_rule; awk_free_rule(x); } free(rs); } } /* * awk_add_rule: add a rule to a program */ void awk_add_rule(awk_program *this, awk_rule *r) { if (!this) { return; } if (!this->last) { this->head = this->last = r; r->next_rule = NULL; } else { this->last->next_rule = r; this->last = r; } } /* * awk_load_program_array: load program from an array of rules. Use this * to load a program from a statically declared array (see test main * program for an example). */ awk_program *awk_load_program_array(awk_rule rules[], /* rules array */ int nrules) { /* size of array */ awk_program *n = awk_new_program(); awk_rule *r; if (!n) { return NULL; } for (r = rules; r < &rules[nrules]; r++) { awk_add_rule(n,r); } return n; } static void garbage(const char *file, int line, const char *buf, const char *cp) { fprintf(stderr,"%s:%d: parse error:\n",file,line); fputs(buf,stderr); fputc('\n',stderr); while (cp-- > buf) { fputc(' ',stderr); } fputs("^\n\n",stderr); } /* * awk_load_program_file: load program from a file. * * File syntax is a simplified version of awk: * * {action} * /pattern/ {action} * BEGIN {action} * BEGIN_RECORD {action} * END_RECORD {action} * END {action} * # comments... * (blank lines) * * Note that action can continue onto subsequent lines. */ awk_program *awk_load_program_file(const char *file) { /* rules filename */ awk_program *n = awk_new_program(); awk_rule *r; FILE *f = fopen(file,"r"); char in[1024]; int line = 0; if (!f) { if (n) { awk_free_program(n); } return NULL; } if (!n) { return NULL; } while (fgets(in,sizeof(in),f)) { char *cp = in, *p; int l = strlen(in); ++line; if (in[l-1] == '\n') { in[--l] = '\0'; } while (isspace((int)*cp)) { ++cp; } switch(*cp) { case '\0': /* empty line */ continue; case '#': /* comment line */ continue; case '/': /* begin regexp */ r = awk_new_rule(); r->ruletype = REGEXP; p = ++cp;; /* now points at pattern */ more: while (*cp && *cp != '/') { ++cp; /* find end of pattern */ } if (cp > in && cp[-1] == '\\') { /* '/' quoted */ ++cp; goto more; /* so keep going */ } if (*cp != '\0') /* zap end of pattern */ { *cp++ = '\0'; } r->pattern = strdup(p); break; case 'B': /* BEGIN? */ if (strncmp(cp,"BEGIN_RECORD",12) == 0) { r = awk_new_rule(); r->ruletype = BEGIN_REC; cp += 12; /* strlen("BEGIN_RECORD") */ } else if (strncmp(cp,"BEGIN",5) == 0) { r = awk_new_rule(); r->ruletype = BEGIN; cp += 5; /* strlen("BEGIN") */ } else { garbage(file,line,in,cp); continue; } break; case 'E': /* END? */ if (strncmp(cp,"END_RECORD",10) == 0) { r = awk_new_rule(); r->ruletype = END_REC; cp += 10; /* strlen("END_RECORD") */ } else if (strncmp(cp,"END",3) == 0) { r = awk_new_rule(); r->ruletype = END; cp += 3; /* strlen("END") */ } else { garbage(file,line,in,cp); continue; } break; default: garbage(file,line,in,cp); continue; } while (isspace((int)*cp)) { ++cp; /* skip whitespace */ } if (*cp == '{') { p = ++cp; loop: while (*cp && *cp != '}' && *cp != '#') { ++cp; } if (*cp == '\0' || *cp == '#') { /* continues on next line */ *cp++=' '; /* replace \n w/white space */ if (cp >= &in[sizeof(in)-1]) { garbage(file,line,"line too long",0); return n; } if (!fgets(cp,sizeof(in)-(cp-in),f)) { fprintf(stderr,"%s:%d: failed to parse\n",file,line); return n; } ++line; goto loop; /* keep looking for that close bracket */ } if (*cp != '\0') /* zap end of act */ { *cp++ = '\0'; } r->act = strdup(p); r->flags |= AR_MALLOC; /* make sure there's no extraneous junk on the line */ while (*cp && isspace((int)*cp)) { ++cp; } if (*cp == '#' || *cp == '\0') { awk_add_rule(n,r); } else { garbage(file,line,in,cp); continue; } } else { garbage(file,line,in,cp); continue; } } /* end while */ fclose(f); return n; } /* * awk_compile_program: Once loaded (from array or file), the program is compiled. Check for already compiled program. */ int awk_compile_program(awk_symtab *symtab, awk_program *rs) { awk_rule *r; #ifdef XASTIR_LEGACY_PCRE const char *error; int erroffset; #else int errornumber; PCRE2_SIZE erroffset; pcre2_compile_context *theCompileContext; #endif if (!rs) { return -1; } rs->symtbl = symtab; for (r = rs->head; r; r = r->next_rule) { if (r->ruletype == REGEXP) { if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } #ifdef XASTIR_LEGACY_PCRE r->tables = pcre_maketables(); /* NLS locale parse tables */ #else theCompileContext=pcre2_compile_context_create(NULL); r->tables = pcre2_maketables(NULL); /* NLS locale parse tables */ /* this always returns zero, so can ignore errornumber */ errornumber=pcre2_set_character_tables(theCompileContext,r->tables); #endif if (!r->re) { #ifdef XASTIR_LEGACY_PCRE r->re = pcre_compile(r->pattern, /* the pattern */ 0, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ r->tables); /* NLS locale character tables */ #else r->re = pcre2_compile((PCRE2_SPTR8)r->pattern, /* the pattern */ PCRE2_ZERO_TERMINATED, /* no length needed */ 0, /* default options */ &errornumber, /* for error message */ &erroffset, /* for error offset */ theCompileContext); #endif } if (!r->re) { int i; fprintf(stderr,"parse error: %s\n",r->pattern); fprintf(stderr," "); for (i = 0; i < erroffset; i++) { fputc(' ',stderr); } fprintf(stderr,"^\n"); return -1; } #ifdef XASTIR_LEGACY_PCRE if (!r->pe) { r->pe = pcre_study(r->re, 0, &error); /* optimize the regexp */ } #else pcre2_compile_context_free(theCompileContext); #endif } else if (r->ruletype == BEGIN) { rs->begin = r; } else if (r->ruletype == BEGIN_REC) { rs->begin_rec = r; } else if (r->ruletype == END_REC) { rs->end_rec = r; } else if (r->ruletype == END) { rs->end = r; } if (!r->code) { r->code = awk_compile_action(rs->symtbl,r->act); /* compile the action */ } } return 0; } /* * awk_uncompile_program: Frees the compiled program (patterns and stmts) * but keeps the program text loaded so it can be recompiled (e.g. with a * new symtbl). */ void awk_uncompile_program(awk_program *p) { awk_rule *r; if (!p) { return; } for (r = p->head; r; r = r->next_rule) { if (r->ruletype == REGEXP) { if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } r->tables = NULL; if (r->re) { #ifdef XASTIR_LEGACY_PCRE pcre_free(r->re); #else pcre2_code_free(r->re); #endif } r->re = NULL; #ifdef XASTIR_LEGACY_PCRE if (r->pe) { pcre_free(r->pe); } r->pe = NULL; #endif } if (r->code) { awk_free_action(r->code); /* free the action */ } r->code = NULL; } } /* * awk_exec_program: apply the program to the given buffer */ int awk_exec_program(awk_program *this, char *buf, int len) { int i,rc,done = 0; awk_rule *r; #ifdef XASTIR_LEGACY_PCRE int ovector[3*MAXSUBS]; #define OVECLEN (sizeof(ovector)/sizeof(ovector[0])) #else PCRE2_SIZE *ovector; #endif if (!this || !buf || len <= 0) { return 0; } for (r = this->head; r && !done ; r = r->next_rule) { if (r->ruletype == REGEXP) { #ifdef XASTIR_LEGACY_PCRE rc = pcre_exec(r->re,r->pe,buf,len,0,0,ovector,OVECLEN); #else pcre2_match_data *match_data; match_data=pcre2_match_data_create_from_pattern(r->re,NULL); rc=pcre2_match(r->re,(PCRE2_SPTR8)buf,len,0,0,match_data,NULL); if (rc >0 ) ovector=pcre2_get_ovector_pointer(match_data); #endif /* assign values to as many of $0 thru $9 as were set */ /* XXX - avoid calling awk_find_sym for these known values */ for (i = 0; rc > 0 && i < rc && i < MAXSUBS ; i++) { char symname[2]; awk_symbol *s; symname[0] = i + '0'; symname[1] = '\0'; s = awk_find_sym(this->symtbl,symname,1); s->val = &buf[ovector[2*i]]; s->len = ovector[2*i+1]-ovector[2*i]; } /* clobber the remaining $n thru $9 */ for (; i < MAXSUBS; i++) { char symname[10]; awk_symbol *s; symname[0] = i + '0'; symname[1] = '\0'; s = awk_find_sym(this->symtbl,symname,1); s->len = 0; } if (rc > 0) { done = awk_exec_action(this->symtbl,r->code); } #ifndef XASTIR_LEGACY_PCRE pcre2_match_data_free(match_data); #endif } } return done; } /* * awk_exec_begin_record: run the special BEGIN_RECORD rule, if any */ int awk_exec_begin_record(awk_program *this) { if (this && this->begin_rec) { return awk_exec_action(this->symtbl,this->begin_rec->code); } else { return 0; } } /* * awk_exec_begin: run the special BEGIN rule, if any */ int awk_exec_begin(awk_program *this) { if (this && this->begin) { return awk_exec_action(this->symtbl,this->begin->code); } else { return 0; } } /* * awk_exec_end_record: run the special END_RECORD rule, if any */ int awk_exec_end_record(awk_program *this) { if (this && this->end_rec) { return awk_exec_action(this->symtbl,this->end_rec->code); } else { return 0; } } /* * awk_exec_end: run the special END rule, if any */ int awk_exec_end(awk_program *this) { if (this && this->end) { return awk_exec_action(this->symtbl,this->end->code); } else { return 0; } } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.2/src/awk.h000066400000000000000000000126621501463444000160770ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef AWK_H #define AWK_H #ifdef XASTIR_LEGACY_PCRE #ifdef HAVE_PCRE_H #include #endif #ifdef HAVE_PCRE_PCRE_H #include #endif #else #define PCRE2_CODE_UNIT_WIDTH 8 #include #endif enum awk_symtype { STRING, INT, FLOAT }; /* the only data types */ typedef struct awk_symbol_ { /* symbol table entry */ struct awk_symbol_ *next_sym; /* linked list */ const char *name; /* name of the symbol */ int namelen; /* length of the name */ enum awk_symtype type; /* data type of symbol value */ void *val; /* storage for the value */ int size; /* size of *val */ int len; /* current length of *val */ } awk_symbol; #define AWK_SYMTAB_HASH_SIZE 0xff typedef struct awk_symtab_ { /* symbol table anchor */ awk_symbol *hash[AWK_SYMTAB_HASH_SIZE]; } awk_symtab; #define AWK_SYM_HASH(n,l) ((*n)&AWK_SYMTAB_HASH_SIZE) //#define AWK_SYM_HASH(n,l) ((n[0]+((l>1)?n[1]:0))&AWK_SYMTAB_HASH_SIZE) typedef struct awk_action_ { /* a program statement */ struct awk_action_ *next_act; enum {NOOP=0, NEXT, SKIP, ASSIGN} opcode; awk_symbol *dest; /* destination of assignment */ const char *expr; /* value setting expression */ int exprlen; /* length of expression */ } awk_action; typedef struct awk_rule_ { struct awk_rule_ *next_rule; /* linked list */ enum {BEGIN,BEGIN_REC,END_REC,END,REGEXP} ruletype; const char *pattern; /* pcre pattern string */ #ifdef XASTIR_LEGACY_PCRE const u_char *tables; /* pcre NLS tables */ pcre *re; /* pcre compiled pattern */ pcre_extra *pe; /* pcre optimized pattern */ #else const uint8_t *tables; /* pcre2 NLS tables */ pcre2_code *re; /* pcre2 compiled pattern */ void *pe; /* pcre2 doesn't use separate optimization */ #endif const char *act; /* the program string */ awk_action *code; /* compiled program */ int flags; /* some flags */ #define AR_MALLOC 0x01 /* pattern, act were malloc'd by me */ } awk_rule; typedef struct awk_program_ { /* anchor for the list of rules */ awk_symtab *symtbl; /* the symbol table for this program */ awk_rule *head; /* head of list */ awk_rule *last; /* last element */ awk_rule *begin; /* optional BEGIN rule */ awk_rule *begin_rec; /* optional BEGIN_RECORD rule */ awk_rule *end_rec; /* optional END_RECORD rule */ awk_rule *end; /* optional END rule */ } awk_program; extern awk_symtab *awk_new_symtab(void); extern void awk_free_symtab(awk_symtab *s); extern int awk_declare_sym(awk_symtab *this, const char *name, enum awk_symtype type, const void *val, const int size); extern awk_symbol *awk_find_sym(awk_symtab *this, const char *name, const int len); extern int awk_set_sym(awk_symbol *s, const char *val, const int len); extern int awk_get_sym(awk_symbol *s, char *store, int size, int *len); extern int awk_compile_stmt(awk_symtab *this, awk_action *p, const char *stmt, int len); extern awk_action *awk_compile_action(awk_symtab *this, const char *act); extern void awk_free_action(awk_action *a); extern void awk_eval_expr(awk_symtab *this, awk_symbol *dest, const char *expr, int exprlen); extern int awk_exec_action(awk_symtab *this, const awk_action *code); extern awk_rule *awk_new_rule(void); extern void awk_free_rule(awk_rule *r); extern awk_program *awk_new_program(void); extern void awk_free_program(awk_program *rs); void awk_add_rule(awk_program *this, awk_rule *r); extern awk_program *awk_load_program_array(awk_rule rules[],int nrules); extern awk_program *awk_load_program_file(const char *file); extern int awk_compile_program(awk_symtab *symtbl,awk_program *rs); extern void awk_uncompile_program(awk_program *rs); extern int awk_exec_program(awk_program *this, char *buf, int len); extern int awk_exec_begin_record(awk_program *this); extern int awk_exec_end_record(awk_program *this); extern int awk_exec_begin(awk_program *this); extern int awk_exec_end(awk_program *this); #endif /*!AWK_H*/ Xastir-Release-2.2.2/src/bulletin_gui.c000066400000000000000000000654131501463444000177740ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include #include #include "xastir.h" #include "main.h" #include "bulletin_gui.h" #include "interface.h" #include "util.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget Display_bulletins_dialog = NULL; Widget Display_bulletins_text = NULL; Widget dist_data = NULL; Widget zero_bulletin_data = NULL; static xastir_mutex display_bulletins_dialog_lock; int bulletin_range; int new_bulletin_flag = 0; int new_bulletin_count = 0; static time_t first_new_bulletin_time = 0; static time_t last_new_bulletin_time = 0; void bulletin_gui_init(void) { init_critical_section(&display_bulletins_dialog_lock); } // Function called from check_for_new_bulletins() if a new bulletin // has come in that's within our range and we have // pop_up_new_bulletins enabled. This causes the Bulletins() dialog // to come up and rescan the message database for all bulletins that // are within the radius specified. By the time this gets called // we've already waited a few seconds to try to get the posit to // come in that matches the bulletin, and have then checked the // database to make sure that the new bulletins received are still // within our range. void popup_bulletins(void) { if ( Display_bulletins_dialog == NULL ) // Dialog not up { // Bring up the dialog Bulletins( (Widget)NULL, (XtPointer)NULL, (XtPointer)NULL ); } } void bulletin_message(char *call_sign, char *tag, char *packet_message, time_t sec_heard) { char temp[200]; char temp_my_course[10]; char temp_text[30]; double distance; XmTextPosition pos, eol, eod; struct tm *tmp; time_t timehd; char time_str[20]; char *temp_ptr; timehd=sec_heard; tmp = localtime(&timehd); if ( (packet_message != NULL) && (strlen(packet_message) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 1) { fprintf(stderr,"bulletin_message: Message length too long\n"); } return; } (void)strftime(time_str,sizeof(time_str),"%b %d %H:%M",tmp); distance = distance_from_my_station(call_sign,temp_my_course); xastir_snprintf(temp, sizeof(temp), "%-9s:%-4s (%s %6.1f %s) %s\n", call_sign, &tag[3], time_str, distance, english_units ? langcode("UNIOP00004"): langcode("UNIOP00005"), packet_message); // Operands of <= have incompatible types (double, int): if ( ( ((int)distance <= bulletin_range) && (distance > 0.0) ) || (view_zero_distance_bulletins && distance == 0.0) || ( (bulletin_range == 0) && (distance > 0.0) ) ) { begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:bulletin_message" ); if ((Display_bulletins_dialog != NULL) && Display_bulletins_text != NULL) // Dialog is up { eod = XmTextGetLastPosition(Display_bulletins_text); memcpy(temp_text, temp, 15); temp_text[14] = '\0'; // Terminate string // Look for this bulletin ID. "pos" will hold the first char position if found. if (XmTextFindString(Display_bulletins_text, 0, temp_text, XmTEXT_FORWARD, &pos)) { // Found it, so now find the end-of-line for it if (XmTextFindString(Display_bulletins_text, pos, "\n", XmTEXT_FORWARD, &eol)) { eol++; } else { eol = eod; } // And replace the old bulletin with a new copy if (eol == eod) { temp[strlen(temp)-1] = '\0'; } XmTextReplace(Display_bulletins_text, pos, eol, temp); } else { for (pos = 0; strlen(temp_text) > 12 && pos < eod;) { if (XmCOPY_SUCCEEDED == XmTextGetSubstring(Display_bulletins_text, pos, 14, 30, temp_text)) { if (temp_text[0] && strncmp(temp, temp_text, 14) < 0) { break; } } else { break; } if (XmTextFindString(Display_bulletins_text, pos, "\n", XmTEXT_FORWARD, &eol)) { pos = ++eol; } else { pos = eod; } } if (pos == eod) { temp[strlen(temp)-1] = '\0'; // End-of-Data remove trailing LF if (pos > 0) // Already have text. Need to insert LF between items { memmove(&temp[1], temp, strlen(temp)); temp[0] = '\n'; } } XmTextInsert(Display_bulletins_text,pos,temp); } temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); } end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:bulletin_message" ); } } static void bulletin_line(Message *fill) { bulletin_message(fill->from_call_sign, fill->call_sign, fill->message_line, fill->sec_heard); } static void scan_bulletin_file(void) { mscan_file(MESSAGE_BULLETIN, bulletin_line); } // bulletin_data_add // // Adds the bulletin to the message database. Updates the Bulletins // dialog if it is up. Causes Bulletins dialog to pop up if the // bulletin matches certain parameters. // long temp_bulletin_record; void bulletin_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from) { int distance = -1; // Add to the message database (void)msg_data_add(call_sign, from_call, data, " ", // Need something here. Empty string no good. MESSAGE_BULLETIN, from, &temp_bulletin_record); // If we received a NEW bulletin if (temp_bulletin_record == -1L) { char temp[10]; //fprintf(stderr,"We think it's a new bulletin!\n"); // We add to the distance in order to come up with 0.0 // if the distance is not known at all (no position // found yet). distance = (int)(distance_from_my_station(from_call,temp) + 0.9999); if ( (bulletin_range == 0) || (distance <= bulletin_range && distance > 0) || (view_zero_distance_bulletins && distance == 0.0) ) { // We have a _new_ bulletin that's within our // current range setting. Note that it's also possible // to have a zero distance for the bulletin (we haven't // heard a posit from the sending station yet), then get // a posit later. if (debug_level & 1) { fprintf(stderr,"New bulletin:"); fprintf(stderr,"%05d:%9s:%c:%c:%9s:%s:%s ", distance, call_sign, type, from, from_call, data, seq); fprintf(stderr," Distance ok:%d miles",distance); } if (pop_up_new_bulletins) { //fprintf(stderr,"bulletin_data_add: popping up bulletins\n"); popup_bulletins(); if (debug_level & 1) { fprintf(stderr,"\n"); } } else { if (debug_level & 1) { fprintf(stderr,", but popups disabled!\n"); } } } else { // fprintf(stderr,", but distance didn't work out!\n"); } } // Update the View->Bulletins dialog if it's up bulletin_message(from_call, call_sign, data, sec_now()); } // Find each bulletin that is within our range _and_ within our time // parameters for new bulletins. Count them only. Results returned // in the new_bulletin_count variable. void count_bulletin_messages(char *call_sign, char *packet_message, time_t sec_heard) { char temp_my_course[10]; double distance; if ( (packet_message != NULL) && (strlen(packet_message) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 1) { fprintf(stderr,"bulletin_message: Message length too long\n"); } return; } distance = distance_from_my_station(call_sign,temp_my_course); // Operands of <= have incompatible types (double, int): if ( ( ((int)distance <= bulletin_range) && (distance > 0.0) ) || (view_zero_distance_bulletins && distance == 0.0) || ( (bulletin_range == 0) && (distance > 0.0) ) ) { // Is it newer than our first new_bulletin timestamp? if (sec_heard >= first_new_bulletin_time) { new_bulletin_count++; } } } static void count_bulletin_line(Message *fill) { count_bulletin_messages(fill->from_call_sign, fill->message_line, fill->sec_heard); } static void count_new_bulletins(void) { mscan_file(MESSAGE_BULLETIN, count_bulletin_line); } // Function called by mscan_file for each bulletin with zero for the // position_known flag. See next function find_zero_position_bulletins() // static void zero_bulletin_processing(Message *fill) { DataRow *p_station; // Pointer to station data if (!fill->position_known) { //fprintf(stderr,"Position unknown: %s:%s\n", // fill->from_call_sign, // fill->message_line); // Check to see if we _now_ have a position for this non-new // bulletin. If so, change the position_known flag on that // record to a one, update the record, set the proper timers // and then schedule a popup if it fits within our current // parameters. if ( search_station_name(&p_station,fill->from_call_sign,1) ) { // Found a bulletin for which we get to fill in a new // position! if ( (p_station->coord_lon == 0l) && (p_station->coord_lat == 0l) ) { //fprintf(stderr,"Found it but still no valid position!\n"); } else // Found valid position for this bulletin { //fprintf(stderr,"Found it now! %s:%s\n", // fill->from_call_sign, // fill->message_line); // Mark it as found fill->position_known = 1; // Fake the timestamp so that we check messages back // to at least this one we just found. Allow for the // fact that we might find several older messages, so // we only want to keep taking the timestamp backwards // in time here. if (first_new_bulletin_time > (fill->sec_heard) ) { first_new_bulletin_time = fill->sec_heard; } // Check whether we really wish to pop them up if (pop_up_new_bulletins) { int distance; char temp_my_course[10]; distance = (int)(distance_from_my_station(fill->from_call_sign, temp_my_course) + 0.9999); if ( (bulletin_range == 0) || (distance <= bulletin_range && distance > 0) ) { if (debug_level & 1) { fprintf(stderr,"Filled in distance for earlier bulletin:%d miles\n", distance); } // If view_zero_distance_bulletins was not // turned on, then we probably haven't seen // this bulletin until now. Popup up the // Bulletin dialog. if (!view_zero_distance_bulletins) { //fprintf(stderr,"zero_bulletin_processing: popping up bulletins\n"); popup_bulletins(); } } } } } else { // No position known for the bulletin. Skip it for now. //fprintf(stderr,"Still not found\n"); } } } // Find all bulletins that have a zero for the position_known flag. // Calls the function above for each bulletin. // static void find_zero_position_bulletins(void) { mscan_file(MESSAGE_BULLETIN, zero_bulletin_processing); } // Function called by main.c:UpdateTime(). Checks whether enough // time has passed since the last new bulletin came in (so that the // posit for it might come in as well). If so, checks for bulletins // that are newer than first_new_bulletin_time and fit within our // range. If any found, it updates the Bulletins dialog. time_t last_bulletin_check = (time_t)0l; void check_for_new_bulletins(int curr_sec) { // Check every 15 seconds max if ( (last_bulletin_check + 15) > curr_sec ) { return; } last_bulletin_check = curr_sec; // Look first to see if we might be able to fill in positions on // any older bulletins, then cause a popup for those that fit // our parameters. The below function sets new_bulletin_flag if // it is able to fill in a distance for an older bulletin. // Note: This is time-consuming! find_zero_position_bulletins(); // Any new bulletins to check? If not, return if (!new_bulletin_flag) { return; } // Enough time passed since most recent bulletin? Need to have // enough time to perhaps fill in a distance for each bulletin. if ( (last_new_bulletin_time + 15) > curr_sec ) { //fprintf(stderr,"Not enough time has passed\n"); return; } // If we get to here, then we think we may have at least one new // bulletin, and the latest arrived more than XX seconds ago // (currently 15 seconds). Check for bulletins which have // timestamps equal to or newer than first_new_bulletin_time and // fit within our range. new_bulletin_count = 0; //fprintf(stderr,"Checking for new bulletins\n"); count_new_bulletins(); //fprintf(stderr,"%d new bulletins found\n",new_bulletin_count); if (new_bulletin_count) { //fprintf(stderr,"check_for_new_bulletins: popping up bulletins\n"); popup_bulletins(); if (debug_level & 1) { fprintf(stderr,"New bulletins (%d) caused popup!\n",new_bulletin_count); } } else { if (debug_level & 1) { fprintf(stderr,"No bulletin popup generated.\n"); } } // Reset so that we can do it all over again later. We need // mutex locks protecting these variables. first_new_bulletin_time = last_new_bulletin_time + 1; new_bulletin_flag = 0; } void Display_bulletins_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; // Keep this. It stores the range in a global variable when we destroy the dialog. temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Display_bulletins_destroy_shell" ); XtDestroyWidget(shell); Display_bulletins_dialog = (Widget)NULL; end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Display_bulletins_destroy_shell" ); } void Display_bulletins_change_range(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; // Keep this. It stores the range in a global variable when we destroy the dialog. temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); view_zero_distance_bulletins = (int)XmToggleButtonGetState(zero_bulletin_data); //fprintf(stderr,"%d\n",view_zero_distance_bulletins); Display_bulletins_destroy_shell( widget, clientData, callData); Bulletins( widget, clientData, callData); } void Zero_Bulletin_Data_toggle( Widget widget, XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { view_zero_distance_bulletins = atoi(which); } else { view_zero_distance_bulletins = 0; } Display_bulletins_destroy_shell( widget, Display_bulletins_dialog, callData); Bulletins( widget, clientData, callData); } void Bulletins(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, form, button_range, button_close, dist, dist_units; unsigned int n; Arg args[50]; Atom delw; char temp[10]; if(!Display_bulletins_dialog) { begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Bulletins" ); Display_bulletins_dialog = XtVaCreatePopupShell(langcode("BULMW00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Bulletins pane", xmPanedWindowWidgetClass, Display_bulletins_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Bulletins form", xmFormWidgetClass, pane, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); dist = XtVaCreateManagedWidget(langcode("BULMW00002"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); dist_data = XtVaCreateManagedWidget("dist_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*7)+2), XmNmaxLength, 8, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); dist_units = XtVaCreateManagedWidget((english_units?langcode("UNIOP00004"):langcode("UNIOP00005")), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_range = XtVaCreateManagedWidget(langcode("BULMW00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_units, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); zero_bulletin_data = XtVaCreateManagedWidget(langcode("WPUPCFD029"), xmToggleButtonWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_range, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(zero_bulletin_data,XmNvalueChangedCallback,Zero_Bulletin_Data_toggle,"1"); if (view_zero_distance_bulletins) { XmToggleButtonSetState(zero_bulletin_data,TRUE,FALSE); } else { XmToggleButtonSetState(zero_bulletin_data,FALSE,FALSE); } n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 108); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNscrollHorizontal, TRUE); n++; XtSetArg(args[n], XmNscrollVertical, TRUE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, dist); n++; XtSetArg(args[n], XmNtopOffset, 20); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, 30); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; Display_bulletins_text = XmCreateScrolledText(form, "Bulletins text", args, n); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_range, XmNactivateCallback, Display_bulletins_change_range, Display_bulletins_dialog); XtAddCallback(button_close, XmNactivateCallback, Display_bulletins_destroy_shell, Display_bulletins_dialog); pos_dialog(Display_bulletins_dialog); delw = XmInternAtom(XtDisplay(Display_bulletins_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(Display_bulletins_dialog, delw, Display_bulletins_destroy_shell, (XtPointer)Display_bulletins_dialog); xastir_snprintf(temp, sizeof(temp), "%d", bulletin_range); XmTextFieldSetString(dist_data, temp); XtManageChild(form); XtManageChild(Display_bulletins_text); XtVaSetValues(Display_bulletins_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); redraw_on_new_packet_data=1; XtPopup(Display_bulletins_dialog,XtGrabNone); end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Bulletins" ); scan_bulletin_file(); // Move focus to the Close button. This appears to // highlight the button fine, but we're not able to hit the // key to have that default function happen. Note: // We _can_ hit the key, and that activates the // option. //XmUpdateDisplay(Display_bulletins_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(Display_bulletins_dialog), XtWindow(Display_bulletins_dialog)); } } Xastir-Release-2.2.2/src/bulletin_gui.h000066400000000000000000000024231501463444000177710ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_BULLETIN_GUI_H #define __XASTIR_BULLETIN_GUI_H extern int bulletin_range; // From bulletin_gui.c extern void bulletin_gui_init(void); extern void bulletin_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from); extern void check_for_new_bulletins(int current_sec); #endif // __XASTIR_BULLETIN_GUI_H Xastir-Release-2.2.2/src/color.c000066400000000000000000000224521501463444000164240ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include "xastir.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" static color_load color_choice[MAX_COLORS]; static int colors_loaded; static int rm, gm, bm; // rgb masks static int rs, gs, bs; // rgb shifts int visual_depth; /**********************************************************************************/ /* load color file */ /* load the colors to be used with Xastir */ /* Return 1 if good 0 if not found or error */ /**********************************************************************************/ int load_color_file(void) { FILE *f; char temp[40]; int r,g,b; char colorname[50]; int ok,x; xastir_snprintf(temp, sizeof(temp), "config/xastir.rgb"); colors_loaded=0; ok=1; f=fopen(get_data_base_dir(temp),"r"); if (f!=NULL) { while (!feof(f) && ok) { if (fscanf(f,"%d %d %d %49s",&r,&g,&b,colorname)==4) { if (colors_loaded < MAX_COLORS) { for (x=0; x= 0) { // XFreeColors() here generates an error. Why? // "BadAccess (attempt to access private resource denied)" // XFreeColors(dpy, cmap, &(color_choice[found].color.pixel),1,0); if (XAllocColor(dpy,cmap,&color_choice[found].color)) { return(color_choice[found].color.pixel); } else { xastir_snprintf(warning, sizeof(warning), "Couldn't allocate color %s", colorname); XtWarning(warning); return(BlackPixel(dpy,scr)); } } else { xastir_snprintf(warning, sizeof(warning), "Couldn't find color %s", colorname); XtWarning(warning); return(BlackPixel(dpy,scr)); } } void setup_visual_info(Display* dpy, int scr) { int visuals_matched, i, j; XVisualInfo *visual_list, *vp; XVisualInfo visual_template; rm = gm = bm = rs = gs = bs = 0; visual_list = XGetVisualInfo(dpy, VisualNoMask, &visual_template, &visuals_matched); if (visuals_matched) { if (debug_level & 16) { fprintf(stderr,"Found %d visuals\n", visuals_matched); } for (i = 0; i < visuals_matched; i++) { vp = &visual_list[i]; if (vp->visualid == XVisualIDFromVisual(DefaultVisual(dpy, scr))) { if (vp->class == TrueColor || vp->class == DirectColor) { if (vp->red_mask == 0xf800 && vp->green_mask == 0x07e0 && vp->blue_mask == 0x001f) { visual_type = RGB_565; } else if (vp->red_mask == 0x7c00 && vp->green_mask == 0x03e0 && vp->blue_mask == 0x001f) { visual_type = RGB_555; } else if (vp->red_mask == 0xff0000 && vp->green_mask == 0x00ff00 && vp->blue_mask == 0x0000ff) { visual_type = RGB_888; } else { rm = vp->red_mask; gm = vp->green_mask; bm = vp->blue_mask; for (j = 31; j >= 0; j--) { if (rm >= (1 << j)) { rs = j - 15; break; } } for (j = 31; j >= 0; j--) { if (gm >= (1 << j)) { gs = j - 15; break; } } for (j = 31; j >= 0; j--) { if (bm >= (1 << j)) { bs = j - 15; break; } } visual_type = RGB_OTHER; } } else { visual_type = NOT_TRUE_NOR_DIRECT; } if (debug_level & 16) { fprintf(stderr,"\tID: 0x%lx, Default\n", vp->visualid); } } else if (debug_level & 16) { fprintf(stderr,"\tID: 0x%lx\n", vp->visualid); } // Store color depth for use by other routines. visual_depth = vp->depth; if (debug_level & 16) { fprintf(stderr,"\tScreen: %d\n", vp->screen); fprintf(stderr,"\tDepth: %d\n", vp->depth); fprintf(stderr,"\tClass: %d", vp->class); switch (vp->class) { case StaticGray: fprintf(stderr,", StaticGray\n"); break; case GrayScale: fprintf(stderr,", GrayScale\n"); break; case StaticColor: fprintf(stderr,", StaticColor\n"); break; case PseudoColor: fprintf(stderr,", PseudoColor\n"); break; case TrueColor: fprintf(stderr,", TrueColor\n"); break; case DirectColor: fprintf(stderr,", DirectColor\n"); break; default: fprintf(stderr,", ??\n"); break; } fprintf(stderr,"\tClrmap Size: %d\n", vp->colormap_size); fprintf(stderr,"\tBits per RGB: %d\n", vp->bits_per_rgb); fprintf(stderr,"\tRed Mask: 0x%lx\n", vp->red_mask); fprintf(stderr,"\tGreen Mask: 0x%lx\n", vp->green_mask); fprintf(stderr,"\tBlue Mask: 0x%lx\n\n", vp->blue_mask); } } } XFree(visual_list); } void pack_pixel_bits(unsigned short r, unsigned short g, unsigned short b, unsigned long* pixel) { switch (visual_type) { case RGB_565: *pixel = (( r & 0xf800) | ((g >> 5) & 0x07e0) | (b >> 11)); break; case RGB_555: *pixel = (((r >> 1) & 0x7c00) | ((g >> 6) & 0x03e0) | (b >> 11)); break; case RGB_888: *pixel = (((r << 8) & 0xff0000) | ( g & 0x00ff00) | (b >> 8)); break; case RGB_OTHER: if (rs >= 0) { *pixel = ((r << rs) & rm); } else { *pixel = ((r >> (-rs)) & rm); } if (gs >= 0) { *pixel |= ((g << gs) & gm); } else { *pixel |= ((g >> (-gs)) & gm); } if (bs >= 0) { *pixel |= ((b << bs) & bm); } else { *pixel |= ((b >> (-bs)) & bm); } break; case NOT_TRUE_NOR_DIRECT: default: break; } } Xastir-Release-2.2.2/src/color.h000066400000000000000000000030471501463444000164300ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_COLOR_H #define XASTIR_COLOR_H #define MAX_COLORS 81 #define MAX_COLORNAME 40 typedef struct { char colorname[MAX_COLORNAME]; XColor color; } color_load; typedef enum { NOT_TRUE_NOR_DIRECT, RGB_565, RGB_555, RGB_888, RGB_OTHER } Pixel_Format; extern Pixel_Format visual_type; extern int visual_depth; /* from color.c */ extern int load_color_file(void); extern Pixel GetPixelByName(Widget w, char *colorname); extern void setup_visual_info(Display* dpy, int scr); extern void pack_pixel_bits(unsigned short r, unsigned short g, unsigned short b, unsigned long* pixel); #endif /* XASTIR_COLOR_H */ Xastir-Release-2.2.2/src/database.h000066400000000000000000000550371501463444000170640ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Note: this file should be called db.h, but was renamed to database.h * to avoid conflicts with the Berkeley DB package. */ /* * Database structures * */ #ifndef XASTIR_DATABASE_H #define XASTIR_DATABASE_H #define MSG_INCREMENT 200 #define MAX_CALLSIGN 9 // Objects are up to 9 chars #define MAX_TACTICAL_CALL 57 // Up to XX chars for tactical calls #define MAX_COMMENT_LINES 20 // Save XX unique comment strings per station #define MAX_STATUS_LINES 20 // Save XX unique status strings per station /* define max size of info field */ #define MAX_INFO_FIELD_SIZE 256 // Number of times to send killed objects/items before ceasing to // transmit them. #define MAX_KILLED_OBJECT_RETRANSMIT 20 // Check entire station list at this rate for objects/items that // might need to be transmitted via the decaying algorithm. This is // the start rate, which gets doubled on each transmit. #define OBJECT_CHECK_RATE 20 // We should probably be using APRS_DF in extract_bearing_NRQ() // and extract_omnidf() functions. We aren't currently. /* Define APRS Types */ enum APRS_Types { APRS_NULL, APRS_MSGCAP, APRS_FIXED, APRS_DOWN, // Not used anymore APRS_MOBILE, APRS_DF, APRS_OBJECT, APRS_ITEM, APRS_STATUS, APRS_WX1, APRS_WX2, APRS_WX3, APRS_WX4, APRS_WX5, APRS_WX6, QM_WX, PEET_COMPLETE, RSWX200, GPS_RMC, GPS_GGA, GPS_GLL, STATION_CALL_DATA, OTHER_DATA, APRS_MICE, APRS_GRID, DALLAS_ONE_WIRE, DAVISMETEO, DAVISAPRSDL }; /* Define Record Types */ #define NORMAL_APRS 'N' #define MOBILE_APRS 'M' #define DF_APRS 'D' #define DOWN_APRS 'Q' #define NORMAL_GPS_RMC 'C' #define NORMAL_GPS_GGA 'A' #define NORMAL_GPS_GLL 'L' #define APRS_WX1 '1' #define APRS_WX2 '2' #define APRS_WX3 '3' #define APRS_WX4 '4' #define APRS_WX5 '5' #define APRS_WX6 '6' /* define RECORD ACTIVES */ #define RECORD_ACTIVE 'A' #define RECORD_NOTACTIVE 'N' #define RECORD_CLOSED 'C' /* define data from info type */ #define DATA_VIA_LOCAL 'L' #define DATA_VIA_TNC 'T' #define DATA_VIA_NET 'I' #define DATA_VIA_FILE 'F' #define DATA_VIA_DATABASE 'D' /* define Heard info type */ #define VIA_TNC 'Y' #define NOT_VIA_TNC 'N' /* define Message types */ #define MESSAGE_MESSAGE 'M' #define MESSAGE_BULLETIN 'B' #define MESSAGE_NWS 'W' // Define file info, string length are without trailing '\0' #define MAX_TIME 20 #define MAX_LONG 12 #define MAX_LAT 11 #define MAX_ALTITUDE 10 //-32808.4 to 300000.0? feet #define MAX_SPEED 9 /* ?? 3 in knots */ #define MAX_COURSE 7 /* ?? */ #define MAX_POWERGAIN 7 #define MAX_STATION_TIME 10 /* 6+1 */ #define MAX_SAT 4 #define MAX_DISTANCE 10 #define MAX_WXSTATION 50 #define MAX_TEMP 100 #define MAX_MESSAGE_LENGTH 100 #define MAX_MESSAGE_ORDER 10 // track export file formats #define EXPORT_XASTIR_TRACK 0 #define EXPORT_KML_TRACK 1 extern char *get_most_recent_ack(char *callsign); extern void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata); // From main.c extern char my_callsign[MAX_CALLSIGN+1]; extern char my_lat[MAX_LAT]; extern char my_long[MAX_LONG]; // Used for messages and bulletins typedef struct { char active; char data_via; char type; char heard_via_tnc; time_t sec_heard; time_t last_ack_sent; char packet_time[MAX_TIME]; char call_sign[MAX_CALLSIGN+1]; char from_call_sign[MAX_CALLSIGN+1]; char message_line[MAX_MESSAGE_LENGTH+1]; char seq[MAX_MESSAGE_ORDER+1]; char acked; char position_known; time_t interval; int tries; } Message; // Struct used to create linked list of most recent ack's typedef struct _ack_record { char callsign[MAX_CALLSIGN+1]; char ack[5+1]; struct _ack_record *next; } ack_record; #ifdef MSG_DEBUG extern void msg_clear_data(Message *clear); extern void msg_copy_data(Message *to, Message *from); #else // MSG_DEBUG #define msg_clear_data(clear) memset((Message *)clear, 0, sizeof(Message)) #define msg_copy_data(to, from) memmove((Message *)to, (Message *)from, \ sizeof(Message)) #endif /* MSG_DEBUG */ extern int message_update_time(void); enum AreaObjectTypes { AREA_OPEN_CIRCLE = 0x0, AREA_LINE_LEFT = 0x1, AREA_OPEN_ELLIPSE = 0x2, AREA_OPEN_TRIANGLE = 0x3, AREA_OPEN_BOX = 0x4, AREA_FILLED_CIRCLE = 0x5, AREA_LINE_RIGHT = 0x6, AREA_FILLED_ELLIPSE = 0x7, AREA_FILLED_TRIANGLE = 0x8, AREA_FILLED_BOX = 0x9, AREA_MAX = 0x9, AREA_NONE = 0xF }; enum AreaObjectColors { AREA_BLACK_HI = 0x0, AREA_BLUE_HI = 0x1, AREA_GREEN_HI = 0x2, AREA_CYAN_HI = 0x3, AREA_RED_HI = 0x4, AREA_VIOLET_HI = 0x5, AREA_YELLOW_HI = 0x6, AREA_GRAY_HI = 0x7, AREA_BLACK_LO = 0x8, AREA_BLUE_LO = 0x9, AREA_GREEN_LO = 0xA, AREA_CYAN_LO = 0xB, AREA_RED_LO = 0xC, AREA_VIOLET_LO = 0xD, AREA_YELLOW_LO = 0xE, AREA_GRAY_LO = 0xF }; typedef struct { unsigned type : 4; unsigned color : 4; unsigned sqrt_lat_off : 8; unsigned sqrt_lon_off : 8; unsigned corridor_width : 16; } AreaObject; typedef struct { char aprs_type; char aprs_symbol; char special_overlay; AreaObject area_object; } APRS_Symbol; // Struct for holding current weather data. // This struct is pointed to by the DataRow structure. // An empty string indicates undefined data. typedef struct // strlen { time_t wx_sec_time; int wx_storm; // Set to one if severe storm char wx_time[MAX_TIME]; char wx_course[4]; // in 3 char wx_speed[4]; // in mph 3 time_t wx_speed_sec_time; char wx_gust[4]; // in mph 3 char wx_hurricane_radius[4]; //nautical miles 3 char wx_trop_storm_radius[4]; //nautical miles 3 char wx_whole_gale_radius[4]; // nautical miles 3 char wx_temp[5]; // in F 3 char wx_rain[10]; // in hundredths inch/h 3 char wx_rain_total[10]; // in hundredths inch char wx_snow[6]; // in inches/24h 3 char wx_prec_24[10]; // in hundredths inch/day 3 char wx_prec_00[10]; // in hundredths inch 3 char wx_hum[5]; // in % 3 char wx_baro[10]; // in hPa 6 char wx_fuel_temp[5]; // in F 3 char wx_fuel_moisture[5];// in % 2 char wx_type; char wx_station[MAX_WXSTATION]; int wx_compute_rain_rates; // Some stations provide rain rates // directly, others require Xastir to // compute from total rain. Flag this, // so we don't clobber useful info from // a station. } WeatherRow; // Struct for holding track data. Keeps a dynamically allocated // doubly-linked list of track points. The first record should have its // "prev" pointer set to NULL and the last record should have its "next" // pointer set to NULL. If no track storage exists then the pointers to // these structs in the DataRow struct should be NULL. typedef struct _TrackRow { long trail_long_pos; // coordinate of trail point long trail_lat_pos; // coordinate of trail point time_t sec; // date/time of position long speed; // in 0.1 km/h undefined: -1 int course; // in degrees undefined: -1 long altitude; // in 0.1 m undefined: -99999 char flag; // several flags, see below struct _TrackRow *prev; // pointer to previous record in list struct _TrackRow *next; // pointer to next record in list } TrackRow; // trail flag definitions #define TR_LOCAL 0x01 // heard direct (not via digis) #define TR_NEWTRK 0x02 // start new track // Struct for holding comment/status data. Will keep a dynamically // allocated list of text. Every different comment field will be // stored in a separate line. typedef struct _CommentRow { char *text_ptr; // Ptr to the comment text time_t sec_heard; // Latest timestamp for this comment/status struct _CommentRow *next; // Ptr to next record or NULL } CommentRow; #define MAX_MULTIPOINTS 35 // Struct for holding multipoint data. typedef struct _MultipointRow { long multipoints[MAX_MULTIPOINTS][2]; } MultipointRow; // Break DataRow into several structures. DataRow will contain the // parameters that are common across all types of stations. DataRow // will contain a pointer to TrackRow if it is a moving station, and // contain a pointer to WeatherRow if it is a weather station. If no // weather or track data existed, the pointers will be NULL. This new // way of storing station data will save a LOT of memory. If a // station suddenly starts moving or spitting out weather data the new // structures will be allocated, filled in, and pointers to them // installed in DataRow. // // Station storage now is organized as an ordered linked list. We have // both sorting by name and by time last heard // // todo: check the string length! // typedef struct _DataRow { struct _DataRow *n_next; // pointer to next element in name ordered list struct _DataRow *n_prev; // pointer to previous element in name ordered // list struct _DataRow *t_newer; // pointer to next element in time ordered // list (newer) struct _DataRow *t_older; // pointer to previous element in time ordered // list (older) char call_sign[MAX_CALLSIGN+1]; // call sign or name index or object/item // name char *tactical_call_sign; // Tactical callsign. NULL if not assigned APRS_Symbol aprs_symbol; long coord_lon; // Xastir coordinates 1/100 sec, 0 = 180W long coord_lat; // Xastir coordinates 1/100 sec, 0 = 90N int time_sn; // serial number for making time index unique time_t sec_heard; // time last heard, used also for time index time_t heard_via_tnc_last_time; time_t direct_heard; // KC2ELS - time last heard direct // Change into time_t structs? It'd save us a bunch of space. char packet_time[MAX_TIME]; char pos_time[MAX_TIME]; // char altitude_time[MAX_TIME]; // char speed_time[MAX_TIME]; // char station_time[MAX_STATION_TIME]; // char station_time_type; short flag; // several flags, see below char pos_amb; // Position ambiguity, 0 = none, // 1 = 0.1 minute... unsigned int error_ellipse_radius; // Degrades precision for this // station, from 0 to 65535 cm or // 655.35 meters. Assigned when we // decode each type of packet. // Default is 6.0 meters (600 cm) // unless we know the GPS position // is augmented, or is degraded by // less precision in the packet. unsigned int lat_precision; // In 100ths of a second latitude unsigned int lon_precision; // In 100ths of a second longitude int trail_color; // trail color (when assigned) char record_type; char data_via; // L local, T TNC, I internet, F file // Change to char's to save space? int heard_via_tnc_port; int last_port_heard; unsigned int num_packets; char *node_path_ptr; // Pointer to path string char altitude[MAX_ALTITUDE]; // in meters (feet gives better resolution ??) char speed[MAX_SPEED+1]; // in knots (same as nautical miles/hour) char course[MAX_COURSE+1]; char bearing[MAX_COURSE+1]; char NRQ[MAX_COURSE+1]; char power_gain[MAX_POWERGAIN+1]; // Holds the phgd values char signal_gain[MAX_POWERGAIN+1]; // Holds the shgd values (for DF'ing) WeatherRow *weather_data; // Pointer to weather data or NULL CommentRow *status_data; // Ptr to status records or NULL CommentRow *comment_data; // Ptr to comment records or NULL // Below two pointers are NULL if only one position has been received TrackRow *oldest_trackpoint; // Pointer to oldest track point in // doubly-linked list TrackRow *newest_trackpoint; // Pointer to newest track point in // doubly-linked list // When the station is an object, it can include coordinates // of related points. Currently these are being used to draw // outlines of NWS severe weather watches and warnings, and // storm regions. The coordinates are stored here in Xastir // coordinate form. Element [x][0] is the latitude, and // element [x][1] is the longitude. --KG4NBB // // Is there anything preventing a multipoint string from being // in other types of packets, in the comment field? --WE7U // int num_multipoints; char type; // from '0' to '9' char style; // from 'a' to 'z' MultipointRow *multipoint_data; /////////////////////////////////////////////////////////////////////// // Optional stuff for Objects/Items only (I think, needs to be // checked). These could be moved into an ObjectRow structure, with // only a NULL pointer here if not an object/item. /////////////////////////////////////////////////////////////////////// char origin[MAX_CALLSIGN+1]; // call sign originating an object short object_retransmit; // Number of times to retransmit object. // -1 = forever // Used currently to stop sending killed // objects. time_t last_transmit_time; // Time we last transmitted an object/item. // Used to implement decaying transmit time // algorithm short transmit_time_increment; // Seconds to add to transmit next time // around. Used to implement decaying // transmit time algorithm // time_t last_modified_time; // Seconds since the object/item // was last modified. We'll // eventually use this for // dead-reckoning. char signpost[5+1]; // Holds signpost data int df_color; char sats_visible[MAX_SAT]; char probability_min[10+1]; // Holds prob_min (miles) char probability_max[10+1]; // Holds prob_max (miles) } DataRow; // Used to store one vertice in CADRow object typedef struct _VerticeRow { long latitude; // Xastir coordinates 1/100sec, 0 = 180W long longitude; // Xastir coordinates 1/100sec, 0 = 90N struct _VerticeRow *next; // Pointer to next record in list } VerticeRow; #define CAD_LABEL_MAX_SIZE 40 #define CAD_COMMENT_MAX_SIZE 256 // CAD Objects typedef struct _CADRow { struct _CADRow *next; // Pointer to next element in list time_t creation_time; // Time at which object was first created VerticeRow *start; // Pointer to first VerticeRow int line_color; // Border color int line_type; // Border linetype int line_width; // Border line width float computed_area; // Area in square kilometers float raw_probability; // Probability of area (POA) or probability of // detection (POD) stored as probability // with a value between 0 and 1. // Set and get with CAD_object_get_raw_probability() // and CAD_object_set_raw_probability(), rather // than by a direct request for CADRow->raw_probability. long label_latitude; // Latitude for label placement long label_longitude; // Longitude for label placement char label[CAD_LABEL_MAX_SIZE]; // Name of polygon char comment[CAD_COMMENT_MAX_SIZE]; // Comments associated with polygon } CADRow; extern CADRow *CAD_list_head; // station flag definitions. We have 16 bits available here as // "flag" in "DataRow" is defined as a short. // #define ST_OBJECT 0x01 // station is an object #define ST_ITEM 0x02 // station is an item #define ST_ACTIVE 0x04 // station is active (deleted objects are // inactive) #define ST_MOVING 0x08 // station is moving #define ST_DIRECT 0x10 // heard direct (not via digis) #define ST_VIATNC 0x20 // station heard via TNC #define ST_3RD_PT 0x40 // third party traffic #define ST_MSGCAP 0x80 // message capable (not used yet) #define ST_STATUS 0x100 // got real status message #define ST_INVIEW 0x200 // station is in current screen view #define ST_MYSTATION 0x400 // station is owned by my call-SSID #define ST_MYOBJITEM 0x800 // object/item owned by me #ifdef DATA_DEBUG extern void clear_data(DataRow *clear); extern void copy_data(DataRow *to, DataRow *from); #else // DATA_DEBUG #define clear_data(clear) memset((DataRow *)clear, 0, sizeof(DataRow)) #define copy_data(to, from) memmove((DataRow *)to, (DataRow *)from, \ sizeof(DataRow)) #endif /* DATA_DEBUG */ extern void db_init(void); extern void export_trail_as_kml(DataRow *p_station); // export trail of one or all stations to kml file // extern int is_my_call(char *call, int exact); extern int is_my_station(DataRow *p_station); extern int is_my_object_item(DataRow *p_station); void mscan_file(char msg_type, void (*function)(Message *fill)); extern void msg_record_ack(char *to_call_sign, char *my_call, char *seq, int timeout, int cancel); extern void msg_record_interval_tries(char *to_call_sign, char *my_call, char *seq, time_t interval, int tries); extern void display_file(Widget w); extern void clean_data_file(void); extern void read_file_line(FILE *f); extern void mdisplay_file(char msg_type); extern void mem_display(void); extern long sort_input_database(char *filename, char *fill, int size); extern void sort_display_file(char *filename, int size); extern void clear_sort_file(char *filename); extern void display_packet_data(void); extern int redraw_on_new_packet_data; extern int decode_ax25_header(unsigned char *data_string, int *length); extern int decode_ax25_line(char *line, char from, int port, int dbadd); // utilities extern void packet_data_add(char *from, char *line, int data_port); extern void General_query(Widget w, XtPointer clientData, XtPointer calldata); extern void IGate_query(Widget w, XtPointer clientData, XtPointer calldata); extern void WX_query(Widget w, XtPointer clientData, XtPointer calldata); extern unsigned long max_stations; extern int heard_via_tnc_in_past_hour(char *call); // messages extern void update_messages(int force); extern void mdelete_messages_from(char *from); extern void mdelete_messages_to(char *to); extern void init_message_data(void); extern void check_message_remove(time_t curr_sec); extern int new_message_data; extern time_t msg_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from, long *record_out); // stations extern int st_direct_timeout; // Interval that ST_DIRECT flag stays set extern int station_count; // Count of stations in the database extern int station_count_save; // Old copy of the above extern DataRow *n_first; // pointer to first element in name ordered station // list extern DataRow *n_last; // pointer to last element in name ordered station // list extern DataRow *t_oldest; // pointer to first element in time ordered station // list extern DataRow *t_newest; // pointer to last element in time ordered station // list extern void init_station_data(void); extern void Station_data(Widget w, XtPointer clientData, XtPointer calldata); extern int station_data_auto_update; extern int next_station_name(DataRow **p_curr); extern int prev_station_name(DataRow **p_curr); extern int next_station_time(DataRow **p_curr); extern int prev_station_time(DataRow **p_curr); extern int search_station_name(DataRow **p_name, char *call, int exact); extern int search_station_time(DataRow **p_time, time_t heard, int serial); extern void check_station_remove(time_t curr_sec); extern void delete_all_stations(void); extern void station_del(char *callsign); extern void my_station_add(char *my_call_sign, char my_group, char my_symbol, char *my_long, char *my_lat, char *my_phg, char *my_comment, char my_amb); extern void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char speedu, char *alt, char *sats); extern int locate_station(Widget w, char *call, int follow_case, int get_match, int center_map); extern void update_station_info(Widget w); // objects/items extern time_t last_object_check; // trails extern int delete_trail(DataRow *fill); // weather extern int get_weather_record(DataRow *fill); extern void set_map_position(Widget w, long lat, long lon); // just used for aloha calcs typedef struct { double distance; char call_sign[MAX_CALLSIGN+1]; // call sign or name index or object/item // name char is_mobile; char is_other_mobile; char is_wx; char is_digi; // can only tell this if using a digi icon! char is_home; // stationary stations that are not digis } aloha_entry; typedef struct { int digis; int wxs; int other_mobiles; int mobiles_in_motion; int homes; int total; } aloha_stats; double calc_aloha_distance(void); //meat void calc_aloha(int curr_sec); // periodic function void Show_Aloha_Stats(Widget w, XtPointer clientData, XtPointer callData); // popup window int comp_by_dist(const void *,const void *);// used only for qsort DataRow * sanity_check_time_list(time_t); // used only for debugging void dump_time_sorted_list(void); extern int store_trail_point(DataRow *p_station, long lon, long lat, time_t sec, char *alt, char *speed, char *course, short stn_flag); #ifdef HAVE_DB extern int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time, char *timeformat); #endif /* HAVE_DB */ #endif /* XASTIR_DATABASE_H */ Xastir-Release-2.2.2/src/datum.c000066400000000000000000001345601501463444000164240ustar00rootroot00000000000000/* See the top of datum.h for information on this code. N7TAP Portions Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include "xastir.h" #include "datum.h" #include "main.h" #include "util.h" // Must be last include file #include "leak_detection.h" // ellipsoid: index into the gEllipsoid[] array, in which // a is the ellipsoid semimajor axis // invf is the inverse of the ellipsoid flattening f // dx, dy, dz: ellipsoid center with respect to WGS84 ellipsoid center // x axis is the prime meridian // y axis is 90 degrees east longitude // z axis is the axis of rotation of the ellipsoid // The following values for dx, dy and dz were extracted from the output of // the GARMIN PCX5 program. The output also includes values for da and df, the // difference between the reference ellipsoid and the WGS84 ellipsoid semi- // major axis and flattening, respectively. These are replaced by the // data contained in the structure array gEllipsoid[], which was obtained from // the Defence Mapping Agency document number TR8350.2, "Department of Defense // World Geodetic System 1984." /* The above are the original comments by John Waers. Curt Mills, WE7U wrote a perl version of this code and added more datums from Peter H. Dana's website. Reference Ellipsoids: http://www.Colorado.EDU/geography/gcraft/notes/datum/elist.html Reference Ellipsoids and Datums: http://www.Colorado.EDU/geography/gcraft/notes/datum/edlist.html I've loaded the numbers from that second, newer web page. N7TAP */ /* Keep the enum in datum.h up to date with the order of this array */ const Ellipsoid gEllipsoid[] = { // name a 1/f { "Airy 1830", 6377563.396, 299.3249646 }, { "Modified Airy", 6377340.189, 299.3249646 }, { "Australian National", 6378160.0, 298.25 }, { "Bessel 1841", 6377397.155, 299.1528128 }, { "Bessel 1841 (Namibia)", 6377483.865, 299.1528128 }, { "Clarke 1866", 6378206.4, 294.9786982 }, { "Clarke 1880", 6378249.145, 293.465 }, { "Everest (India 1830)", 6377276.345, 300.8017 }, { "Everest (India 1956)", 6377301.243, 300.8017 }, { "Everest (Sabah Sarawak)", 6377298.556, 300.8017 }, { "Everest (Malaysia 1969)", 6377295.664, 300.8017 }, { "Everest (Malay. & Sing)", 6377304.063, 300.8017 }, { "Everest (Pakistan)", 6377309.613, 300.8017 }, { "Fischer 1960 (Mercury)", 6378166.0, 298.3 }, { "Modified Fischer 1960", 6378155.0, 298.3 }, { "Fischer 1968", 6378150.0, 298.3 }, { "Helmert 1906", 6378200.0, 298.3 }, { "Hough 1960", 6378270.0, 297.0 }, { "Indonesian 1974", 6378160.0, 298.247 }, { "International 1924", 6378388.0, 297.0 }, { "Krassovsky 1940", 6378245.0, 298.3 }, { "GRS 67", 6378160.0, 298.247167427 }, { "GRS 80", 6378137.0, 298.257222101 }, { "South American 1969", 6378160.0, 298.25 }, { "WGS 60", 6378165.0, 298.3 }, { "WGS 66", 6378145.0, 298.25 }, { "WGS 72", 6378135.0, 298.26 }, { "WGS 84", 6378137.0, 298.257223563 } }; /* Keep correct indices to commonly used datums in the enum in datum.h */ /* Feel free to add mnemonic indices for datums that you use */ const Datum gDatum[] = { // name ellipsoid dx dy dz { "Adindan (Burkina Faso)", E_CLARKE_80, -118, -14, 218 }, // 0 { "Adindan (Cameroon)", E_CLARKE_80, -134, -2, 210 }, // 1 { "Adindan (Ethiopia)", E_CLARKE_80, -165, -11, 206 }, // 2 { "Adindan (Mali)", E_CLARKE_80, -123, -20, 220 }, // 3 { "Adindan (MEAN FOR Ethiopia; Sudan)", E_CLARKE_80, -166, -15, 204 }, // 4 { "Adindan (Senegal)", E_CLARKE_80, -128, -18, 224 }, // 5 { "Adindan (Sudan)", E_CLARKE_80, -161, -14, 205 }, // 6 { "Afgooye (Somalia)", E_KRASS_40, -43, -163, 45 }, // 7 { "Ain el Abd 1970 (Bahrain)", E_INT_24, -150, -250, -1 }, // 8 { "Ain el Abd 1970 (Saudi Arabia)", E_INT_24, -143, -236, 7 }, // 9 { "American Samoa 1962 (American Samoa Islands)", E_CLARKE_66, -115, 118, 426 }, // 10 { "Anna 1 Astro 1965 (Cocos Islands)", E_AUS_NAT, -491, -22, 435 }, // 11 { "Antigua Island Astro 1943 (Antigua (Leeward Islands))", E_CLARKE_80, -270, 13, 62 }, // 12 { "Arc 1950 (Botswana)", E_CLARKE_80, -138, -105, -289 }, // 13 { "Arc 1950 (Burundi)", E_CLARKE_80, -153, -5, -292 }, // 14 { "Arc 1950 (Lesotho)", E_CLARKE_80, -125, -108, -295 }, // 15 { "Arc 1950 (Malawi)", E_CLARKE_80, -161, -73, -317 }, // 16 { "Arc 1950 (MEAN FOR Botswana; Lesotho; Malawi; Swaziland; Zaire; Zambia; Zimbabwe)", E_CLARKE_80, -143, -90, -294 }, // 17 { "Arc 1950 (Swaziland)", E_CLARKE_80, -134, -105, -295 }, // 18 { "Arc 1950 (Zaire)", E_CLARKE_80, -169, -19, -278 }, // 19 { "Arc 1950 (Zambia)", E_CLARKE_80, -147, -74, -283 }, // 20 { "Arc 1950 (Zimbabwe)", E_CLARKE_80, -142, -96, -293 }, // 21 { "Arc 1960 (MEAN FOR Kenya; Tanzania)", E_CLARKE_80, -160, -6, -302 }, // 22 { "Arc 1960 (Kenya)", E_CLARKE_80, -157, -2, -299 }, // 23 { "Arc 1960 (Taanzania)", E_CLARKE_80, -175, -23, -303 }, // 24 { "Ascension Island 1958 (Ascension Island)", E_INT_24, -205, 107, 53 }, // 25 { "Astro Beacon E 1945 (Iwo Jima)", E_INT_24, 145, 75, -272 }, // 26 { "Astro DOS 71/4 (St Helena Island)", E_INT_24, -320, 550, -494 }, // 27 { "Astro Tern Island (FRIG) 1961 (Tern Island)", E_INT_24, 114, -116, -333 }, // 28 { "Astronomical Station 1952 (Marcus Island)", E_INT_24, 124, -234, -25 }, // 29 { "Australian Geodetic 1966 (Australia; Tasmania)", E_AUS_NAT, -133, -48, 148 }, // 30 { "Australian Geodetic 1984 (Australia; Tasmania)", E_AUS_NAT, -134, -48, 149 }, // 31 { "Ayabelle Lighthouse (Djibouti)", E_CLARKE_80, -79, -129, 145 }, // 32 { "Bellevue (IGN) (Efate & Erromango Islands)", E_INT_24, -127, -769, 472 }, // 33 { "Bermuda 1957 (Bermuda)", E_CLARKE_66, -73, 213, 296 }, // 34 { "Bissau (Guinea-Bissau)", E_INT_24, -173, 253, 27 }, // 35 { "Bogota Observatory (Colombia)", E_INT_24, 307, 304, -318 }, // 36 { "Bukit Rimpah (Indonesia (Bangka & Belitung Ids))", E_BESS_41, -384, 664, -48 }, // 37 { "Camp Area Astro (Antarctica (McMurdo Camp Area))", E_INT_24, -104, -129, 239 }, // 38 { "Campo Inchauspe (Argentina)", E_INT_24, -148, 136, 90 }, // 39 { "Canton Astro 1966 (Phoenix Islands)", E_INT_24, 298, -304, -375 }, // 40 { "Cape (South Africa)", E_CLARKE_80, -136, -108, -292 }, // 41 { "Cape Canaveral (Bahamas; Florida)", E_CLARKE_66, -2, 151, 181 }, // 42 { "Carthage (Tunisia)", E_CLARKE_80, -263, 6, 431 }, // 43 { "Chatham Island Astro 1971 (New Zealand (Chatham Island))", E_INT_24, 175, -38, 113 }, // 44 { "Chua Astro (Paraguay)", E_INT_24, -134, 229, -29 }, // 45 { "Corrego Alegre (Brazil)", E_INT_24, -206, 172, -6 }, // 46 { "Dabola (Guinea)", E_CLARKE_80, -83, 37, 124 }, // 47 { "Deception Island (Deception Island; Antarctia)", E_CLARKE_80, 260, 12, -147 }, // 48 { "Djakarta (Batavia) (Indonesia (Sumatra))", E_BESS_41, -377, 681, -50 }, // 49 { "DOS 1968 (New Georgia Islands (Gizo Island))", E_INT_24, 230, -199, -752 }, // 50 { "Easter Island 1967 (Easter Island)", E_INT_24, 211, 147, 111 }, // 51 { "Estonia; Coordinate System 1937 (Estonia)", E_BESS_41, 374, 150, 588 }, // 52 { "European 1950 (Cyprus)", E_INT_24, -104, -101, -140 }, // 53 { "European 1950 (Egypt)", E_INT_24, -130, -117, -151 }, // 54 { "European 1950 (England; Channel Islands; Scotland; Shetland Islands)", E_INT_24, -86, -96, -120 }, // 55 { "European 1950 (England; Ireland; Scotland; Shetland Islands)", E_INT_24, -86, -96, -120 }, // 56 { "European 1950 (Finland; Norway)", E_INT_24, -87, -95, -120 }, // 57 { "European 1950 (Greece)", E_INT_24, -84, -95, -130 }, // 58 { "European 1950 (Iran)", E_INT_24, -117, -132, -164 }, // 59 { "European 1950 (Italy (Sardinia))", E_INT_24, -97, -103, -120 }, // 60 { "European 1950 (Italy (Sicily))", E_INT_24, -97, -88, -135 }, // 61 { "European 1950 (Malta)", E_INT_24, -107, -88, -149 }, // 62 { "European 1950 (MEAN FOR Austria; Belgium; Denmark; Finland; France; W Germany; Gibraltar; Greece; Italy; Luxembourg; Netherlands; Norway; Portugal; Spain; Sweden; Switzerland)", E_INT_24, -87, -98, -121 }, // 63 { "European 1950 (MEAN FOR Austria; Denmark; France; W Germany; Netherlands; Switzerland)", E_INT_24, -87, -96, -120 }, // 64 { "European 1950 (MEAN FOR Iraq; Israel; Jordan; Lebanon; Kuwait; Saudi Arabia; Syria)", E_INT_24, -103, -106, -141 }, // 65 { "European 1950 (Portugal; Spain)", E_INT_24, -84, -107, -120 }, // 66 { "European 1950 (Tunisia)", E_INT_24, -112, -77, -145 }, // 67 { "European 1979 (MEAN FOR Austria; Finland; Netherlands; Norway; Spain; Sweden; Switzerland)", E_INT_24, -86, -98, -119 }, // 68 { "Fort Thomas 1955 (Nevis; St. Kitts (Leeward Islands))", E_CLARKE_80, -7, 215, 225 }, // 69 { "Gan 1970 (Republic of Maldives)", E_INT_24, -133, -321, 50 }, // 70 { "Geodetic Datum 1949 (New Zealand)", E_INT_24, 84, -22, 209 }, // 71 { "Graciosa Base SW 1948 (Azores (Faial; Graciosa; Pico; Sao Jorge; Terceira))", E_INT_24, -104, 167, -38 }, // 72 { "Guam 1963 (Guam)", E_CLARKE_66, -100, -248, 259 }, // 73 { "Gunung Segara (Indonesia (Kalimantan))", E_BESS_41, -403, 684, 41 }, // 74 { "GUX 1 Astro (Guadalcanal Island)", E_INT_24, 252, -209, -751 }, // 75 { "Herat North (Afghanistan)", E_INT_24, -333, -222, 114 }, // 76 { "Hermannskogel Datum (Croatia -Serbia, Bosnia-Herzegovina)", E_BESS_41_NAM, 653, -212, 449 }, // 77 { "Hjorsey 1955 (Iceland)", E_INT_24, -73, 46, -86 }, // 78 { "Hong Kong 1963 (Hong Kong)", E_INT_24, -156, -271, -189 }, // 79 { "Hu-Tzu-Shan (Taiwan)", E_INT_24, -637, -549, -203 }, // 80 { "Indian (Bangladesh)", E_EVR_IND_30, 282, 726, 254 }, // 81 { "Indian (India; Nepal)", E_EVR_IND_56, 295, 736, 257 }, // 82 { "Indian (Pakistan)", E_EVR_PAK, 283, 682, 231 }, // 83 { "Indian 1954 (Thailand)", E_EVR_IND_30, 217, 823, 299 }, // 84 { "Indian 1960 (Vietnam (Con Son Island))", E_EVR_IND_30, 182, 915, 344 }, // 85 { "Indian 1960 (Vietnam (Near 16N))", E_EVR_IND_30, 198, 881, 317 }, // 86 { "Indian 1975 (Thailand)", E_EVR_IND_30, 210, 814, 289 }, // 87 { "Indonesian 1974 (Indonesia)", E_IND_74, -24, -15, 5 }, // 88 { "Ireland 1965 (Ireland)", E_MOD_AIRY, 506, -122, 611 }, // 89 { "ISTS 061 Astro 1968 (South Georgia Islands)", E_INT_24, -794, 119, -298 }, // 90 { "ISTS 073 Astro 1969 (Diego Garcia)", E_INT_24, 208, -435, -229 }, // 91 { "Johnston Island 1961 (Johnston Island)", E_INT_24, 189, -79, -202 }, // 92 { "Kandawala (Sri Lanka)", E_EVR_IND_30, -97, 787, 86 }, // 93 { "Kerguelen Island 1949 (Kerguelen Island)", E_INT_24, 145, -187, 103 }, // 94 { "Kertau 1948 (West Malaysia & Singapore)", E_EVR_MAL_SING, -11, 851, 5 }, // 95 { "Kusaie Astro 1951 (Caroline Islands)", E_INT_24, 647, 1777, -1124 }, // 96 { "Korean Geodetic System (South Korea)", E_GRS_80, 0, 0, 0 }, // 97 { "L. C. 5 Astro 1961 (Cayman Brac Island)", E_CLARKE_66, 42, 124, 147 }, // 98 { "Leigon (Ghana)", E_CLARKE_80, -130, 29, 364 }, // 99 { "Liberia 1964 (Liberia)", E_CLARKE_80, -90, 40, 88 }, // 100 { "Luzon (Philippines (Excluding Mindanao))", E_CLARKE_66, -133, -77, -51 }, // 101 { "Luzon (Philippines (Mindanao))", E_CLARKE_66, -133, -79, -72 }, // 102 { "M'Poraloko (Gabon)", E_CLARKE_80, -74, -130, 42 }, // 103 { "Mahe 1971 (Mahe Island)", E_CLARKE_80, 41, -220, -134 }, // 104 { "Massawa (Ethiopia (Eritrea))", E_BESS_41, 639, 405, 60 }, // 105 { "Merchich (Morocco)", E_CLARKE_80, 31, 146, 47 }, // 106 { "Midway Astro 1961 (Midway Islands)", E_INT_24, 912, -58, 1227 }, // 107 { "Minna (Cameroon)", E_CLARKE_80, -81, -84, 115 }, // 108 { "Minna (Nigeria)", E_CLARKE_80, -92, -93, 122 }, // 109 { "Montserrat Island Astro 1958 (Montserrat (Leeward Islands))", E_CLARKE_80, 174, 359, 365 }, // 110 { "Nahrwan (Oman (Masirah Island))", E_CLARKE_80, -247, -148, 369 }, // 111 { "Nahrwan (Saudi Arabia)", E_CLARKE_80, -243, -192, 477 }, // 112 { "Nahrwan (United Arab Emirates)", E_CLARKE_80, -249, -156, 381 }, // 113 { "Naparima BWI (Trinidad & Tobago)", E_INT_24, -10, 375, 165 }, // 114 { "North American 1927 (Alaska (Excluding Aleutian Ids))", E_CLARKE_66, -5, 135, 172 }, // 115 { "North American 1927 (Alaska (Aleutian Ids East of 180W))", E_CLARKE_66, -2, 152, 149 }, // 116 { "North American 1927 (Alaska (Aleutian Ids West of 180W))", E_CLARKE_66, 2, 204, 105 }, // 117 { "North American 1927 (Bahamas (Except San Salvador Id))", E_CLARKE_66, -4, 154, 178 }, // 118 { "North American 1927 (Bahamas (San Salvador Island))", E_CLARKE_66, 1, 140, 165 }, // 119 { "North American 1927 (Canada (Alberta; British Columbia))", E_CLARKE_66, -7, 162, 188 }, // 120 { "North American 1927 (Canada (Manitoba; Ontario))", E_CLARKE_66, -9, 157, 184 }, // 121 { "North American 1927 (Canada (New Brunswick; Newfoundland; Nova Scotia; Quebec))", E_CLARKE_66, -22, 160, 190 }, // 122 { "North American 1927 (Canada (Northwest Territories; Saskatchewan))", E_CLARKE_66, 4, 159, 188 }, // 123 { "North American 1927 (Canada (Yukon))", E_CLARKE_66, -7, 139, 181 }, // 124 { "North American 1927 (Canal Zone)", E_CLARKE_66, 0, 125, 201 }, // 125 { "North American 1927 (Cuba)", E_CLARKE_66, -9, 152, 178 }, // 126 { "North American 1927 (Greenland (Hayes Peninsula))", E_CLARKE_66, 11, 114, 195 }, // 127 { "North American 1927 (MEAN FOR Antigua; Barbados; Barbuda; Caicos Islands; Cuba; Dominican Republic; Grand Cayman; Jamaica; Turks Islands)", E_CLARKE_66, -3, 142, 183 }, // 128 { "North American 1927 (MEAN FOR Belize; Costa Rica; El Salvador; Guatemala; Honduras; Nicaragua)", E_CLARKE_66, 0, 125, 194 }, // 129 { "North American 1927 (MEAN FOR Canada)", E_CLARKE_66, -10, 158, 187 }, // 130 { "North American 1927 (MEAN FOR CONUS)", E_CLARKE_66, -8, 160, 176 }, // 131 { "North American 1927 (MEAN FOR CONUS (East of Mississippi; River Including Louisiana; Missouri; Minnesota))", E_CLARKE_66, -9, 161, 179 }, // 132 { "North American 1927 (MEAN FOR CONUS (West of Mississippi; River Excluding Louisiana; Minnesota; Missouri))", E_CLARKE_66, -8, 159, 175 }, // 133 { "North American 1927 (Mexico)", E_CLARKE_66, -12, 130, 190 }, // 134 { "North American 1983 (Alaska (Excluding Aleutian Ids))", E_GRS_80, 0, 0, 0 }, // 135 { "North American 1983 (Aleutian Ids)", E_GRS_80, -2, 0, 4 }, // 136 { "North American 1983 (Canada)", E_GRS_80, 0, 0, 0 }, // 137 { "North American 1983 (CONUS)", E_GRS_80, 0, 0, 0 }, // 138 { "North American 1983 (Hawaii)", E_GRS_80, 1, 1, -1 }, // 139 { "North American 1983 (Mexico; Central America)", E_GRS_80, 0, 0, 0 }, // 140 { "North Sahara 1959 (Algeria)", E_CLARKE_80, -186, -93, 310 }, // 141 { "Observatorio Meteorologico 1939 (Azores (Corvo & Flores Islands))", E_INT_24, -425, -169, 81 }, // 142 { "Old Egyptian 1907 (Egypt)", E_HELM_06, -130, 110, -13 }, // 143 { "Old Hawaiian (Hawaii)", E_CLARKE_66, 89, -279, -183 }, // 144 { "Old Hawaiian (Kauai)", E_CLARKE_66, 45, -290, -172 }, // 145 { "Old Hawaiian (Maui)", E_CLARKE_66, 65, -290, -190 }, // 146 { "Old Hawaiian (MEAN FOR Hawaii; Kauai; Maui; Oahu)", E_CLARKE_66, 61, -285, -181 }, // 147 { "Old Hawaiian (Oahu)", E_CLARKE_66, 58, -283, -182 }, // 148 { "Oman (Oman)", E_CLARKE_80, -346, -1, 224 }, // 149 { "Ordnance Survey Great Britain 1936 (England)", E_AIRY_30, 371, -112, 434 }, // 150 { "Ordnance Survey Great Britain 1936 (England; Isle of Man; Wales)", E_AIRY_30, 371, -111, 434 }, // 151 { "Ordnance Survey Great Britain 1936 (MEAN FOR England; Isle of Man; Scotland; Shetland Islands; Wales)", E_AIRY_30, 375, -111, 431 }, // 152 { "Ordnance Survey Great Britain 1936 (Scotland; Shetland Islands)", E_AIRY_30, 384, -111, 425 }, // 153 { "Ordnance Survey Great Britain 1936 (Wales)", E_AIRY_30, 370, -108, 434 }, // 154 { "Pico de las Nieves (Canary Islands)", E_INT_24, -307, -92, 127 }, // 155 { "Pitcairn Astro 1967 (Pitcairn Island)", E_INT_24, 185, 165, 42 }, // 156 { "Point 58 (MEAN FOR Burkina Faso & Niger)", E_CLARKE_80, -106, -129, 165 }, // 157 { "Pointe Noire 1948 (Congo)", E_CLARKE_80, -148, 51, -291 }, // 158 { "Porto Santo 1936 (Porto Santo; Madeira Islands)", E_INT_24, -499, -249, 314 }, // 159 { "Provisional South American 1956 (Bolivia)", E_INT_24, -270, 188, -388 }, // 160 { "Provisional South American 1956 (Chile (Northern; Near 19S))", E_INT_24, -270, 183, -390 }, // 161 { "Provisional South American 1956 (Chile (Southern; Near 43S))", E_INT_24, -305, 243, -442 }, // 162 { "Provisional South American 1956 (Colombia)", E_INT_24, -282, 169, -371 }, // 163 { "Provisional South American 1956 (Ecuador)", E_INT_24, -278, 171, -367 }, // 164 { "Provisional South American 1956 (Guyana)", E_INT_24, -298, 159, -369 }, // 165 { "Provisional South American 1956 (MEAN FOR Bolivia; Chile; Colombia; Ecuador; Guyana; Peru; Venezuela)", E_INT_24, -288, 175, -376 }, // 166 { "Provisional South American 1956 (Peru)", E_INT_24, -279, 175, -379 }, // 167 { "Provisional South American 1956 (Venezuela)", E_INT_24, -295, 173, -371 }, // 168 { "Provisional South Chilean 1963 (Chile (Near 53S) (Hito XVIII))", E_INT_24, 16, 196, 93 }, // 169 { "Puerto Rico (Puerto Rico; Virgin Islands)", E_CLARKE_66, 11, 72, -101 }, // 170 { "Pulkovo 1942 (Russia)", E_KRASS_40, 28, -130, -95 }, // 171 { "Qatar National (Qatar)", E_INT_24, -128, -283, 22 }, // 172 { "Qornoq (Greenland (South))", E_INT_24, 164, 138, -189 }, // 173 { "Reunion (Mascarene Islands)", E_INT_24, 94, -948, -1262 }, // 174 { "Rome 1940 (Italy (Sardinia))", E_INT_24, -225, -65, 9 }, // 175 { "S-42 (Pulkovo 1942) (Hungary)", E_KRASS_40, 28, -121, -77 }, // 176 { "S-42 (Pulkovo 1942) (Poland)", E_KRASS_40, 23, -124, -82 }, // 177 { "S-42 (Pulkovo 1942) (Czechoslavakia)", E_KRASS_40, 26, -121, -78 }, // 178 { "S-42 (Pulkovo 1942) (Latvia)", E_KRASS_40, 24, -124, -82 }, // 179 { "S-42 (Pulkovo 1942) (Kazakhstan)", E_KRASS_40, 15, -130, -84 }, // 180 { "S-42 (Pulkovo 1942) (Albania)", E_KRASS_40, 24, -130, -92 }, // 181 { "S-42 (Pulkovo 1942) (Romania)", E_KRASS_40, 28, -121, -77 }, // 182 { "S-JTSK (Czechoslavakia (Prior 1 JAN 1993))", E_BESS_41, 589, 76, 480 }, // 183 { "Santo (DOS) 1965 (Espirito Santo Island)", E_INT_24, 170, 42, 84 }, // 184 { "Sao Braz (Azores (Sao Miguel; Santa Maria Ids))", E_INT_24, -203, 141, 53 }, // 185 { "Sapper Hill 1943 (East Falkland Island)", E_INT_24, -355, 21, 72 }, // 186 { "Schwarzeck (Namibia)", E_BESS_41_NAM, 616, 97, -251 }, // 187 { "Selvagem Grande 1938 (Salvage Islands)", E_INT_24, -289, -124, 60 }, // 188 { "Sierra Leone 1960 (Sierra Leone)", E_CLARKE_80, -88, 4, 101 }, // 189 { "South American 1969 (Argentina)", E_S_AMER_69, -62, -1, -37 }, // 190 { "South American 1969 (Bolivia)", E_S_AMER_69, -61, 2, -48 }, // 191 { "South American 1969 (Brazil)", E_S_AMER_69, -60, -2, -41 }, // 192 { "South American 1969 (Chile)", E_S_AMER_69, -75, -1, -44 }, // 193 { "South American 1969 (Colombia)", E_S_AMER_69, -44, 6, -36 }, // 194 { "South American 1969 (Ecuador)", E_S_AMER_69, -48, 3, -44 }, // 195 { "South American 1969 (Ecuador (Baltra; Galapagos))", E_S_AMER_69, -47, 26, -42 }, // 196 { "South American 1969 (Guyana)", E_S_AMER_69, -53, 3, -47 }, // 197 { "South American 1969 (MEAN FOR Argentina; Bolivia; Brazil; Chile; Colombia; Ecuador; Guyana; Paraguay; Peru; Trinidad & Tobago; Venezuela)", E_S_AMER_69, -57, 1, -41 }, // 198 { "South American 1969 (Paraguay)", E_S_AMER_69, -61, 2, -33 }, // 199 { "South American 1969 (Peru)", E_S_AMER_69, -58, 0, -44 }, // 200 { "South American 1969 (Trinidad & Tobago)", E_S_AMER_69, -45, 12, -33 }, // 201 { "South American 1969 (Venezuela)", E_S_AMER_69, -45, 8, -33 }, // 202 { "South Asia (Singapore)", E_MOD_FISCH_60, 7, -10, -26 }, // 203 { "Tananarive Observatory 1925 (Madagascar)", E_INT_24, -189, -242, -91 }, // 204 { "Timbalai 1948 (Brunei; E. Malaysia (Sabah Sarawak))", E_EVR_SAB_SAR, -679, 669, -48 }, // 205 { "Tokyo (Japan)", E_BESS_41, -148, 507, 685 }, // 206 { "Tokyo (MEAN FOR Japan; South Korea; Okinawa)", E_BESS_41, -148, 507, 685 }, // 207 { "Tokyo (Okinawa)", E_BESS_41, -158, 507, 676 }, // 208 { "Tokyo (South Korea)", E_BESS_41, -147, 506, 687 }, // 209 { "Tristan Astro 1968 (Tristan da Cunha)", E_INT_24, -632, 438, -609 }, // 210 { "Viti Levu 1916 (Fiji (Viti Levu Island))", E_CLARKE_80, 51, 391, -36 }, // 211 { "Voirol 1960 (Algeria)", E_CLARKE_80, -123, -206, 219 }, // 212 { "Wake Island Astro 1952 (Wake Atoll)", E_INT_24, 276, -57, 149 }, // 213 { "Wake-Eniwetok 1960 (Marshall Islands)", E_HOUGH_60, 102, 52, -38 }, // 214 { "WGS 1972 (Global Definition)", E_WGS_72, 0, 0, 0 }, // 215 { "WGS 1984 (Global Definition)", E_WGS_84, 0, 0, 0 }, // 216 { "Yacare (Uruguay)", E_INT_24, -155, 171, 37 }, // 217 { "Zanderij (Suriname)", E_INT_24, -265, 120, -358 } // 218 }; static const double PI = 3.14159265358979323846; /* As you can see this little function is just a 2 step datum shift, going through WGS84. */ void datum_shift(double *latitude, double *longitude, short fromDatumID, short toDatumID) { wgs84_datum_shift(TO_WGS_84, latitude, longitude, fromDatumID); wgs84_datum_shift(FROM_WGS_84, latitude, longitude, toDatumID); } /* Function to convert latitude and longitude in decimal degrees from WGS84 to another datum or from another datum to WGS84. The arguments to this function include a direction flag 'fromWGS84', pointers to double precision latitude and longitude, and an index to the gDatum[] array. */ void wgs84_datum_shift(short fromWGS84, double *latitude, double *longitude, short datumID) { double dx = gDatum[datumID].dx; double dy = gDatum[datumID].dy; double dz = gDatum[datumID].dz; double phi = *latitude * PI / 180.0; double lambda = *longitude * PI / 180.0; double a0, b0, es0, f0; /* Reference ellipsoid of input data */ // a1 and b1 are never actually used, so don't declare them and set // them (gcc warns about set-but-unused vars) //double a1, b1, es1, f1; /* Reference ellipsoid of output data */ double es1, f1; /* Reference ellipsoid of output data */ double psi; /* geocentric latitude */ double x, y, z; /* 3D coordinates with respect to original datum */ double psi1; /* transformed geocentric latitude */ if (datumID == D_WGS_84) // do nothing if current datum is WGS84 { return; } if (fromWGS84) /* convert from WGS84 to new datum */ { a0 = gEllipsoid[E_WGS_84].a; /* WGS84 semimajor axis */ f0 = 1.0 / gEllipsoid[E_WGS_84].invf; /* WGS84 flattening */ // a1 is never used except to set b1, which itself is never used // a1 = gEllipsoid[gDatum[datumID].ellipsoid].a; f1 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf; } else /* convert from datum to WGS84 */ { a0 = gEllipsoid[gDatum[datumID].ellipsoid].a; /* semimajor axis */ f0 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf; /* flattening */ // a1 is never used except to set b1, which is never used. // a1 = gEllipsoid[E_WGS_84].a; /* WGS84 semimajor axis */ f1 = 1.0 / gEllipsoid[E_WGS_84].invf; /* WGS84 flattening */ dx = -dx; dy = -dy; dz = -dz; } b0 = a0 * (1 - f0); /* semiminor axis for input datum */ es0 = 2 * f0 - f0*f0; /* eccentricity^2 */ // b1 is never used // b1 = a1 * (1 - f1); /* semiminor axis for output datum */ es1 = 2 * f1 - f1*f1; /* eccentricity^2 */ /* Convert geodedic latitude to geocentric latitude, psi */ if (*latitude == 0.0 || *latitude == 90.0 || *latitude == -90.0) { psi = phi; } else { psi = atan((1 - es0) * tan(phi)); } /* Calculate x and y axis coordinates with respect to the original ellipsoid */ if (*longitude == 90.0 || *longitude == -90.0) { x = 0.0; y = fabs(a0 * b0 / sqrt(b0*b0 + a0*a0*pow(tan(psi), 2.0))); } else { x = fabs((a0 * b0) / sqrt((1 + pow(tan(lambda), 2.0)) * (b0*b0 + a0*a0 * pow(tan(psi), 2.0)))); y = fabs(x * tan(lambda)); } if (*longitude < -90.0 || *longitude > 90.0) { x = -x; } if (*longitude < 0.0) { y = -y; } /* Calculate z axis coordinate with respect to the original ellipsoid */ if (*latitude == 90.0) { z = b0; } else if (*latitude == -90.0) { z = -b0; } else { z = tan(psi) * sqrt((a0*a0 * b0*b0) / (b0*b0 + a0*a0 * pow(tan(psi), 2.0))); } /* Calculate the geocentric latitude with respect to the new ellipsoid */ psi1 = atan((z - dz) / sqrt((x - dx)*(x - dx) + (y - dy)*(y - dy))); /* Convert to geocentric latitude and save return value */ *latitude = atan(tan(psi1) / (1 - es1)) * 180.0 / PI; /* Calculate the longitude with respect to the new ellipsoid */ *longitude = atan((y - dy) / (x - dx)) * 180.0 / PI; /* Correct the resultant for negative x values */ if (x-dx < 0.0) { if (y-dy > 0.0) { *longitude = 180.0 + *longitude; } else { *longitude = -180.0 + *longitude; } } } #define deg2rad (PI / 180) #define rad2deg (180.0 / PI) /* Source Defense Mapping Agency. 1987b. DMA Technical Report: Supplement to Department of Defense World Geodetic System 1984 Technical Report. Part I and II. Washington, DC: Defense Mapping Agency */ // // Convert lat/long to UTM/UPS coordinates void ll_to_utm_ups(short ellipsoidID, const double lat, const double lon, double *utmNorthing, double *utmEasting, char* utmZone, int utmZoneLength) { //converts lat/long to UTM coords. Equations from USGS Bulletin 1532 //East Longitudes are positive, West longitudes are negative. //North latitudes are positive, South latitudes are negative //Lat and Long are in decimal degrees //Written by Chuck Gantz- chuck.gantz@globalstar.com double a = gEllipsoid[ellipsoidID].a; double f = 1.0 / gEllipsoid[ellipsoidID].invf; double eccSquared = (2 * f) - (f * f); double k0 = 0.9996; double LongOrigin; double eccPrimeSquared; double N, T, C, A, M; //Make sure the longitude is between -180.00 .. 179.9 double LongTemp = (lon+180)-(int)((lon+180)/360)*360-180; // -180.00 .. 179.9; double LatRad = lat*deg2rad; double LongRad = LongTemp*deg2rad; double LongOriginRad; int ZoneNumber; ZoneNumber = (int)((LongTemp + 180)/6) + 1; if (coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { // Special zone for southern Norway. Used for military // version of UTM (MGRS) only. if ( lat >= 56.0 && lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 ) { ZoneNumber = 32; } // Handle the special zones for Svalbard. Used for military // version of UTM (MGRS) only. if (lat >= 72.0 && lat < 84.0) { if (LongTemp >= 0.0 && LongTemp < 9.0) { ZoneNumber = 31; } else if (LongTemp >= 9.0 && LongTemp < 21.0) { ZoneNumber = 33; } else if (LongTemp >= 21.0 && LongTemp < 33.0) { ZoneNumber = 35; } else if (LongTemp >= 33.0 && LongTemp < 42.0) { ZoneNumber = 37; } } } LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone LongOriginRad = LongOrigin * deg2rad; if (lat > 84.0 || lat < -80.0) { // We're in the UPS areas (near the poles). ZoneNumber // should not be printed in this case. xastir_snprintf(utmZone, utmZoneLength, "%c", utm_letter_designator(lat, lon)); } else // We're in the UTM areas (not near the poles). { //compute the UTM Zone from the latitude and longitude xastir_snprintf(utmZone, utmZoneLength, "%d%c", ZoneNumber, utm_letter_designator(lat, lon)); } eccPrimeSquared = (eccSquared)/(1-eccSquared); if (lat > 84.0 || lat < -80.0) { // // We're dealing with UPS coordinates (near the poles) // // The following piece of code which implements UPS // conversion is derived from code that John Waers // placed in the public domain. It's from // his program "MacGPS45". double t, e, rho; const double k0 = 0.994; double lambda = lon * (PI/180.0); double phi = fabs(lat * (PI/180.0) ); e = sqrt(eccSquared); t = tan(PI/4.0 - phi/2.0) / pow( (1.0 - e * sin(phi)) / (1.0 + e * sin(phi)), (e/2.0) ); rho = 2.0 * a * k0 * t / sqrt(pow(1.0+e, 1.0+e) * pow(1.0-e, 1.0-e)); *utmEasting = rho * sin(lambda); *utmNorthing = rho * cos(lambda); if (lat > 0.0) // Northern hemisphere { *utmNorthing = -(*utmNorthing); } *utmEasting += 2.0e6; // Add in false easting and northing *utmNorthing += 2.0e6; } else { // // We're dealing with UTM coordinates // N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad)); T = tan(LatRad)*tan(LatRad); C = eccPrimeSquared*cos(LatRad)*cos(LatRad); A = cos(LatRad)*(LongRad-LongOriginRad); M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256) * LatRad - (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024) * sin(2*LatRad) + (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024) * sin(4*LatRad) - (35*eccSquared*eccSquared*eccSquared/3072) * sin(6*LatRad)); *utmEasting = (double)(k0*N*(A+(1-T+C)*A*A*A/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120) + 500000.0); *utmNorthing = (double)(k0*(M+N*tan(LatRad)* (A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24 + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720))); if (lat < 0) { *utmNorthing += 10000000.0; //10000000 meter offset for southern hemisphere } } } // Handles UPS/UTM coordinates equally well! // char utm_letter_designator(double lat, double lon) { // This routine determines the correct UTM/UPS letter designator // for the given latitude. Originally written by Chuck Gantz- // chuck.gantz@globalstar.com // Modified to handle UPS zones. --we7u char LetterDesignator; if ((84 >= lat) && (lat >= 72)) { LetterDesignator = 'X'; } else if ((72 > lat) && (lat >= 64)) { LetterDesignator = 'W'; } else if ((64 > lat) && (lat >= 56)) { LetterDesignator = 'V'; } else if ((56 > lat) && (lat >= 48)) { LetterDesignator = 'U'; } else if ((48 > lat) && (lat >= 40)) { LetterDesignator = 'T'; } else if ((40 > lat) && (lat >= 32)) { LetterDesignator = 'S'; } else if ((32 > lat) && (lat >= 24)) { LetterDesignator = 'R'; } else if ((24 > lat) && (lat >= 16)) { LetterDesignator = 'Q'; } else if ((16 > lat) && (lat >= 8)) { LetterDesignator = 'P'; } else if (( 8 > lat) && (lat >= 0)) { LetterDesignator = 'N'; } else if (( 0 > lat) && (lat >= -8)) { LetterDesignator = 'M'; } else if ((-8 > lat) && (lat >= -16)) { LetterDesignator = 'L'; } else if ((-16 > lat) && (lat >= -24)) { LetterDesignator = 'K'; } else if ((-24 > lat) && (lat >= -32)) { LetterDesignator = 'J'; } else if ((-32 > lat) && (lat >= -40)) { LetterDesignator = 'H'; } else if ((-40 > lat) && (lat >= -48)) { LetterDesignator = 'G'; } else if ((-48 > lat) && (lat >= -56)) { LetterDesignator = 'F'; } else if ((-56 > lat) && (lat >= -64)) { LetterDesignator = 'E'; } else if ((-64 > lat) && (lat >= -72)) { LetterDesignator = 'D'; } else if ((-72 > lat) && (lat >= -80)) { LetterDesignator = 'C'; } else { // // We're dealing with UPS (N/S Pole) coordinates, not UTM // if (lat > 84) // North Pole, Y/Z zones { if ((0 <= lon) && (lon <= 180)) { LetterDesignator = 'Z'; // E or + longitude } else { LetterDesignator = 'Y'; // W or - longitude } } else // Lat < 80S, South Pole, A/B zones { if ((0 <= lon) && (lon <= 180)) { LetterDesignator = 'B'; // E or + longitude } else { LetterDesignator = 'A'; // W or - longitude } } } return LetterDesignator; } // The following piece of code which implements UPS conversion is // derived from code that John Waers placed in // the public domain. It's from his program "MacGPS45". // static void calcPhi(double *phi, double e, double t) { double old = PI/2.0 - 2.0 * atan(t); short maxIterations = 20; while ( (fabs((*phi - old) / *phi) > 1.0e-8) && maxIterations-- ) { old = *phi; *phi = PI/ 2.0 - 2.0 * atan( t * pow((1.0 - e * sin(*phi)) / ((1.0 + e * sin(*phi))), (e / 2.0)) ); } } // Converts from UTM/UPS coordinates to Lat/Long coordinates. // void utm_ups_to_ll(short ellipsoidID, const double utmNorthing, const double utmEasting, const char* utmZone, double *lat, double *lon) { // Converts UTM coords to lat/long. Equations from USGS // Bulletin 1532. East Longitudes are positive, West longitudes // are negative. North latitudes are positive, South latitudes // are negative Lat and Long are in decimal degrees. // Written by Chuck Gantz- chuck.gantz@globalstar.com // Modified by WE7U to add UPS support. double k0 = 0.9996; double a = gEllipsoid[ellipsoidID].a; double f = 1.0 / gEllipsoid[ellipsoidID].invf; double eccSquared = (2 * f) - (f * f); double eccPrimeSquared; double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared)); double N1, T1, C1, R1, D, M; double LongOrigin; // phi1 is never used, but is set. Don't make gcc warn us // double mu, phi1, phi1Rad; double mu, phi1Rad; double x, y; int ZoneNumber; char* ZoneLetter; // Unused variable // int NorthernHemisphere; // 1=northern hemisphere, 0=southern //fprintf(stderr,"%s %f %f\n", // utmZone, // utmEasting, // utmNorthing); x = utmEasting; y = utmNorthing; ZoneNumber = strtoul(utmZone, &ZoneLetter, 10); // Remove any possible leading spaces remove_leading_spaces(ZoneLetter); // Make sure the zone letter is upper-case *ZoneLetter = toupper(*ZoneLetter); //fprintf(stderr,"ZoneLetter: %s\n", ZoneLetter); if ( *ZoneLetter == 'Y' // North Pole || *ZoneLetter == 'Z' // North Pole || *ZoneLetter == 'A' // South Pole || *ZoneLetter == 'B') // South Pole { // The following piece of code which implements UPS // conversion is derived from code that John Waers // placed in the public domain. It's from // his program "MacGPS45". // // We're dealing with a UPS coordinate (near the poles) // instead of a UTM coordinate. We need to do entirely // different calculations for UPS. // double e, t, rho; const double k0 = 0.994; //fprintf(stderr,"UPS Coordinates\n"); e = sqrt(eccSquared); x -= 2.0e6; // Remove false easting and northing y -= 2.0e6; rho = sqrt(x*x + y*y); t = rho * sqrt(pow(1.0+e, 1.0+e) * pow(1.0-e, 1.0-e)) / (2.0 * a * k0); calcPhi(lat, e, t); *lat /= (PI/180.0); // This appears to be necessary in order to get proper // positions in the south polar region if (*ZoneLetter == 'A' || *ZoneLetter == 'B') { *lat = -*lat; } if (y != 0.0) { t = atan(fabs(x/y)); } else { t = PI / 2.0; if (x < 0.0) { t = -t; } } if (*ZoneLetter == 'Z' || *ZoneLetter == 'Y') { y = -y; // Northern hemisphere } if (y < 0.0) { t = PI - t; } if (x < 0.0) { t = -t; } *lon = t / (PI/180.0); /* fprintf(stderr,"datum.c:utm_ups_to_ll(): Found UPS Coordinate: %s %f %f\n", utmZone, utmEasting, utmNorthing); */ return; // Done computing UPS coordinates } // If we make it here, we're working on UTM coordinates (not // UPS coordinates). x = utmEasting - 500000.0; //remove 500,000 meter offset for longitude y = utmNorthing; if ((*ZoneLetter - 'N') >= 0) { // We never use this variable // NorthernHemisphere = 1;//point is in northern hemisphere } else { // we never use NorthernHemisphere // NorthernHemisphere = 0;//point is in southern hemisphere y -= 10000000.0;//remove 10,000,000 meter offset used for southern hemisphere } LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone eccPrimeSquared = (eccSquared)/(1-eccSquared); M = y / k0; mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64-5*eccSquared*eccSquared*eccSquared/256)); phi1Rad = mu + (3*e1/2-27*e1*e1*e1/32)*sin(2*mu) + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu) + (151*e1*e1*e1/96)*sin(6*mu); // This variable is never used, it is just phi1Rad converted to degrees // phi1 = phi1Rad*rad2deg; N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad)); T1 = tan(phi1Rad)*tan(phi1Rad); C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad); R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5); D = x/(N1*k0); *lat = phi1Rad - (N1*tan(phi1Rad)/R1)*(D*D/2-(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24 +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared-3*C1*C1)*D*D*D*D*D*D/720); *lat *= rad2deg; *lon = (D-(1+2*T1+C1)*D*D*D/6+(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1) *D*D*D*D*D/120)/cos(phi1Rad); *lon = LongOrigin + (*lon) * rad2deg; } Xastir-Release-2.2.2/src/datum.h000066400000000000000000000061641501463444000164270ustar00rootroot00000000000000/* Portions Copyright (C) 2000-2023 The Xastir Group The datum conversion code here and in datum.c is from MacGPS 45. According to the Read_Me file in the source archive of that program, the author says the following: "I've read the legalese statements that everyone attaches to works like this, but I can never remember what they say. Suffice it to say that I am releasing this source code to the public domain, and you are free to do with it what you like. If you find it of some use and include any of it in an application, credits (and perhaps a copy of your program, if your feel so inclined) would be appreciated. John F. Waers " If you ever read this, John, thanks for the code and feel free to try out Xastir, it's free. The UTM to/from Lat/Long translations were written by Chuck Gantz . Curt Mills received permission via e-mail to release the code under the GPL for a conversion he did to perl. I deduce from this that including it in Xastir, a GPL program is no problem. Thanks Chuck! N7TAP */ // Equatorial radius of the Earth. In our distance/angular/area // calculations (not here in datum.h/datum.c, but elsewhere in the // code) we currently ignore flattening as you go towards the poles. // // The datum translation code in datum.h/datum.c doesn't use these // three defines at all: That code uses ellipsoids and so // flattening is accounted for there. #define EARTH_RADIUS_METERS 6378138.0 #define EARTH_RADIUS_KILOMETERS 6378.138 #define EARTH_RADIUS_MILES 3963.1836 #define FROM_WGS_84 1 #define TO_WGS_84 0 void wgs84_datum_shift(short fromWGS84, double *latitude, double *longitude, short datumID); void datum_shift(double *latitude, double *longitude, short fromDatumID, short toDatumID); typedef struct { char *name; // name of ellipsoid double a; // semi-major axis, meters double invf; // 1/f } Ellipsoid; extern const Ellipsoid gEllipsoid[]; enum Ellipsoid_Names // Must match the order of the Ellipsoids defined in datum.c { E_AIRY_30, E_MOD_AIRY, E_AUS_NAT, E_BESS_41, E_BESS_41_NAM, E_CLARKE_66, E_CLARKE_80, E_EVR_IND_30, E_EVR_IND_56, E_EVR_SAB_SAR, E_EVR_MAL_69, E_EVR_MAL_SING, E_EVR_PAK, E_FISCH_60_MERC, E_MOD_FISCH_60, E_FISCH_68, E_HELM_06, E_HOUGH_60, E_IND_74, E_INT_24, E_KRASS_40, E_GRS_67, E_GRS_80, E_S_AMER_69, E_WGS_60, E_WGS_66, E_WGS_72, E_WGS_84 }; typedef struct { char *name; short ellipsoid; short dx; short dy; short dz; } Datum; extern const Datum gDatum[]; enum Common_Datum_Names // Must match the indices of the Datums defined in datum.c { D_NAD_27_CONUS = 131, D_NAD_83_CONUS = 138, D_WGS_72 = 215, D_WGS_84 = 216 }; void ll_to_utm_ups(short ellipsoidID, const double lat, const double lon, double *utmNorthing, double *utmEasting, char* utmZone, int utmZoneLength); void utm_ups_to_ll(short ellipsoidID, const double utmNorthing, const double utmEasting, const char* utmZone, double *lat, double *lon); char utm_letter_designator(double lat, double lon); Xastir-Release-2.2.2/src/db.c000066400000000000000000024544541501463444000157100ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Note: the header file for db.c should be called db.h, * but is named database.h to avoid conflicts with the * Berkeley DB package. */ // NOTE: decode_info_field() is a good place to start for decoding. // Used only for special debugging of message/station expiration. // Leave commented out for normal operation. //#define EXPIRE_DEBUG #define DEBUG_MESSAGE_REMOVE_CYCLE 15 #define DEBUG_STATION_REMOVE_CYCLE 15 #define DEBUG_MESSAGE_REMOVE 600 #define DEBUG_STATION_REMOVE 600 #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "draw_symbols.h" #include "alert.h" #include "util.h" #include "bulletin_gui.h" #include "fcc_data.h" #include "geo.h" #include "gps.h" #include "rac_data.h" #include "interface.h" #include "maps.h" #include "wx.h" #include "igate.h" #include "list_gui.h" #include "objects.h" #include "track_gui.h" #include "xa_config.h" #include "x_spider.h" #include "db_gis.h" // Must be last include file #include "leak_detection.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #define STATION_REMOVE_CYCLE 300 /* check station remove in seconds (every 5 minutes) */ #define MESSAGE_REMOVE_CYCLE 600 /* check message remove in seconds (every 10 minutes) */ #define IN_VIEW_MIN 600l /* margin for off-screen stations, with possible trails on screen, in minutes */ #define TRAIL_POINT_MARGIN 30l /* margin for off-screen trails points, for segment to be drawn, in minutes */ #define TRAIL_MAX_SPEED 900 /* max. acceptable speed for drawing trails, in mph */ #define MY_TRAIL_COLOR 0x16 /* trail color index reserved for my station */ #define TRAIL_ECHO_TIME 30 /* check for delayed echos during last 30 minutes */ /* MY_TRAIL_DIFF_COLOR changed to user configurable my_trail_diff_color */ ///////////////////////////////////// #define GUARD_SIZE 10 char GUARD_BAND_THREE[GUARD_SIZE]; ///////////////////////////////////// extern XmFontList fontlist1; // Menu/System fontlist // Station Info Widget db_station_popup = (Widget)NULL; char *db_station_info_callsign = NULL; Pixmap SiS_icon0, SiS_icon; Widget SiS_symb; Widget station_list; Widget button_store_track; int station_data_auto_update = 0; // Used to store all the calls we might "relay" digipeat by. // Separated by commas. Up to 50 callsigns of 9 chars each plus // comma delimiters. char relay_digipeater_calls[10*MAX_RELAY_DIGIPEATER_CALLS]; Widget si_text; Widget db_station_info = (Widget)NULL; static xastir_mutex db_station_info_lock; static xastir_mutex db_station_popup_lock; void redraw_symbols(Widget w); int delete_weather(DataRow *fill); int delete_multipoints(DataRow *fill); void Station_data_destroy_track(Widget widget, XtPointer clientData, XtPointer callData); void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char speedu, char *alt, char *sats); void station_shortcuts_update_function(int hash_key, DataRow *p_rem); int position_on_extd_screen(long lat, long lon); int extract_speed_course(char *info, char *speed, char *course); int extract_bearing_NRQ(char *info, char *bearing, char *nrq); int skip_dupe_checking; int tracked_stations = 0; // A count variable used in debug code only void track_station(Widget w, char *call_tracked, DataRow *p_station); int new_message_data; time_t last_message_remove; // last time we did a check for message removing //////////////////////////////////// char GUARD_BAND_FOUR[GUARD_SIZE]; //////////////////////////////////// //// Save most recent 100 packets in an array called packet_data_string[] #define MAX_PACKET_DATA_DISPLAY 100 int redraw_on_new_packet_data; char packet_data_string[MAX_PACKET_DATA_DISPLAY][MAX_LINE_SIZE+1]; int first_line=-1; int next_line=0; int ncharsdel=0; int nlinesadd=0; /////////////////////////////////// char GUARD_BAND_ONE[GUARD_SIZE]; /////////////////////////////////// int station_count; // number of stored stations int station_count_save = 0; // old copy of above DataRow *n_first; // pointer to first element in name sorted station list DataRow *n_last; // pointer to last element in name sorted station list DataRow *t_oldest; // pointer to first element in time sorted station list (oldest) DataRow *t_newest; // pointer to last element in time sorted station list (newest) time_t last_station_remove; // last time we did a check for station removing time_t last_sec,curr_sec; // for comparing if seconds in time have changed int next_time_sn; // time serial number for unique time index /////////////////////////////////// char GUARD_BAND_TWO[GUARD_SIZE]; /////////////////////////////////// int emergency_distance_check = 1; float emergency_range = 280.0; // Default is 4hrs @ 70mph distance CADRow *CAD_list_head = NULL; // pointer to first element in CAD objects list void draw_trail(Widget w, DataRow *fill, int solid); void export_trail(DataRow *p_station); // export trail of one or all stations to xastir export file //void export_trail_as_kml(DataRow *p_station); // export trail of one or all stations to kml file int decoration_offset_x = 0; int decoration_offset_y = 0; int last_station_info_x = 0; int last_station_info_y = 0; int fcc_lookup_pushed = 0; int rac_lookup_pushed = 0; time_t last_object_check = 0; // Used to determine when to re-transmit objects/items time_t last_emergency_time = 0; char last_emergency_callsign[MAX_CALLSIGN+1]; int st_direct_timeout = 60 * 60; // 60 minutes. // Used in search_station_name() function. Shortcuts into the // station list based on the least-significant 7 bits of the first // two letters of the callsign/object name. DataRow *station_shortcuts[16384]; // used to time aloha calculations static time_t aloha_time = 0; static time_t aloha_status_time = 0; static double aloha_radius=-1; // in miles static aloha_stats the_aloha_stats; // calculate every half hour, display in status line every 5 minutes #define ALOHA_CALC_INTERVAL 1800 #define ALOHA_STATUS_INTERVAL 300 int process_emergency_packet_again = 0; void db_init(void) { int ii; // Set up guard bands around important global pointers for (ii = 0; ii < GUARD_SIZE; ii++) { GUARD_BAND_ONE[ii] = 0x00; GUARD_BAND_TWO[ii] = 0x00; GUARD_BAND_THREE[ii] = 0x00; GUARD_BAND_FOUR[ii] = 0x00; } init_critical_section( &db_station_info_lock ); init_critical_section( &db_station_popup_lock ); last_emergency_callsign[0] = '\0'; // Seed the random number generator srand(1); } /////////////////////////////////// Utilities //////////////////////////////////////////////////// // Variable used for below test code //int we7u_count = 50; // Check guard bands around important global pointers. // // These guard bands are initialized in db.c:db_init() // // Returns: 0 if ok // 1 if guard band has been tampered with // int check_guard_band(void) { int ii; for (ii = 0; ii < GUARD_SIZE; ii++) { if (GUARD_BAND_ONE[ii] != 0x00 || GUARD_BAND_TWO[ii] != 0x00 || GUARD_BAND_THREE[ii] != 0x00 || GUARD_BAND_FOUR[ii] != 0x00) { if (GUARD_BAND_ONE[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_ONE was corrupted!\n"); } if (GUARD_BAND_TWO[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_TWO was corrupted!\n"); } if (GUARD_BAND_THREE[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_THREE was corrupted!\n"); } if (GUARD_BAND_FOUR[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_FOUR was corrupted!\n"); } fprintf(stderr, "Previous incoming line was: %s\n", incoming_data_copy_previous); fprintf(stderr, " Last incoming line was: %s\n", incoming_data_copy); abort(); // Cause immediate exit to aid in debugging return(1); } } // Test code /* if (we7u_count-- <= 0) { GUARD_BAND_ONE[0] = 0x01; GUARD_BAND_TWO[0] = 0x01; GUARD_BAND_THREE[0] = 0x01; GUARD_BAND_FOUR[0] = 0x01; } */ return(0); } /* * Check whether callsign is mine. "exact == 1" checks the SSID * for a match as well. "exact == 0" checks only the base * callsign. */ int is_my_call(char *call, int exact) { char *p_del; int ok; // U.S. special-event callsigns can be as short as three // characters, any less and we don't have a valid callsign. We // don't check for that restriction here though. if (exact) { // We're looking for an exact match ok = (int)( !strcmp(call,my_callsign) ); //fprintf(stderr,"My exact call found: %s\n",call); } else { // We're looking for a similar match. Compare only up to // the '-' in each (if present). int len1,len2; p_del = index(call,'-'); if (p_del == NULL) { len1 = (int)strlen(call); } else { len1 = p_del - call; } p_del = index(my_callsign,'-'); if (p_del == NULL) { len2 = (int)strlen(my_callsign); } else { len2 = p_del - my_callsign; } ok = (int)(len1 == len2 && !strncmp(call,my_callsign,(size_t)len1)); //fprintf(stderr,"My base call found: %s\n",call); } return(ok); } int is_my_station(DataRow *p_station) { // if station is owned by me (including SSID) return(p_station->flag & ST_MYSTATION); } int is_my_object_item(DataRow *p_station) { // If object/item is owned by me (including SSID) return(p_station->flag & ST_MYOBJITEM); } /* * Change map position if necessary while tracking a station * we call it with defined station call and position */ int is_tracked_station(char *call_sign) { int found; char call_find[MAX_CALLSIGN+1]; int ii; int call_len; if (!track_station_on) { return(0); } call_len = 0; found = 0; if (!track_case) { for ( ii = 0; ii < (int)strlen(tracking_station_call); ii++ ) { if (isalpha((int)tracking_station_call[ii])) { call_find[ii] = toupper((int)tracking_station_call[ii]); } else { call_find[ii] = tracking_station_call[ii]; } } call_find[ii] = '\0'; } else { memcpy(call_find, tracking_station_call, sizeof(call_find)); call_find[sizeof(call_find)-1] = '\0'; // Terminate string } if (debug_level & 256) { fprintf(stderr,"is_tracked_station(): CALL %s %s %s\n", tracking_station_call, call_find, call_sign); } if (track_match) { if (strcmp(call_find,call_sign) == 0) // we want an exact match { found = 1; } } else { found = 0; call_len = (int)(strlen(call_sign) - strlen(call_find)); if (strlen(call_find) <= strlen(call_sign)) { found = 1; for ( ii = 0; ii <= call_len; ii++ ) { if (!track_case) { if (strncasecmp(call_find,call_sign+ii,strlen(call_find)) != 0) { found = 0; // Found a mis-match } } else { if (strncmp(call_find,call_sign+ii,strlen(call_find)) != 0) { found = 0; } } } } } return(found); } /////////////////////////////////////////// Messages /////////////////////////////////////////// static long *msg_index; static long msg_index_end; static long msg_index_max; static Message *msg_data; // Array containing all messages, // including ones we've transmitted (via // loopback in the code) time_t last_message_update = 0; ack_record *ack_list_head = NULL; // Head of linked list storing most recent ack's int satellite_ack_mode; // How often update_messages() will run, in seconds. // This is necessary because routines like UpdateTime() // call update_messages() VERY OFTEN. // // Actually, we just changed the code around so that we only call // update_messages() with the force option, and only when we receive a // message. message_update_delay is no longer used, and we don't call // update_messages() from UpdateTime() anymore. static int message_update_delay = 300; // Saves latest ack in a linked list. We need this value in order // to use Reply/Ack protocol when sending out messages. void store_most_recent_ack(char *callsign, char *ack) { ack_record *p; int done = 0; char call[MAX_CALLSIGN+1]; char new_ack[5+1]; xastir_snprintf(call, sizeof(call), "%s", callsign); remove_trailing_spaces(call); // Get a copy of "ack". We might need to change it. xastir_snprintf(new_ack, sizeof(new_ack), "%s", ack); // If it's more than 2 characters long, we can't use it for // Reply/Ack protocol as there's only space enough for two. // In this case we need to make sure that we blank out any // former ack that was 1 or 2 characters, so that communications // doesn't stop. if ( strlen(new_ack) > 2 ) { // It's too long, blank it out so that gets saved as "", // which will overwrite any previously saved ack's that were // short enough to use. new_ack[0] = '\0'; } // Search for matching callsign through linked list p = ack_list_head; while ( !done && (p != NULL) ) { if (strcasecmp(call,p->callsign) == 0) { done++; } else { p = p->next; } } if (done) // Found it. Update the ack field. { //fprintf(stderr,"Found callsign %s on recent ack list, Old:%s, New:%s\n",call,p->ack,new_ack); xastir_snprintf(p->ack,sizeof(p->ack),"%s",new_ack); } else // Not found. Add a new record to the beginning of the { // list. //fprintf(stderr,"New callsign %s, adding to list. Ack: %s\n",call,new_ack); p = (ack_record *)malloc(sizeof(ack_record)); CHECKMALLOC(p); xastir_snprintf(p->callsign,sizeof(p->callsign),"%s",call); xastir_snprintf(p->ack,sizeof(p->ack),"%s",new_ack); p->next = ack_list_head; ack_list_head = p; } } // Gets latest ack by callsign char *get_most_recent_ack(char *callsign) { ack_record *p; int done = 0; char call[MAX_CALLSIGN+1]; xastir_snprintf(call, sizeof(call), "%s", callsign); remove_trailing_spaces(call); // Search for matching callsign through linked list p = ack_list_head; while ( !done && (p != NULL) ) { if (strcasecmp(call,p->callsign) == 0) { done++; } else { p = p->next; } } if (done) // Found it. Return pointer to ack string. { //fprintf(stderr,"Found callsign %s on linked list, returning ack: %s\n",call,p->ack); return(&p->ack[0]); } else { //fprintf(stderr,"Callsign %s not found\n",call); return(NULL); } } void init_message_data(void) // called at start of main { new_message_data = 0; last_message_remove = sec_now(); } #ifdef MSG_DEBUG void msg_clear_data(Message *clear) { int size; int i; unsigned char *data_ptr; data_ptr = (unsigned char *)clear; size=sizeof(Message); for(i=0; i (last_message_update + message_update_delay) ) { return(1); } else { return(0); } } int msg_comp_active(const void *a, const void *b) { char temp_a[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+2]; char temp_b[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+2]; xastir_snprintf(temp_a, sizeof(temp_a), "%c%s%s%s", ((Message*)a)->active, ((Message*)a)->call_sign, ((Message*)a)->from_call_sign, ((Message*)a)->seq); xastir_snprintf(temp_b, sizeof(temp_b), "%c%s%s%s", ((Message*)b)->active, ((Message*)b)->call_sign, ((Message*)b)->from_call_sign, ((Message*)b)->seq); return(strcmp(temp_a, temp_b)); } int msg_comp_data(const void *a, const void *b) { char temp_a[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; char temp_b[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; xastir_snprintf(temp_a, sizeof(temp_a), "%s%s%s", msg_data[*(long*)a].call_sign, msg_data[*(long *)a].from_call_sign, msg_data[*(long *)a].seq); xastir_snprintf(temp_b, sizeof(temp_b), "%s%s%s", msg_data[*(long*)b].call_sign, msg_data[*(long *)b].from_call_sign, msg_data[*(long *)b].seq); return(strcmp(temp_a, temp_b)); } void msg_input_database(Message *m_fill) { void *m_ptr; long i; if (msg_index_end == msg_index_max) { for (i = 0; i < msg_index_end; i++) { // Check for a record that is marked RECORD_NOTACTIVE. // If found, use that record instead of malloc'ing a new // one. if (msg_data[msg_index[i]].active == RECORD_NOTACTIVE) { // Found an unused record. Fill it in. memcpy(&msg_data[msg_index[i]], m_fill, sizeof(Message)); // Sort msg_data qsort(msg_data, (size_t)msg_index_end, sizeof(Message), msg_comp_active); for (i = 0; i < msg_index_end; i++) { msg_index[i] = i; if (msg_data[i].active == RECORD_NOTACTIVE) { msg_index_end = i; break; } } // Sort msg_index qsort(msg_index, (size_t)msg_index_end, sizeof(long *), msg_comp_data); // All done with this message. return; } } // Didn't find free message record. Fetch some more space. // Get more msg_data space. m_ptr = realloc(msg_data, (msg_index_max+MSG_INCREMENT)*sizeof(Message)); if (m_ptr) { msg_data = m_ptr; // Get more msg_index space m_ptr = realloc(msg_index, (msg_index_max+MSG_INCREMENT)*sizeof(Message *)); if (m_ptr) { msg_index = m_ptr; msg_index_max += MSG_INCREMENT; //fprintf(stderr, "Max Message Array: %ld\n", msg_index_max); } else { XtWarning("Unable to allocate more space for message index.\n"); } } else { XtWarning("Unable to allocate more space for message database.\n"); } } if (msg_index_end < msg_index_max) { msg_index[msg_index_end] = msg_index_end; // Copy message data into new message record. memcpy(&msg_data[msg_index_end++], m_fill, sizeof(Message)); // Sort msg_index qsort(msg_index, (size_t)msg_index_end, sizeof(long *), msg_comp_data); } } // Does a binary search through a sorted message database looking // for a string match. // // If two or more messages match, this routine _should_ return the // message with the latest timestamp. This will ensure that earlier // messages don't get mistaken for current messages, for the case // where the remote station did a restart and is using the same // sequence numbers over again. // long msg_find_data(Message *m_fill) { long record_start, record_mid, record_end, return_record, done; char tempfile[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; char tempfill[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; xastir_snprintf(tempfill, sizeof(tempfill), "%s%s%s", m_fill->call_sign, m_fill->from_call_sign, m_fill->seq); return_record = -1L; if (msg_index && msg_index_end >= 1) { /* more than one record */ record_start=0L; record_end = (msg_index_end - 1); record_mid=(record_end-record_start)/2; done=0; while (!done) { /* get data for record start */ xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_start]].call_sign, msg_data[msg_index[record_start]].from_call_sign, msg_data[msg_index[record_start]].seq); if (strcmp(tempfill, tempfile) < 0) { /* filename comes before */ /*fprintf(stderr,"Before No data found!!\n");*/ done=1; break; } else /* get data for record end */ { xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_end]].call_sign, msg_data[msg_index[record_end]].from_call_sign, msg_data[msg_index[record_end]].seq); if (strcmp(tempfill,tempfile)>=0) /* at end or beyond */ { if (strcmp(tempfill, tempfile) == 0) { return_record = record_end; //fprintf(stderr,"record %ld",return_record); } done=1; break; } else if ((record_mid == record_start) || (record_mid == record_end)) { /* no mid for compare check to see if in the middle */ done=1; xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_mid]].call_sign, msg_data[msg_index[record_mid]].from_call_sign, msg_data[msg_index[record_mid]].seq); if (strcmp(tempfill,tempfile)==0) { return_record = record_mid; //fprintf(stderr,"record: %ld",return_record); } } } if (!done) /* get data for record mid */ { xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_mid]].call_sign, msg_data[msg_index[record_mid]].from_call_sign, msg_data[msg_index[record_mid]].seq); if (strcmp(tempfill, tempfile) == 0) { return_record = record_mid; //fprintf(stderr,"record %ld",return_record); done = 1; break; } if(strcmp(tempfill, tempfile)<0) { record_end = record_mid; } else { record_start = record_mid; } record_mid = record_start+(record_end-record_start)/2; } } } return(return_record); } void msg_replace_data(Message *m_fill, long record_num) { memcpy(&msg_data[msg_index[record_num]], m_fill, sizeof(Message)); } void msg_get_data(Message *m_fill, long record_num) { memcpy(m_fill, &msg_data[msg_index[record_num]], sizeof(Message)); } void msg_update_ack_stamp(long record_num) { //fprintf(stderr,"Attempting to update ack stamp: %ld\n",record_num); if ( (record_num >= 0) && (record_num < msg_index_end) ) { msg_data[msg_index[record_num]].last_ack_sent = sec_now(); //fprintf(stderr,"Ack stamp: %ld\n",msg_data[msg_index[record_num]].last_ack_sent); } //fprintf(stderr,"\n\n\n*** Record: %ld ***\n\n\n",record_num); } // Called when we receive an ACK. Sets the "acked" field in a // Message which gets rid of the highlighting in the Send Message // dialog for that message line. This lets us know which messages // have been acked and which have not. If timeout is non-zero, then // set acked to 2: We use this in update_messages() to flag that // "*TIMEOUT*" should prefix the string. If cancelled is non-zero, // set acked to 3: We use this in update_messages() to flag that // "*CANCELLED*" should prefix the string. // void msg_record_ack(char *to_call_sign, char *my_call, char *seq, int timeout, int cancel) { Message m_fill; long record; int do_update = 0; if (debug_level & 1) { fprintf(stderr,"Recording ack for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i], set the // "acked" field to one. substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if (record == -1L) // No match yet, try another tactic. { if (seq[2] == '}' && strlen(seq) == 3) { // Try it again without the trailing '}' character m_fill.from_call_sign[2] = '\0'; // Look for a message with the same to_call_sign, // my_call, and seq number (minus the trailing '}') record = msg_find_data(&m_fill); } } if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 1, seq %s, record %ld\n", msg_data[msg_index[record]].acked, seq, record); } // Only cause an update if this is the first ack. This // reduces dialog "flashing" a great deal if ( msg_data[msg_index[record]].acked == 0 ) { // Check for my callsign (including SSID). If found, // update any open message dialogs if (is_my_call(msg_data[msg_index[record]].from_call_sign, 1) ) { //fprintf(stderr,"From: %s\tTo: %s\n", // msg_data[msg_index[record]].from_call_sign, // msg_data[msg_index[record]].call_sign); do_update++; } } else // This message has already been acked. { } if (cancel) { msg_data[msg_index[record]].acked = (char)3; } else if (timeout) { msg_data[msg_index[record]].acked = (char)2; } else { msg_data[msg_index[record]].acked = (char)1; } // Set the interval to zero so that we don't display it // anymore in the dialog. Same for tries. msg_data[msg_index[record]].interval = 0; msg_data[msg_index[record]].tries = 0; if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 1, seq %s, record %ld\n\n", msg_data[msg_index[record]].acked, seq, record); } } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } if (do_update) { update_messages(1); // Force an update // Call check_popup_messages() here in order to pop up any // closed Send Message dialogs. For first ack's or // CANCELLED messages it is less important, but for TIMEOUT // messages it is very important. // (void)check_popup_window(m_fill.call_sign, 2); // Calls update_messages() } } // Called when we receive a REJ packet (reject). Sets the "acked" // field in a Message to 4 to indicate that the message has been // rejected by the remote station. This gets rid of the // highlighting in the Send Message dialog for that message line. // This lets us know which messages have been rejected and which // have not. We use this in update_messages() to flag that // "*REJECTED*" should prefix the string. // // The most common source of REJ packets would be from sending to a // D700A who's buffers are full, so that it can't take another // message. // void msg_record_rej(char *to_call_sign, char *my_call, char *seq) { Message m_fill; long record; int do_update = 0; if (debug_level & 1) { fprintf(stderr,"Recording rej for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i], set the // "acked" field to four. substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if (record == -1L) // No match yet, try another tactic. { if (seq[2] == '}' && strlen(seq) == 3) { // Try it again without the trailing '}' character m_fill.from_call_sign[2] = '\0'; // Look for a message with the same to_call_sign, // my_call, and seq number (minus the trailing '}') record = msg_find_data(&m_fill); } } if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 4, seq %s, record %ld\n", msg_data[msg_index[record]].acked, seq, record); } // Only cause an update if this is the first rej. This // reduces dialog "flashing" a great deal if ( msg_data[msg_index[record]].acked == 0 ) { // Check for my callsign (including SSID). If found, // update any open message dialogs if (is_my_call(msg_data[msg_index[record]].from_call_sign, 1) ) { //fprintf(stderr,"From: %s\tTo: %s\n", // msg_data[msg_index[record]].from_call_sign, // msg_data[msg_index[record]].call_sign); do_update++; } } else // This message has already been acked. { } // Actually record the REJ here msg_data[msg_index[record]].acked = (char)4; // Set the interval to zero so that we don't display it // anymore in the dialog. Same for tries. msg_data[msg_index[record]].interval = 0; msg_data[msg_index[record]].tries = 0; if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 4, seq %s, record %ld\n\n", msg_data[msg_index[record]].acked, seq, record); } } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } if (do_update) { update_messages(1); // Force an update // Call check_popup_messages() here in order to pop up any // closed Send Message dialogs. For first ack's or // CANCELLED messages it is less important, but for TIMEOUT // messages it is very important. // (void)check_popup_window(m_fill.call_sign, 2); // Calls update_messages() } } // Called from check_and_transmit_messages(). Updates the interval // field in our message record for the message currently being // transmitted. We'll use this in the Send Message dialog to // display the current message interval. // void msg_record_interval_tries(char *to_call_sign, char *my_call, char *seq, time_t interval, int tries) { Message m_fill; long record; if (debug_level & 1) { fprintf(stderr,"Recording interval for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i] substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr, "Found in msg db, updating interval field %ld -> 1, seq %s, record %ld\n", (long)msg_data[msg_index[record]].interval, seq, record); } msg_data[msg_index[record]].interval = interval; msg_data[msg_index[record]].tries = tries; } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } update_messages(1); // Force an update } // Returns: time_t for last_ack_sent // -1 if the message doesn't pass our tests // 0 if it is a new message. // // Also returns the record number found if not passed a NULL pointer // in record_out or -1L if it's a new record. // time_t msg_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from, long *record_out) { Message m_fill; long record; char time_data[MAX_TIME]; int do_msg_update = 0; time_t last_ack_sent; int distance = -1; char temp[10]; int group_message = 0; if (debug_level & 1) { fprintf(stderr,"msg_data_add start\n"); } //fprintf(stderr,"from:%s, to:%s, seq:%s\n", from_call, call_sign, seq); // Set the default output condition. We'll change this later if // we need to. if (record_out != NULL) { *record_out = -1l; } // Check for some reasonable string in call_sign parameter if (call_sign == NULL || strlen(call_sign) == 0) { if (debug_level & 1) { fprintf(stderr,"msg_data_add():call_sign was NULL or empty, exiting\n"); } return((time_t)-1l); } //else //fprintf(stderr,"msg_data_add():call_sign: %s\n", call_sign); if ( (data != NULL) && (strlen(data) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 2) { fprintf(stderr,"msg_data_add: Message length too long\n"); } return((time_t)-1l); } substr(m_fill.call_sign, call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, from_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // If the sequence number is blank, then it may have been a query, // directed query, or group message. Assume it is a new message in // each case and add it. if (seq[0] != '\0') // Normal station->station messaging or { // bulletins // Look for a message with the same call_sign, // from_call_sign, and seq number record = msg_find_data(&m_fill); //fprintf(stderr,"RECORD %ld \n",record); //fprintf(stderr,"Normal station->station message\n"); } else // Group message/query/etc. { record = -1L; group_message++; // Flag it as a group message //fprintf(stderr,"Group message/query/etc\n"); } msg_clear_data(&m_fill); if(record != -1L) /* fill old data */ { msg_get_data(&m_fill, record); last_ack_sent = m_fill.last_ack_sent; //fprintf(stderr,"Found: last_ack_sent: %ld\n",m_fill.last_ack_sent); //fprintf(stderr,"Found a duplicate message. Updating fields, seq %s\n",seq); // If message is different this time, do an update to the // send message window and update the sec_heard field. The // remote station must have restarted and is re-using the // sequence numbers. What a pain! if (strcmp(m_fill.message_line,data) != 0) { m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"Message is different this time: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { do_msg_update++; } } // If message is the same, but the sec_heard field is quite // old (more than 8 hours), the remote station must have // restarted, is re-using the sequence numbers, and just // happened to send the same message with the same sequence // number. Again, what a pain! Either that, or we // connected to a spigot with a _really_ long queue! if (m_fill.sec_heard < (sec_now() - (8 * 60 * 60) )) { m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"Found >8hrs old: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { do_msg_update++; } } // Check for zero time if (m_fill.sec_heard == (time_t)0) { m_fill.sec_heard = sec_now(); fprintf(stderr,"Zero time on a previous message.\n"); } } else { // Only do this if it's a new message. This keeps things // more in sequence by not updating the time stamps // constantly on old messages that don't get ack'ed. m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"New msg: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { //fprintf(stderr,"Found new message\n"); do_msg_update++; // Always do an update to the // message window for new messages } } /* FROM */ m_fill.data_via=from; m_fill.active=RECORD_ACTIVE; m_fill.type=type; if (m_fill.heard_via_tnc != VIA_TNC) { m_fill.heard_via_tnc = (from == 'T') ? VIA_TNC : NOT_VIA_TNC; } distance = (int)(distance_from_my_station(from_call,temp) + 0.9999); if (distance != 0) // Have a posit from the sending station { m_fill.position_known = 1; //fprintf(stderr,"Position known: %s\n",from_call); } else { //fprintf(stderr,"Position not known: %s\n",from_call); } substr(m_fill.call_sign,call_sign,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign,from_call,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); // Update the message field substr(m_fill.message_line,data,MAX_MESSAGE_LENGTH); substr(m_fill.seq,seq,MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Create a timestamp from the current time xastir_snprintf(m_fill.packet_time, sizeof(m_fill.packet_time), "%s", get_time(time_data)); if(record == -1L) // No old record found { if (group_message) { m_fill.acked = 1; // Group msgs/queries need no ack } else { m_fill.acked = 0; // We can't have been acked yet } m_fill.interval = 0; m_fill.tries = 0; // We'll be sending an ack right away if this is a new // message, so might as well set the time now so that we // don't care about failing to set it in // msg_update_ack_stamp due to the record number being -1. m_fill.last_ack_sent = sec_now(); msg_input_database(&m_fill); // Create a new entry //fprintf(stderr,"No record found: Setting last_ack_sent to sec_now()00\n"); } else // Old record found { //fprintf(stderr,"Replacing the message in the database, seq %s\n",seq); msg_replace_data(&m_fill, record); // Copy fields from m_fill to record } /* display messages */ if (type == MESSAGE_MESSAGE) { all_messages(from,call_sign,from_call,data); } // Check for my callsign (including SSID). If found, update any // open message dialogs if ( is_my_call(m_fill.from_call_sign, 1) || is_my_call(m_fill.call_sign, 1) ) { if (do_msg_update) { update_messages(1); // Force an update } } if (debug_level & 1) { fprintf(stderr,"msg_data_add end\n"); } // Return the important variables we'll need if (record_out != NULL) { *record_out = record; } //fprintf(stderr,"\nrecord_out:%ld record %ld\n",*record_out,record); return(last_ack_sent); } // End of msg_data_add() // alert_data_add: Function which adds NWS weather alerts to the // alert hash. // // This function adds alerts directly to the alert hash, bypassing // the message list and associated message-scan functions. // void alert_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from) { Message m_fill; char time_data[MAX_TIME]; char user_base_dir[MAX_VALUE]; if (debug_level & 2) { fprintf(stderr,"alert_data_add start\n"); } if (log_wx_alert_data && from != DATA_VIA_FILE) { char temp_msg[MAX_MESSAGE_LENGTH+1]; // Attempt to reconstruct the original weather alert packet // here, minus the path. xastir_snprintf(temp_msg, sizeof(temp_msg), "%s>APRS::%-9s:%s{%s", from_call, call_sign, data, seq); log_data( get_user_base_dir(LOGFILE_WX_ALERT, user_base_dir, sizeof(user_base_dir)), temp_msg); // fprintf(stderr, "%s\n", temp_msg); } if ( (data != NULL) && (strlen(data) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 2) { fprintf(stderr,"alert_data_add: Message length too long\n"); } return; } substr(m_fill.call_sign, call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, from_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); m_fill.sec_heard = sec_now(); /* FROM */ m_fill.data_via=from; m_fill.active=RECORD_ACTIVE; m_fill.type=type; // We don't have a value filled in yet here! //if (m_fill.heard_via_tnc != VIA_TNC) m_fill.heard_via_tnc = (from == 'T') ? VIA_TNC : NOT_VIA_TNC; substr(m_fill.call_sign,call_sign,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign,from_call,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); // Update the message field substr(m_fill.message_line,data,MAX_MESSAGE_LENGTH); substr(m_fill.seq,seq,MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Create a timestamp from the current time xastir_snprintf(m_fill.packet_time, sizeof(m_fill.packet_time), "%s", get_time(time_data)); // Go try to add it to our alert hash. alert_build_list() will // check for duplicates before adding it. alert_build_list(&m_fill); // This function fills in the Shapefile filename and index // so that we can later draw it. fill_in_new_alert_entries(); if (debug_level & 2) { fprintf(stderr,"alert_data_add end\n"); } } // End of alert_data_add() // What I'd like to do for the following routine: Use // XmTextGetInsertionPosition() or XmTextGetCursorPosition() to // find the last of the text. Could also save the position for // each SendMessage window. Compare the timestamps of messages // found with the last update time. If newer, then add them to // the end. This should stop the incessant scrolling. // Another idea, easier method: Create a buffer. Snag out the // messages from the array and sort by time. Put them into a // buffer. Figure out the length of the text widget, and append // the extra length of the buffer onto the end of the text widget. // Once the message data is turned into a linked list, it might // be sorted already by time, so this window will look better // anyway. // Calling update_messages with force == 1 will cause an update // no matter what message_update_time() says. void update_messages(int force) { static XmTextPosition pos; char temp1[MAX_CALLSIGN+1]; char temp2[500]; char stemp[20]; long i; int mw_p; char *temp_ptr; if ( message_update_time() || force) { //fprintf(stderr,"update_messages()\n"); //fprintf(stderr,"Um %d\n",(int)sec_now() ); /* go through all mw_p's! */ // Perform this for each message window for (mw_p=0; msg_index && mw_p < MAX_MESSAGE_WINDOWS; mw_p++) { //pos=0; begin_critical_section(&send_message_dialog_lock, "db.c:update_messages" ); if (mw[mw_p].send_message_dialog!=NULL/* && mw[mw_p].message_group==1*/) { //fprintf(stderr,"\n"); //fprintf(stderr,"found send_message_dialog\n"); // Clear the text from message window XmTextReplace(mw[mw_p].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[mw_p].send_message_text), ""); // Snag the callsign you're dealing with from the message dialogue if (mw[mw_p].send_message_call_data != NULL) { temp_ptr = XmTextFieldGetString(mw[mw_p].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); new_message_data--; if (new_message_data<0) { new_message_data=0; } if(strlen(temp1)>0) // We got a callsign from the dialog so { // create a linked list of the message indexes in time-sorted order typedef struct _index_record { int index; time_t sec_heard; struct _index_record *next; } index_record; index_record *head = NULL; index_record *p_prev = NULL; index_record *p_next = NULL; // Allocate the first record (a dummy record) head = (index_record *)malloc(sizeof(index_record)); CHECKMALLOC(head); head->index = -1; head->sec_heard = (time_t)0; head->next = NULL; (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); pos = 0; // Loop through looking for messages to/from // that callsign (including SSID) for (i = 0; i < msg_index_end; i++) { if (msg_data[msg_index[i]].active == RECORD_ACTIVE && (strcmp(temp1, msg_data[msg_index[i]].from_call_sign) == 0 || strcmp(temp1,msg_data[msg_index[i]].call_sign) == 0) && (is_my_call(msg_data[msg_index[i]].from_call_sign, 1) || is_my_call(msg_data[msg_index[i]].call_sign, 1) || mw[mw_p].message_group ) ) { int done = 0; // Message matches our parameters so // save the relevant data about the // message in our linked list. Compare // the sec_heard field to see whether // we're higher or lower, and insert the // record at the correct spot in the // list. We end up with a time-sorted // list. p_prev = head; p_next = p_prev->next; while (!done && (p_next != NULL)) // Loop until end of list or record inserted { //fprintf(stderr,"Looping, looking for insertion spot\n"); if (p_next->sec_heard <= msg_data[msg_index[i]].sec_heard) { // Advance one record p_prev = p_next; p_next = p_prev->next; } else // We found the correct insertion spot { done++; } } //fprintf(stderr,"Inserting\n"); // Add the record in between p_prev and // p_next, even if we're at the end of // the list (in that case p_next will be // NULL. p_prev->next = (index_record *)malloc(sizeof(index_record)); CHECKMALLOC(p_prev->next); p_prev->next->next = p_next; // Link to rest of records or NULL p_prev->next->index = i; p_prev->next->sec_heard = msg_data[msg_index[i]].sec_heard; // Remember to free this entire linked list before exiting the loop for // this message window! } } // Done processing the entire list for this // message window. //fprintf(stderr,"Done inserting/looping\n"); if (head->next != NULL) // We have messages to display { int done = 0; //fprintf(stderr,"We have messages to display\n"); // Run through the linked list and dump the // info out. It's now in time-sorted order. // Another optimization would be to keep a count of records added, then // later when we were dumping it out to the window, only dump the last // XX records out. p_prev = head->next; // Skip the first dummy record p_next = p_prev->next; while (!done && (p_prev != NULL)) // Loop until end of list { int j = p_prev->index; // Snag the index out of the record char prefix[50]; char interval_str[50]; int offset = 22; // Offset for highlighting //fprintf(stderr,"\nLooping through, reading messages\n"); //fprintf(stderr,"acked: %d\n",msg_data[msg_index[j]].acked); // Message matches so snag the important pieces into a string xastir_snprintf(stemp, sizeof(stemp), "%c%c/%c%c %c%c:%c%c", msg_data[msg_index[j]].packet_time[0], msg_data[msg_index[j]].packet_time[1], msg_data[msg_index[j]].packet_time[2], msg_data[msg_index[j]].packet_time[3], msg_data[msg_index[j]].packet_time[8], msg_data[msg_index[j]].packet_time[9], msg_data[msg_index[j]].packet_time[10], msg_data[msg_index[j]].packet_time[11] ); // Somewhere in here we appear to be losing the first message. It // doesn't get written to the window later in the QSO. Same for // closing the window and re-opening it, putting the same callsign // in and pressing "New Call" button. First message is missing. // Label the message line with who sent it. // If acked = 2 a timeout has occurred // If acked = 3 a cancel has occurred if (msg_data[msg_index[j]].acked == 2) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB016") ); // "*TIMEOUT*" } else if (msg_data[msg_index[j]].acked == 3) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB017") ); // "*CANCELLED*" } else if (msg_data[msg_index[j]].acked == 4) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB018") ); // "*REJECTED*" } else { prefix[0] = '\0'; } if (msg_data[msg_index[j]].interval) { xastir_snprintf(interval_str, sizeof(interval_str), ">%d/%lds", msg_data[msg_index[j]].tries + 1, (long)msg_data[msg_index[j]].interval); // Don't highlight the interval // value offset = offset + strlen(interval_str); } else { interval_str[0] = '\0'; } xastir_snprintf(temp2, sizeof(temp2), "%s %-9s%s>%s%s\n", // Debug code. Trying to find sorting error //"%ld %s %-9s>%s\n", //msg_data[msg_index[j]].sec_heard, stemp, msg_data[msg_index[j]].from_call_sign, interval_str, prefix, msg_data[msg_index[j]].message_line); //fprintf(stderr,"message: %s\n", msg_data[msg_index[j]].message_line); //fprintf(stderr,"update_messages: %s|%s", temp1, temp2); if (debug_level & 2) { fprintf(stderr,"update_messages: %s|%s\n", temp1, temp2); } // Replace the text from pos to pos+strlen(temp2) by the string "temp2" if (mw[mw_p].send_message_text != NULL) { // Insert the text at the end // XmTextReplace(mw[mw_p].send_message_text, // pos, // pos+strlen(temp2), // temp2); XmTextInsert(mw[mw_p].send_message_text, pos, temp2); // Set highlighting based on the // "acked" field. Callsign // match here includes SSID. //fprintf(stderr,"acked: %d\t",msg_data[msg_index[j]].acked); if ( (msg_data[msg_index[j]].acked == 0) // Not acked yet && ( is_my_call(msg_data[msg_index[j]].from_call_sign, 1)) ) { //fprintf(stderr,"Setting underline\t"); XmTextSetHighlight(mw[mw_p].send_message_text, pos+offset, pos+strlen(temp2), //XmHIGHLIGHT_SECONDARY_SELECTED); // Underlining XmHIGHLIGHT_SELECTED); // Reverse Video } else // Message was acked, get rid of highlighting { //fprintf(stderr,"Setting normal\t"); XmTextSetHighlight(mw[mw_p].send_message_text, pos+offset, pos+strlen(temp2), XmHIGHLIGHT_NORMAL); } //fprintf(stderr,"Text: %s\n",temp2); pos += strlen(temp2); } // Advance to the next record in the list p_prev = p_next; if (p_next != NULL) { p_next = p_prev->next; } } // End of while } // End of if else // No messages matched, list is empty { } // What does this do? Move all of the text? // if (pos > 0) { // if (mw[mw_p].send_message_text != NULL) { // XmTextReplace(mw[mw_p].send_message_text, // --pos, // XmTextGetLastPosition(mw[mw_p].send_message_text), // ""); // } // } //fprintf(stderr,"Free'ing list\n"); // De-allocate the linked list p_prev = head; while (p_prev != NULL) { //fprintf(stderr,"You're free!\n"); p_next = p_prev->next; free(p_prev); p_prev = p_next; } // Show the last added message in the window XmTextShowPosition(mw[mw_p].send_message_text, pos); } } } end_critical_section(&send_message_dialog_lock, "db.c:update_messages" ); } last_message_update = sec_now(); //fprintf(stderr,"Message index end: %ld\n",msg_index_end); } } void mdelete_messages_from(char *from) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, my_callsign) == 0 && strcmp(msg_data[i].from_call_sign, from) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdelete_messages_to(char *to) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, to) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdelete_messages(char *to_from) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, to_from) == 0 || strcmp(msg_data[i].from_call_sign, to_from) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdata_delete_type(const char msg_type, const time_t reference_time) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if ((msg_type == '\0' || msg_type == msg_data[i].type) && msg_data[i].active == RECORD_ACTIVE && msg_data[i].sec_heard < reference_time) { msg_data[i].active = RECORD_NOTACTIVE; } } void check_message_remove(time_t curr_sec) // called in timing loop { // Time to check for old messages again? (Currently every ten // minutes) #ifdef EXPIRE_DEBUG if ( last_message_remove < (curr_sec - DEBUG_MESSAGE_REMOVE_CYCLE) ) #else // EXPIRE_DEBUG if ( last_message_remove < (curr_sec - MESSAGE_REMOVE_CYCLE) ) #endif { // Yes it is. Mark all messages that are older than // sec_remove with the RECORD_NOTACTIVE flag. This will // mark them for re-use. #ifdef EXPIRE_DEBUG mdata_delete_type('\0', curr_sec-DEBUG_MESSAGE_REMOVE); #else // EXPIRE_DEBUG mdata_delete_type('\0', curr_sec-sec_remove); #endif last_message_remove = curr_sec; } // Should we sort them at this point so that the unused ones are // near the end? It looks like the message input functions do // this, so I guess we don't need to do it here. } void mscan_file(char msg_type, void (*function)(Message *)) { long i; for (i = 0; msg_index && i < msg_index_end; i++) if ((msg_type == '\0' || msg_type == msg_data[msg_index[i]].type) && msg_data[msg_index[i]].active == RECORD_ACTIVE) { function(&msg_data[msg_index[i]]); } } void mprint_record(Message *m_fill) { fprintf(stderr, "%-9s>%-9s %s:%5s %s:%c :%s\n", m_fill->from_call_sign, m_fill->call_sign, langcode("WPUPMSB013"), // "seq" m_fill->seq, langcode("WPUPMSB014"), // "type" m_fill->type, m_fill->message_line); } void mdisplay_file(char msg_type) { fprintf(stderr,"\n\n"); mscan_file(msg_type, mprint_record); fprintf(stderr,"\tmsg_index_end %ld, msg_index_max %ld\n", msg_index_end, msg_index_max); } /////////////////////////////////////// Station Data /////////////////////////////////////////// void pad_callsign(char *callsignout, char *callsignin) { int i,l; l=(int)strlen(callsignin); for(i=0; i<9; i++) { if(i= 'a' && data <= 'j') { // Found a compressed posit numerical overlay data = data - 'a'+'0'; // Convert to a digit } if ( (data >= '0' && data <= '9') || (data >= 'A' && data <= 'Z') ) { // Found normal overlay character fill->aprs_symbol.aprs_type = '\\'; fill->aprs_symbol.special_overlay = data; } else { // Bad overlay character. Don't use it. Insert the // normal alternate table character instead. fill->aprs_symbol.aprs_type = '\\'; fill->aprs_symbol.special_overlay='\0'; } } else // No overlay character { fill->aprs_symbol.aprs_type = data; fill->aprs_symbol.special_overlay='\0'; } fill->aprs_symbol.aprs_symbol = symbol; } APRS_Symbol *id_callsign(char *call_sign, char * to_call) { char *ptr; char *id = "/aUfbYX's>,")) != NULL) { *ptr = '\0'; } if (strlen(hold) >= 2) { switch (hold[0]) { case 'A': symbol.aprs_type = '\\'; /* Falls through. */ case 'P': if (('0' <= hold[1] && hold[1] <= '9') || ('A' <= hold[1] && hold[1] <= 'Z')) { symbol.aprs_symbol = hold[1]; } break; case 'O': symbol.aprs_type = '\\'; /* Falls through. */ case 'B': switch (hold[1]) { case 'B': symbol.aprs_symbol = '!'; break; case 'C': symbol.aprs_symbol = '"'; break; case 'D': symbol.aprs_symbol = '#'; break; case 'E': symbol.aprs_symbol = '$'; break; case 'F': symbol.aprs_symbol = '%'; break; case 'G': symbol.aprs_symbol = '&'; break; case 'H': symbol.aprs_symbol = '\''; break; case 'I': symbol.aprs_symbol = '('; break; case 'J': symbol.aprs_symbol = ')'; break; case 'K': symbol.aprs_symbol = '*'; break; case 'L': symbol.aprs_symbol = '+'; break; case 'M': symbol.aprs_symbol = ','; break; case 'N': symbol.aprs_symbol = '-'; break; case 'O': symbol.aprs_symbol = '.'; break; case 'P': symbol.aprs_symbol = '/'; break; } break; case 'D': symbol.aprs_type = '\\'; /* Falls through. */ case 'H': switch (hold[1]) { case 'S': symbol.aprs_symbol = '['; break; case 'T': symbol.aprs_symbol = '\\'; break; case 'U': symbol.aprs_symbol = ']'; break; case 'V': symbol.aprs_symbol = '^'; break; case 'W': symbol.aprs_symbol = '_'; break; case 'X': symbol.aprs_symbol = '`'; break; } break; case 'N': symbol.aprs_type = '\\'; /* Falls through. */ case 'M': switch (hold[1]) { case 'R': symbol.aprs_symbol = ':'; break; case 'S': symbol.aprs_symbol = ';'; break; case 'T': symbol.aprs_symbol = '<'; break; case 'U': symbol.aprs_symbol = '='; break; case 'V': symbol.aprs_symbol = '>'; break; case 'W': symbol.aprs_symbol = '?'; break; case 'X': symbol.aprs_symbol = '@'; break; } break; case 'Q': symbol.aprs_type = '\\'; /* Falls through. */ case 'J': switch (hold[1]) { case '1': symbol.aprs_symbol = '{'; break; case '2': symbol.aprs_symbol = '|'; break; case '3': symbol.aprs_symbol = '}'; break; case '4': symbol.aprs_symbol = '~'; break; } break; case 'S': symbol.aprs_type = '\\'; /* Falls through. */ case 'L': if ('A' <= hold[1] && hold[1] <= 'Z') { symbol.aprs_symbol = tolower((int)hold[1]); } break; } if (hold[2]) { if (hold[2] >= 'a' && hold[2] <= 'j') { // Compressed mode numeric overlay symbol.special_overlay = hold[2] - 'a'; } else if ( (hold[2] >= '0' && hold[2] <= '9') || (hold[2] >= 'A' && hold[2] <= 'Z') ) { // Normal overlay character symbol.special_overlay = hold[2]; } else { // Bad overlay character found symbol.special_overlay = '\0'; } } else { // No overlay character found symbol.special_overlay = '\0'; } } } return(&symbol); } /******************************** Sort begin *************************** ****/ void clear_sort_file(char *filename) { char ptr_filename[400]; xastir_snprintf(ptr_filename, sizeof(ptr_filename), "%s-ptr", filename); (void)unlink(filename); (void)unlink(ptr_filename); } void sort_reset_pointers(FILE *pointer,long new_data_ptr,long records, int type, long start_ptr) { long temp[13000]; long buffn,start_buffn; long cp_records; long max_buffer; int my_size; my_size=(int)sizeof(new_data_ptr); max_buffer=13000l; if(type==0) { /* before start_ptr */ /* copy back pointers */ for(buffn=records; buffn > start_ptr; buffn-=max_buffer) { start_buffn=buffn-max_buffer; if(start_buffn0) { /* file name comes after */ /*fprintf(stderr,"END - After end\n");*/ done=1; /* now place pointer after end */ } else { if((record_mid==record_start) || (record_mid==record_end)) { /* no mid for compare check to see if in the middle */ /*fprintf(stderr,"END - NO Middle\n");*/ done=1; /* now place pointer before start*/ if (record_mid==record_start) { sort_reset_pointers(pointer,new_data_ptr,records,0,record_mid+1); } else { sort_reset_pointers(pointer,new_data_ptr,records,0,record_mid-1); } } else { /* get data for record mid */ (void)fseek(pointer,(ptr_size*record_mid),SEEK_SET); if (fread(&data_ptr,(size_t)ptr_size,1,pointer) != 0) { // we are explicitly // ignoring the return // value, but are doing it // this way to silence GCC // warnings } (void)fseek(my_data,data_ptr,SEEK_SET); if(fread(file_data,(size_t)size,1,my_data)==1) { /* COMPARE HERE */ if (1 != sscanf(file_data,"%1999s",tempfile)) { fprintf(stderr,"sort_input_database(4): sscanf failed to parse\n"); } if(strcasecmp(tempfill,tempfile)<0) { /* checking comes before */ /*record_start=0l;*/ record_end=record_mid; record_mid=record_start+(record_end-record_start)/2; /*fprintf(stderr,"TOP %ld, mid %ld\n",record_mid,record_end);*/ } else { /* checking comes after*/ record_start=record_mid; /*record_end=end*/ record_mid=record_start+(record_end-record_start)/2; /*fprintf(stderr,"BOTTOM start %ld, mid %ld\n",record_start,record_mid);*/ } } } } } } } } } } else { fprintf(stderr,"Could not open file %s\n",filename); } } else { fprintf(stderr,"Could not open file %s\n",filename); } if(my_data!=NULL) { (void)fclose(my_data); } if(pointer!=NULL) { (void)fclose(pointer); } return(return_records); } /******************** sort end **********************/ // is_altnet() // // Returns true if station fits the current altnet description. // int is_altnet(DataRow *p_station) { char temp_altnet_call[20+1]; char temp2[20+1]; char *net_ptr; int altnet_match; int result; // Snag a possible altnet call out of the record for later use if (p_station->node_path_ptr != NULL) { substr(temp_altnet_call, p_station->node_path_ptr, MAX_CALLSIGN); } else { temp_altnet_call[0] = '\0'; } // Save for later xastir_snprintf(temp2, sizeof(temp2), "%s", temp_altnet_call); if ((net_ptr = strchr(temp_altnet_call, ','))) { *net_ptr = '\0'; // Chop the string at the first ',' character } for (altnet_match = (int)strlen(altnet_call); altnet && altnet_call[altnet_match-1] == '*'; altnet_match--); result = (!strncmp(temp_altnet_call, altnet_call, (size_t)altnet_match) || !strcmp(temp_altnet_call, "local") || !strncmp(temp_altnet_call, "SPC", 3) || !strcmp(temp_altnet_call, "SPECL") // || is_my_call(p_station->call_sign,1)); // Check SSID as well || ( is_my_station(p_station) ) ) ; // It's my callsign/SSID if ( (debug_level & 1) && result ) { fprintf(stderr,"%s %-9s %s\n", altnet_call, temp_altnet_call, temp2 ); } return(result); } // Function which checks various filtering criteria (the Select struct) // and decides whether this station/object should be displayed. // // 0 = don't draw this station/object // 1 = ok to draw this station/object // int ok_to_draw_station(DataRow *p_station) { time_t secs_now = sec_now(); // Check overall flag if (Select_.none) { return 0; } // Check tactical flag if (Select_.tactical && (p_station->tactical_call_sign == NULL || p_station->tactical_call_sign[0] == '\0')) { return 0; } // Check for my station and my objects/items // if (strcmp(p_station->call_sign, my_callsign) == 0 // || (is_my_call(p_station->origin, 1) // If station is owned by me (including SSID) // && ( p_station->flag & ST_OBJECT // And it's an object // || p_station->flag & ST_ITEM) ) ) { // or an item // if ( is_my_station(p_station) || is_my_object_item(p_station) ) { if ( is_my_station(p_station) ) { if (!Select_.mine) { return 0; } } // Not mine, so check these next things else { // Check whether we wish to display TNC heard stations if (p_station->flag & ST_VIATNC) { if (!Select_.tnc) { return 0; } // Check whether we wish to display directly heard stations if (p_station->flag & ST_DIRECT && secs_now < (p_station->direct_heard + st_direct_timeout)) { if (!Select_.direct) { return 0; } } // Check whether we wish to display stations heard via a digi else { if (!Select_.via_digi) { return 0; } } } // Check whether we wish to display net stations else { if (!Select_.net) { return 0; } } //N7IPB - check for aircraft and if so check aircraft timeout // return 0 if timedout - else continue if ((aircraft_sec_clear != 0) && ((p_station->aprs_symbol.aprs_symbol == '^') || (p_station->aprs_symbol.aprs_symbol == '\'') || (p_station->aprs_symbol.aprs_symbol == 'X'))) { if ((p_station->sec_heard + (aircraft_sec_clear * 5)) < secs_now) { return 0; } } // Check if we want to display data past the clear time if (!Select_.old_data) { if ((p_station->sec_heard + sec_clear) < secs_now) { return 0; } } } // Check whether object or item if (p_station->flag & (ST_OBJECT | ST_ITEM)) { // Check whether we wish to display objects/items if (!Select_.objects || (!Select_.weather_objects && !Select_.gauge_objects && !Select_.aircraft_objects && !Select_.vessel_objects && !Select_.other_objects)) { return 0; } // Check if WX info and we wish to see it if (p_station->weather_data) { return Select_.weather_objects; } // Check if water gauge and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'w') { return Select_.gauge_objects; } // Check if aircraft and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && ((p_station->aprs_symbol.aprs_symbol == '^') || (p_station->aprs_symbol.aprs_symbol == '\'') || (p_station->aprs_symbol.aprs_symbol == 'X')) ) { return Select_.aircraft_objects; } // Check if vessel and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && ((p_station->aprs_symbol.aprs_symbol == 's') || (p_station->aprs_symbol.aprs_symbol == 'Y')) ) { return Select_.vessel_objects; } // Check if we wish to see other objects/items else { return Select_.other_objects; } } else // Not an object or item { if (!Select_.stations || (!Select_.fixed_stations && !Select_.moving_stations && !Select_.weather_stations)) { return 0; } // Check if we wish to see weather stations if (p_station->weather_data) { // We have weather data // Check whether it is a citizen's weather station. // Note that a "CW" prefix is Uruguay and "DW" prefix is // Philippines, so let's be careful how we filter here. // All Cititzen's weather stations seen to date have had // CW or DW and then four digits. if ( (strncasecmp(p_station->call_sign,"CW",2) == 0) || (strncasecmp(p_station->call_sign,"DW",2) == 0) ) { if ( is_num_chr(p_station->call_sign[2]) && is_num_chr(p_station->call_sign[3]) && is_num_chr(p_station->call_sign[4]) && is_num_chr(p_station->call_sign[5]) ) { return(Select_.weather_stations && Select_.CWOP_wx_stations); } else { return Select_.weather_stations; } } else { return Select_.weather_stations; } } // Check if we wish to see other stations else { if (p_station->flag & ST_MOVING) { return Select_.moving_stations; } else { return Select_.fixed_stations; } } } } // display_station // // single is 1 if the calling station wants to update only a // single station. If updating multiple stations in a row, then // "single" will be passed to us as a zero. // // If current course/speed/altitude are absent, we check the last // track point to try to snag those numbers. // void display_station(Widget w, DataRow *p_station, int single) { char temp_altitude[20]; char temp_course[20]; char temp_speed[20]; char dr_speed[20]; char temp_call[MAX_TACTICAL_CALL+1]; char wx_tm[50]; char temp_wx_temp[30]; char temp_wx_wind[40]; char temp_my_distance[20]; char temp_my_course[20]; char temp1_my_course[20]; char temp2_my_gauge_data[50]; time_t temp_sec_heard; int temp_show_last_heard; long l_lon, l_lat; char orient; float value; char tmp[7+1]; int speed_ok = 0; int course_ok = 0; int wx_ghost = 0; Pixmap drawing_target; WeatherRow *weather = p_station->weather_data; time_t secs_now = sec_now(); int ambiguity_flag; long ambiguity_coord_lon, ambiguity_coord_lat; size_t temp_len; if (debug_level & 128) { fprintf(stderr,"Display station (%s) called for Single=%d.\n", p_station->call_sign, single); } if (!ok_to_draw_station(p_station)) { return; } // Set up call string for display if (Display_.callsign) { if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { // Display tactical callsign instead if it has one // defined. xastir_snprintf(temp_call, sizeof(temp_call), "%s", p_station->tactical_call_sign); } else { // Display normal callsign. xastir_snprintf(temp_call, sizeof(temp_call), "%s", p_station->call_sign); } } else { temp_call[0] = '\0'; } // Set up altitude string for display temp_altitude[0] = '\0'; if (Display_.altitude) { // Check whether we have altitude in the current data if (strlen(p_station->altitude)>0) { // Found it in the current data xastir_snprintf(temp_altitude, sizeof(temp_altitude), "%.0f%s", atof(p_station->altitude) * cvt_m2len, un_alt); } // Else check whether the previous position had altitude. // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { if ( p_station->newest_trackpoint->prev->altitude > -99999l) { // Found it in the tracklog xastir_snprintf(temp_altitude, sizeof(temp_altitude), "%.0f%s", (float)(p_station->newest_trackpoint->prev->altitude * cvt_dm2len), un_alt); // fprintf(stderr,"Trail data with altitude: %s : %s\n", // p_station->call_sign, // temp_altitude); } else { //fprintf(stderr,"Trail data w/o altitude %s\n", // p_station->call_sign); } } } // Set up speed and course strings for display temp_speed[0] = '\0'; dr_speed[0] = '\0'; temp_course[0] = '\0'; if (Display_.speed || Display_.dr_data) { // don't display 'fixed' stations speed and course. // Check whether we have speed in the current data and it's // >= 0. if ( (strlen(p_station->speed)>0) && (atof(p_station->speed) >= 0) ) { speed_ok++; xastir_snprintf(tmp, sizeof(tmp), "%s", un_spd); if (Display_.speed_short) { tmp[0] = '\0'; // without unit } xastir_snprintf(temp_speed, sizeof(temp_speed), "%.0f%s", atof(p_station->speed)*cvt_kn2len,tmp); } // Else check whether the previous position had speed // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { xastir_snprintf(tmp, sizeof(tmp), "%s", un_spd); if (Display_.speed_short) { tmp[0] = '\0'; // without unit } if ( p_station->newest_trackpoint->prev->speed > 0) { speed_ok++; xastir_snprintf(temp_speed, sizeof(temp_speed), "%.0f%s", p_station->newest_trackpoint->prev->speed * cvt_hm2len, tmp); } } } if (Display_.course || Display_.dr_data) { // Check whether we have course in the current data if ( (strlen(p_station->course)>0) && (atof(p_station->course) > 0) ) { course_ok++; xastir_snprintf(temp_course, sizeof(temp_course), "%.0f\xB0", atof(p_station->course)); } // Else check whether the previous position had a course // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { if( p_station->newest_trackpoint->prev->course > 0 ) { course_ok++; xastir_snprintf(temp_course, sizeof(temp_course), "%.0f\xB0", (float)p_station->newest_trackpoint->prev->course); } } } // Save the speed into the dr string for later xastir_snprintf(dr_speed, sizeof(dr_speed), "%s", temp_speed); if (!speed_ok || !Display_.speed) { temp_speed[0] = '\0'; } if (!course_ok || !Display_.course) { temp_course[0] = '\0'; } // Set up distance and bearing strings for display temp_my_distance[0] = '\0'; temp_my_course[0] = '\0'; if (Display_.dist_bearing && strcmp(p_station->call_sign,my_callsign) != 0) { l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles, convert to current measurement standard value = cvt_kn2len * calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,temp1_my_course,sizeof(temp1_my_course)); if (value < 5.0) { sprintf(temp_my_distance,"%0.1f%s",value,un_dst); } else { sprintf(temp_my_distance,"%0.0f%s",value,un_dst); } xastir_snprintf(temp_my_course, sizeof(temp_my_course), "%.0f\xB0", atof(temp1_my_course)); } // Set up weather strings for display temp_wx_temp[0] = '\0'; temp_wx_wind[0] = '\0'; if (weather != NULL) { // wx_ghost = 1 if the weather data is too old to display wx_ghost = (int)(((sec_old + weather->wx_sec_time)) < secs_now); } if (Display_.weather && Display_.weather_text && weather != NULL // We have weather data && !wx_ghost) // Weather is current, display it { if (strlen(weather->wx_temp) > 0) { xastir_snprintf(tmp, sizeof(tmp), "T:"); if (Display_.temperature_only) { tmp[0] = '\0'; } if (english_units) xastir_snprintf(temp_wx_temp, sizeof(temp_wx_temp), "%s%.0f\xB0%s", tmp, atof(weather->wx_temp),"F "); else xastir_snprintf(temp_wx_temp, sizeof(temp_wx_temp), "%s%.0f\xB0%s", tmp,((atof(weather->wx_temp)-32.0)*5.0)/9.0,"C "); } if (!Display_.temperature_only) { if (strlen(weather->wx_hum) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "H:%.0f%%", atof(weather->wx_hum)); strncat(temp_wx_temp, wx_tm, sizeof(temp_wx_temp) - 1 - strlen(temp_wx_temp)); } if (strlen(weather->wx_speed) > 0) { xastir_snprintf(temp_wx_wind, sizeof(temp_wx_wind), "S:%.0f%s ", atof(weather->wx_speed)*cvt_mi2len,un_spd); } if (strlen(weather->wx_gust) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "G:%.0f%s ", atof(weather->wx_gust)*cvt_mi2len,un_spd); strncat(temp_wx_wind, wx_tm, sizeof(temp_wx_wind) - 1 - strlen(temp_wx_wind)); } if (strlen(weather->wx_course) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "C:%.0f\xB0", atof(weather->wx_course)); strncat(temp_wx_wind, wx_tm, sizeof(temp_wx_wind) - 1 - strlen(temp_wx_wind)); } temp_len = strlen(temp_wx_wind); if ((temp_len > 0) && (temp_wx_wind[temp_len-1] == ' ')) { temp_wx_wind[temp_len-1] = '\0'; // delete blank at EOL } } temp_len = strlen(temp_wx_temp); if ((temp_len > 0) && (temp_wx_temp[strlen(temp_wx_temp)-1] == ' ')) { temp_wx_temp[temp_len-1] = '\0'; // delete blank at EOL } } (void)remove_trailing_asterisk(p_station->call_sign); // DK7IN: is this needed here? if (Display_.symbol_rotate) { orient = symbol_orient(p_station->course); // rotate symbol } else { orient = ' '; } // Prevents my own call from "ghosting"? // temp_sec_heard = (strcmp(p_station->call_sign, my_callsign) == 0) ? secs_now: p_station->sec_heard; temp_sec_heard = (is_my_station(p_station)) ? secs_now : p_station->sec_heard; // Check whether it's a locally-owned object/item // if ( (is_my_call(p_station->origin,1)) // If station is owned by me (including SSID) // && ( (p_station->flag & ST_OBJECT) // And it's an object // || (p_station->flag & ST_ITEM) ) ) { // or an item // if ( is_my_object_item(p_station) ) { // temp_sec_heard = secs_now; // We don't want our own objects/items to "ghost" // } // Show last heard times only for others stations and their // objects/items. // temp_show_last_heard = (strcmp(p_station->call_sign, my_callsign) == 0) ? 0 : Display_.last_heard; temp_show_last_heard = (is_my_station(p_station)) ? 0 : Display_.last_heard; //------------------------------------------------------------------------------------------ // If we're only planning on updating a single station at this time, we go // through the drawing calls twice, the first time drawing directly onto // the screen. if (!pending_ID_message && single) { drawing_target = XtWindow(da); } else { drawing_target = pixmap_final; } //_do_the_drawing: // Check whether it's a locally-owned object/item // if ( (is_my_call(p_station->origin,1)) // If station is owned by me (including SSID) // && ( (p_station->flag & ST_OBJECT) // And it's an object // || (p_station->flag & ST_ITEM ) ) ) { // or an item // if ( is_my_object_item(p_station) ) { // temp_sec_heard = secs_now; // We don't want our own objects/items to "ghost" // This isn't quite right since if it's a moving object, passing an incorrect // sec_heard should give the wrong results. // } ambiguity_flag = 0; // Default if (Display_.ambiguity && p_station->pos_amb) { ambiguity_flag = 1; draw_ambiguity(p_station->coord_lon, p_station->coord_lat, p_station->pos_amb, &ambiguity_coord_lon, // New longitude may get passed back to us &ambiguity_coord_lat, // New latitude may get passed back to us temp_sec_heard, drawing_target); } // Check for DF'ing data, draw DF circles if present and enabled if (Display_.df_data && strlen(p_station->signal_gain) == 7) // There's an SHGD defined { //fprintf(stderr,"SHGD:%s\n",p_station->signal_gain); draw_DF_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->signal_gain, temp_sec_heard, drawing_target); } // Check for DF'ing beam heading/NRQ data if (Display_.df_data && (strlen(p_station->bearing) == 3) && (strlen(p_station->NRQ) == 3)) { //fprintf(stderr,"Bearing: %s\n",p_station->signal_gain,NRQ); if (p_station->df_color == -1) { p_station->df_color = rand() % MAX_TRAIL_COLORS; } draw_bearing( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->course, p_station->bearing, p_station->NRQ, trail_colors[p_station->df_color], Display_.df_beamwidth_data, Display_.df_bearing_data, temp_sec_heard, drawing_target); } // Check whether to draw dead-reckoning data by KJ5O if (Display_.dr_data && ( (p_station->flag & ST_MOVING) // && (p_station->newest_trackpoint!=0 && course_ok && speed_ok && scale_y < 8000 && atof(dr_speed) > 0) ) { // Does it make sense to try to do dead-reckoning on an // object that has position ambiguity enabled? I don't // think so! // if ( ! ambiguity_flag && ( (secs_now-temp_sec_heard) < dead_reckoning_timeout) ) { draw_deadreckoning_features(p_station, drawing_target, w); } } if (p_station->aprs_symbol.area_object.type != AREA_NONE) { draw_area( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->aprs_symbol.area_object.type, p_station->aprs_symbol.area_object.color, p_station->aprs_symbol.area_object.sqrt_lat_off, p_station->aprs_symbol.area_object.sqrt_lon_off, p_station->aprs_symbol.area_object.corridor_width, temp_sec_heard, drawing_target); } // Draw additional stuff if this is the tracked station if (is_tracked_station(p_station->call_sign)) { //WE7U draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0020 * scale_y, colors[0x0e], // Yellow drawing_target, temp_sec_heard); draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0023 * scale_y, colors[0x44], // Red drawing_target, temp_sec_heard); draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0026 * scale_y, colors[0x61], // Blue drawing_target, temp_sec_heard); } // Draw additional stuff if this is a storm and the weather data // is not too old to display. if ( (weather != NULL) && weather->wx_storm && !wx_ghost ) { char temp[4]; //fprintf(stderr,"Plotting a storm symbol:%s:%s:%s:\n", // weather->wx_hurricane_radius, // weather->wx_trop_storm_radius, // weather->wx_whole_gale_radius); // Still need to draw the circles in different colors for the // different ranges. Might be nice to tint it as well. xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_hurricane_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x44], // Red drawing_target, temp_sec_heard); } xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_trop_storm_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x0e], // Yellow drawing_target, temp_sec_heard); } xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_whole_gale_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x0a], // Green drawing_target, temp_sec_heard); } } // Draw wind barb if selected and we have wind, but not a severe // storm (wind barbs just confuse the matter). if (Display_.weather && Display_.wind_barb && weather != NULL && atoi(weather->wx_speed) >= 5 && !weather->wx_storm && !wx_ghost ) { draw_wind_barb( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, weather->wx_speed, weather->wx_course, temp_sec_heard, drawing_target); } // WE7U // // Draw truncation/rounding rectangles plus error ellipses. // // // We need to keep track of ellipse northing/easting radii plus // rectangle northing/easting offsets. If both sets are present // we'll need to draw the summation of both geometric figures. // Check that the math works at/near the poles. We may need to keep // track of truncation/rounding rectangles separately if some // devices or software use one method, some the other. // if (!ambiguity_flag) { // Check whether we're at a close enough zoom level to have // the ellipses/rectangles be visible, else skip drawing for // efficiency. // //fprintf(stderr,"scale_y: %ld\t", scale_y); if (scale_y < 17) // 60' figures are good out to about zoom 16 { // Here we may have to check what type of device is being used (if // possible to determine) to decide whether to draw a truncation/ // rounding rectangles or GPS error ellipses. Truncation rectangles // have the symbol at one corner, rounding have it in the middle. // Based on the precision inherent in the packet we wish to draw a // GPS error ellipse instead, the decision point is when the packet // precision is adequate to show ~6 meters. // // OpenTracker APRS: Truncation, rectangle // OpenTracker Base91:Truncation, ellipse // OpenTracker OpenTrac: Truncation, ellipse // TinyTrak APRS: Truncation, rectangle // TinyTrak NMEA: Truncation, ellipse/rectangle based on precision // TinyTrak Mic-E: Truncation, rectangle // GPGGA: Truncation, ellipse/rectangle based on precision/HDOP/Augmentation // GPRMC: Truncation, ellipse/rectangle based on precision // GPGLL: Truncation, ellipse/rectangle based on precision // Xastir APRS: Truncation, rectangle // Xastir Base91: Truncation, ellipse // UI-View APRS: ??, rectangle // UI-View Base91: ??, ellipse // APRS+SA APRS: ??, rectangle // APRS+SA Base91: ??, ellipse // PocketAPRS: ??, rectangle // SmartAPRS: ??, rectangle // HamHUD: Truncation, ?? // HamHUD GPRMC: Truncation, ellipse/rectangle based on precision // Linksys NSLU2: ??, rectangle // AGW Tracker: ??, ?? // APRSPoint: ??, rectangle // APRSce: ??, rectangle // APRSdos APRS: ??, rectangle // APRSdos Base91: ??, ellipse // BalloonTrack: ??, ?? // DMapper: ??, ?? // JavAPRS APRS: ??, rectangle // JavAPRS Base91: ??, ellipse // WinAPRS APRS: ??, rectangle // WinAPRS Base91: ??, ellipse // MacAPRS APRS: ??, rectangle // MacAPRS Base91: ??, ellipse // MacAPRSOSX APRS: ??, rectangle // MacAPRSOSX Base91: ??, ellipse // X-APRS APRS: ??, rectangle // X-APRS Base91: ??, ellipse // OziAPRS: ??, rectangle // NetAPRS: ??, rectangle // APRS SCS: ??, ?? // RadioMobile: ??, rectangle // KPC-3: ??, rectangle // MicroTNC: ??, rectangle // TigerTrak: ??, rectangle // PicoPacket: ??, rectangle // MIM: ??, rectangle // Mic-Encoder: ??, rectangle // Pic-Encoder: ??, rectangle // Generic Mic-E: ??, rectangle // D7A/D7E: ??, rectangle // D700A: ??, rectangle // Alinco DR-135: ??, rectangle // Alinco DR-620: ??, rectangle // Alinco DR-635: ??, rectangle // Other: ??, ?? // Initial try at drawing the error_ellipse_radius // circles around the posit. error_ellipse_radius is in // centimeters. Convert from cm to miles for // draw_pod_circle(). // /* draw_pod_circle( p_station->coord_lon, p_station->coord_lat, p_station->error_ellipse_radius / 100000.0 * 0.62137, // cm to mi colors[0x0f], // White drawing_target, temp_sec_heard); */ draw_precision_rectangle( p_station->coord_lon, p_station->coord_lat, p_station->error_ellipse_radius, // centimeters (not implemented yet) p_station->lat_precision, // 100ths of seconds latitude p_station->lon_precision, // 100ths of seconds longitude colors[0x0f], // White drawing_target); // Perhaps draw vectors from the symbol out to the borders of these // odd figures? Draw an outline without vectors to the symbol? // Have the color match the track color assigned to that station so // the geometric figures can be kept separate from nearby stations? // // draw_truncation_rectangle + error_ellipse (symbol at corner) // draw_rounding_rectangle + error_ellipse (symbol in middle) } } // Zero out the variable in case we don't use it below. temp2_my_gauge_data[0] = '\0'; // If an H2O object, create a timestamp + last comment variable // (which should contain gage-height and/or water-flow numbers) // for use in the draw_symbol() function below. if (p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'w' && ( p_station->flag & ST_OBJECT // And it's an object || p_station->flag & ST_ITEM) ) // or an item { // NOTE: Also check whether it was sent by the Firenet GAGE // script?? "GAGE-*" // NOTE: Check most recent comment time against // p_station->sec_heard. If they don't match, don't display the // comment. This will make sure that older comment data doesn't get // displayed which can be quite misleading for stream gauges. // Check whether we have any comment data at all. If so, // the first one will be the most recent comment and the one // we wish to display. if (p_station->comment_data != NULL) { CommentRow *ptr; // time_t sec; // struct tm *time; ptr = p_station->comment_data; // Check most recent comment's sec_heard time against // the station record's sec_heard time. If they don't // match, don't display the comment. This will make // sure that older comment data doesn't get displayed // which can be quite misleading for stream gauges. if (p_station->sec_heard == ptr->sec_heard) { // Note that text_ptr can be an empty string. // That's ok. // Also print the sec_heard timestamp so we know // when this particular gauge data was received // (Very important!). // sec = ptr->sec_heard; // time = localtime(&sec); xastir_snprintf(temp2_my_gauge_data, sizeof(temp2_my_gauge_data), "%s", // "%02d/%02d %02d:%02d %s", // time->tm_mon + 1, // time->tm_mday, // time->tm_hour, // time->tm_min, ptr->text_ptr); //fprintf(stderr, "%s\n", temp2_my_gauge_data); } } } draw_symbol(w, p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay, (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, temp_call, temp_altitude, temp_course, // ?? temp_speed, // ?? temp_my_distance, temp_my_course, // Display only if wx temp is current (wx_ghost) ? "" : temp_wx_temp, // Display only if wind speed is current (wx_ghost) ? "" : temp_wx_wind, temp_sec_heard, temp_show_last_heard, drawing_target, orient, p_station->aprs_symbol.area_object.type, p_station->signpost, temp2_my_gauge_data, 1); // Increment "currently_selected_stations" // If it's a Waypoint symbol, draw a line from it to the // transmitting station. if (p_station->aprs_symbol.aprs_type == '\\' && p_station->aprs_symbol.aprs_symbol == '/') { draw_WP_line(p_station, ambiguity_flag, ambiguity_coord_lon, ambiguity_coord_lat, drawing_target, w); } // Draw other points associated with the station, if any. // KG4NBB if (debug_level & 128) { fprintf(stderr," Number of multipoints = %d\n",p_station->num_multipoints); } if (p_station->num_multipoints != 0) { draw_multipoints( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->num_multipoints, p_station->multipoint_data->multipoints, p_station->type, p_station->style, temp_sec_heard, drawing_target); } temp_sec_heard = p_station->sec_heard; // DK7IN: ??? if (Display_.phg && (!(p_station->flag & ST_MOVING) || Display_.phg_of_moving)) { // Check for Map View "eyeball" symbol if ( strncmp(p_station->power_gain,"RNG",3) == 0 && p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'E' ) { // Map View "eyeball" symbol. Don't draw the RNG ring // for it. } else if (strlen(p_station->power_gain) == 7) { // Station has PHG or RNG defined // draw_phg_rng( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->power_gain, temp_sec_heard, drawing_target); } else if (Display_.default_phg && !(p_station->flag & (ST_OBJECT | ST_ITEM))) { // No PHG defined and not an object/item. Display a PHG // of 3130 as default as specified in the spec: 9W, 3dB // omni at 20 feet = 6.2 mile PHG radius. // draw_phg_rng( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, "PHG3130", temp_sec_heard, drawing_target); } } // Draw minimum proximity circle? if (p_station->probability_min[0] != '\0') { double range = atof(p_station->probability_min); // Draw red circle draw_pod_circle(p_station->coord_lon, p_station->coord_lat, range, colors[0x44], drawing_target, temp_sec_heard); } // Draw maximum proximity circle? if (p_station->probability_max[0] != '\0') { double range = atof(p_station->probability_max); // Draw red circle draw_pod_circle(p_station->coord_lon, p_station->coord_lat, range, colors[0x44], drawing_target, temp_sec_heard); } // DEBUG STUFF // draw_pod_circle(x_long, y_lat, 1.5, colors[0x44], where); // draw_pod_circle(x_long, y_lat, 3.0, colors[0x44], where); // Now if we just did the single drawing, we want to go back and draw // the same things onto pixmap_final so that when we do update from it // to the screen all of the stuff will be there. // if (drawing_target == XtWindow(da)) { // drawing_target = pixmap_final; // goto _do_the_drawing; // } } // draw line relative void draw_test_line(Widget w, long x, long y, long dx, long dy, long ofs) { x += screen_width - 10 - ofs; y += screen_height - 10; (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(x), l16(y), l16(x+dx), l16(y+dy)); } // draw text void draw_ruler_text(Widget w, char * text, long ofs) { int x,y; int len; len = (int)strlen(text); x = screen_width - 10 - ofs / 2; y = screen_height - 10; x -= len * 3; y -= 3; if (draw_labeled_grid_border==TRUE) { // move text up a few pixels to leave space for labeled border y = y - 15; x = x - 10; } draw_nice_string(w,pixmap_final,letter_style,x,y,text,0x10,0x20,len); } // Compute Range Scale in miles or kilometers. // // For this we need to figure out x-distance and y-distance across // the screen. Take the smaller of the two, then figure out which // power of 2 miles fits from the center to the edge of the screen. // "For metric, use the nearest whole number kilometer in powers of // two of 1.5 km above the 1 mile scale. At 1 mile and below, do // the conversion to meters where 1 mi is equal to 1600m..." (Bob // Bruninga's words). void draw_range_scale(Widget w) { Dimension width, height; long x, x0, y, y0; double x_miles_km, y_miles_km, distance; char temp_course[10]; long temp; double temp2; long range; int small_flag = 0; int x_screen, y_screen; int len; char text[80]; int border_offset = 0; // number of pixels to offset the scale if a labeled map border is drawn // Find out the screen values XtVaGetValues(da,XmNwidth, &width, XmNheight, &height, NULL); // Convert points to Xastir coordinate system // X x = center_longitude - ((width *scale_x)/2); x0 = center_longitude; // Center of screen // Y y = center_latitude - ((height*scale_y)/2); y0 = center_latitude; // Center of screen // Compute distance from center to each edge // X distance. Keep Y constant. x_miles_km = cvt_kn2len * calc_distance_course(y0,x0,y0,x,temp_course,sizeof(temp_course)); // Y distance. Keep X constant. y_miles_km = cvt_kn2len * calc_distance_course(y0,x0,y,x0,temp_course,sizeof(temp_course)); // Choose the smaller distance if (x_miles_km < y_miles_km) { distance = x_miles_km; } else { distance = y_miles_km; } // Convert it to nearest power of two that fits inside if (english_units) // English units { if (distance >= 1.0) { // Shift it right until it is less than 2. temp = (long)distance; range = 1; while (temp >= 2) { temp = temp / 2; range = range * 2; } } else // Distance is less than one { // divide 1.0 by 2 until distance is greater small_flag++; temp2 = 1.0; range = 1; while (temp2 > distance) { //fprintf(stderr,"temp2: %f, distance: %f\n", temp2, distance); temp2 = temp2 / 2.0; range = range * 2; } } } else // Metric units { if (distance >= 12800.0) { range = 12800; } else if (distance >= 6400.0) { range = 6400; } else if (distance >= 3200.0) { range = 3200; } else if (distance >= 1600.0) { range = 1600; } else if (distance >= 800.0) { range = 800; } else if (distance >= 400.0) { range = 400; } else if (distance >= 200.0) { range = 200; } else if (distance >= 100.0) { range = 100; } else if (distance >= 50.0) { range = 50; } else if (distance >= 25.0) { range = 25; } else if (distance >= 12.0) { range = 12; } else if (distance >= 6.0) { range = 6; } else if (distance >= 3.0) { range = 3; } else { small_flag++; if (distance >= 1.6) { range = 1600; } else if (distance >= 0.8) { range = 800; } else if (distance >= 0.4) { range = 400; } else if (distance >= 0.2) { range = 200; } else if (distance >= 0.1) { range = 100; } else if (distance >= 0.05) { range = 50; } else if (distance >= 0.025) { range = 25; } else { range = 12; } } } //fprintf(stderr,"Distance: %f\t", distance); //fprintf(stderr,"Range: %ld\n", range); if (english_units) // English units { if (small_flag) { xastir_snprintf(text, sizeof(text), "%s 1/%ld mi", langcode("RANGE001"), // "RANGE SCALE" range); } else { xastir_snprintf(text, sizeof(text), "%s %ld mi", langcode("RANGE001"), // "RANGE SCALE" range); } } else // Metric units { if (small_flag) { xastir_snprintf(text, sizeof(text), "%s %ld m", langcode("RANGE001"), // "RANGE SCALE" range); } else { xastir_snprintf(text, sizeof(text), "%s %ld km", langcode("RANGE001"), // "RANGE SCALE" range); } } // Draw it on the screen len = (int)strlen(text); x_screen = 10; y_screen = screen_height - 5; if ((draw_labeled_grid_border==TRUE) && long_lat_grid) { border_offset = get_rotated_label_text_length_pixels(w, "0", FONT_BORDER) + 3; // don't draw range scale right on top of labeled border, move into map draw_nice_string(w,pixmap_final,letter_style,x_screen+border_offset,y_screen-border_offset-3,text,0x10,0x20,len); } else { // draw range scale in lower left corder of map draw_nice_string(w,pixmap_final,letter_style,x_screen,y_screen,text,0x10,0x20,len); } } /* * Calculate and draw ruler on right bottom of screen */ void draw_ruler(Widget w) { int ruler_pix; // min size of ruler in pixel char unit[5+1]; // units char text[20]; // ruler text double ruler_siz; // len of ruler in meters etc. int mag; int i; int dx, dy; int border_offset = 0; // number of pixels to offset the scale if a labeled map border is drawn ruler_pix = (int)(screen_width / 9); // ruler size (in pixels) ruler_siz = ruler_pix * scale_x * calc_dscale_x(center_longitude,center_latitude); // size in meter if(english_units) { if (ruler_siz > 1609.3/2) { xastir_snprintf(unit, sizeof(unit), "mi"); ruler_siz /= 1609.3; } else { xastir_snprintf(unit, sizeof(unit), "ft"); ruler_siz /= 0.3048; } } else { xastir_snprintf(unit, sizeof(unit), "m"); if (ruler_siz > 1000/2) { xastir_snprintf(unit, sizeof(unit), "km"); ruler_siz /= 1000.0; } } mag = 1; while (ruler_siz > 5.0) // get magnitude { ruler_siz /= 10.0; mag *= 10; } // select best value and adjust ruler length if (ruler_siz > 2.0) { ruler_pix = (int)(ruler_pix * 5.0 / ruler_siz +0.5); ruler_siz = 5.0 * mag; } else { if (ruler_siz > 1.0) { ruler_pix = (int)(ruler_pix * 2.0 / ruler_siz +0.5); ruler_siz = 2.0 * mag; } else { ruler_pix = (int)(ruler_pix * 1.0 / ruler_siz +0.5); ruler_siz = 1.0 * mag; } } xastir_snprintf(text, sizeof(text), "%.0f %s",ruler_siz,unit); // Set up string //fprintf(stderr,"Ruler: %s, %d\n",text,ruler_pix); (void)XSetLineAttributes(XtDisplay(w),gc,1,LineSolid,CapRound,JoinRound); (void)XSetForeground(XtDisplay(w),gc,colors[0x20]); // white for (i = 8; i >= 0; i--) { dx = (((i / 3)+1) % 3)-1; // looks complicated... dy = (((i % 3)+1) % 3)-1; // I want 0 / 0 as last entry if ((draw_labeled_grid_border==TRUE) && long_lat_grid) { // move ruler up a few pixels to leave space for labeled border border_offset = get_rotated_label_text_length_pixels(w, "0", FONT_BORDER) + 3; dy = dy - border_offset - 3; dx = dx - border_offset - 3; } // If text on black background style selected, draw a black // rectangle in that corner of the map first so that the // scale lines show up well. // // If first time through and text-on-black style if ( (i == 8) && (letter_style == 2) ) { XSetForeground(XtDisplay(w),gc,colors[0x10]); // black (void)XSetLineAttributes(XtDisplay(w),gc,20,LineSolid,CapProjecting,JoinMiter); draw_test_line(w, dx, dy+5, ruler_pix, 0, ruler_pix); // Reset to needed parameters for drawing the scale (void)XSetLineAttributes(XtDisplay(w),gc,1,LineSolid,CapRound,JoinRound); (void)XSetForeground(XtDisplay(w),gc,colors[0x20]); // white } if (i == 0) { (void)XSetForeground(XtDisplay(w),gc,colors[0x10]); // black } draw_test_line(w,dx,dy, ruler_pix,0,ruler_pix); // hor line draw_test_line(w,dx,dy, 0,5, ruler_pix); // ver left draw_test_line(w,dx+ruler_pix,dy, 0,5, ruler_pix); // ver right if (text[0] == '2') { draw_test_line(w,dx+0.5*ruler_pix,dy,0,3,ruler_pix); // ver middle } if (text[0] == '5') { draw_test_line(w,dx+0.2*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.4*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.6*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.8*ruler_pix,dy,0,3,ruler_pix); // ver middle } } draw_ruler_text(w,text,ruler_pix); draw_range_scale(w); } /* * Display all stations on screen (trail, symbol, info text) */ void display_file(Widget w) { DataRow *p_station; // pointer to station data time_t temp_sec_heard; // time last heard time_t t_clr, t_old, now; if(debug_level & 1) { fprintf(stderr,"Display File Start\n"); } // Keep track of how many station we are currently displaying on // the screen. We'll display this number and the total number // of objects in the database as displayed/total on the status // line. Each time we call display_station() we'll bump this // number. currently_selected_stations = 0; // Draw probability of detection circle, if enabled //draw_pod_circle(64000000l, 32400000l, 10, colors[0x44], pixmap_final); now = sec_now(); t_old = now - sec_old; // precalc compare times t_clr = now - sec_clear; temp_sec_heard = 0l; p_station = t_oldest; // start with oldest station, have newest on top at t_newest while (p_station != NULL) { if (debug_level & 64) { fprintf(stderr,"display_file: Examining %s\n", p_station->call_sign); } // Skip deleted stations if ( !(p_station->flag & ST_ACTIVE) ) { if (debug_level & 64) { fprintf(stderr,"display_file: ignored deleted %s\n", p_station->call_sign); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } // Check for my objects/items // if ( (is_my_call(p_station->origin, 1) // If station is owned by me (including SSID) // && ( p_station->flag & ST_OBJECT // And it's an object // || p_station->flag & ST_ITEM) ) ) { // or an item // // This case is covered by the is_my_station() call, so we // don't need it here. // if (is_my_object_item(p_station) ) { // temp_sec_heard = now; // } // else { // Callsign match here includes checking SSID // temp_sec_heard = (is_my_call(p_station->call_sign,1))? now: p_station->sec_heard; temp_sec_heard = (is_my_station(p_station)) ? now : p_station->sec_heard; // } // Skip far away station if ((p_station->flag & ST_INVIEW) == 0) { // we make better use of the In View flag in the future if (debug_level & 256) { fprintf(stderr,"display_file: Station outside viewport\n"); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } // Skip if we're running an altnet and this station's not in // it if ( altnet && !is_altnet(p_station) ) { if (debug_level & 64) { fprintf(stderr,"display_file: Station %s skipped altnet\n", p_station->call_sign); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } if (debug_level & 256) { fprintf(stderr,"display_file: Inview, check for trail\n"); } // Display trail if we should if (Display_.trail && p_station->newest_trackpoint != NULL) { // ???????????? what is the difference? : if (debug_level & 256) { fprintf(stderr,"%s: Trails on and have track data\n", "display_file"); } if (temp_sec_heard > t_clr) { // Not too old, so draw trail if (temp_sec_heard > t_old) { // New trail, so draw solid trail if (debug_level & 256) { fprintf(stderr,"Drawing Solid trail for %s, secs old: %ld\n", p_station->call_sign, (long)(now - temp_sec_heard) ); } draw_trail(w,p_station,1); } else { if (debug_level & 256) { fprintf(stderr,"Drawing trail for %s, secs old: %ld\n", p_station->call_sign, (long)(now - temp_sec_heard) ); } draw_trail(w,p_station,0); } } else { if (debug_level & 256) { fprintf(stderr,"Station too old\n"); } } } else { if (debug_level & 256) { fprintf(stderr,"Station trails %d, track data %lx\n", Display_.trail, (long int)p_station->newest_trackpoint); } } if (debug_level & 256) { fprintf(stderr,"calling display_station()\n"); } // This routine will also update the // currently_selected_stations variable, if we're // updating all of the stations at once. display_station(w,p_station,0); p_station = p_station->t_newer; // next station } draw_ruler(w); Draw_All_CAD_Objects(w); // Draw all CAD objects, duh. // Check if we should mark where we found an address if (mark_destination && show_destination_mark) { int offset; // Set the line width in the GC. Make it nice and fat. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 7, LineSolid, CapButt,JoinMiter); (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); (void)(void)XSetFunction (XtDisplay (da), gc_tint, GXxor); // Scale it so that the 'X' stays the same size at all zoom // levels. offset = 25 * scale_y; // Make a big 'X' draw_vector(w, destination_coord_lon-offset, // x1 destination_coord_lat-offset, // y1 destination_coord_lon+offset, // x2 destination_coord_lat+offset, // y2 gc_tint, pixmap_final, 0); draw_vector(w, destination_coord_lon+offset, // x1 destination_coord_lat-offset, // y1 destination_coord_lon-offset, // x2 destination_coord_lat+offset, // y2 gc_tint, pixmap_final, 0); } // And last, draw the ALOHA circle if (Display_.aloha_circle) { if (aloha_radius != -1) { // if we actually have an aloha radius calculated already long l_lat,l_lon; l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); draw_aloha_circle(l_lon, l_lat, aloha_radius, colors[0x0e], pixmap_final); } } // Check whether currently_selected_stations has changed. If // so, set station_count_save to 0 so that main.c will come // along and update the counts on the status line. if (currently_selected_stations != currently_selected_stations_save) { station_count_save = 0; // Cause an update to occur } currently_selected_stations_save = currently_selected_stations; if (debug_level & 1) { fprintf(stderr,"Display File Stop\n"); } } ////////////////////////////// Station Info ///////////////////////////////////// /* * Delete Station Info PopUp */ void Station_data_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&db_station_info_lock, "db.c:Station_data_destroy_shell" ); XtDestroyWidget(shell); db_station_info = (Widget)NULL; end_critical_section(&db_station_info_lock, "db.c:Station_data_destroy_shell" ); } /* * Store track data for current station */ void Station_data_store_track(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { DataRow *p_station = clientData; //busy_cursor(XtParent(w)); busy_cursor(appshell); // Grey-out button so it doesn't get pressed twice XtSetSensitive(button_store_track,FALSE); // Store trail to file export_trail(p_station); #ifdef HAVE_LIBSHP // Save trail as a Shapefile map create_map_from_trail(p_station->call_sign); #endif // HAVE_LIBSHP // store trail to kml file export_trail_as_kml(p_station); } /* * Delete tracklog for current station */ void Station_data_destroy_track( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { DataRow *p_station = clientData; if (delete_trail(p_station)) { redraw_on_new_data = 2; // redraw immediately } } // This function merely reformats the button callback in order to // call wx_alert_double_click_action, which expects the parameter in // calldata instead of in clientData. // void Station_data_wx_alert(Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { //fprintf(stderr, "Station_data_wx_alert start\n"); wx_alert_finger_output( w, clientData); //fprintf(stderr, "Station_data_wx_alert end\n"); } void Station_data_add_fcc(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char temp[500]; FccAppl my_data; char *station = (char *) clientData; (void)check_fcc_data(); //busy_cursor(XtParent(w)); busy_cursor(appshell); if (search_fcc_data_appl(station, &my_data)==1) { /*fprintf(stderr,"FCC call %s\n",station);*/ xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s %s %s\n%s %s, %s %s, %s %s\n\n", langcode("STIFCC0001"), langcode("STIFCC0003"),my_data.name_licensee, langcode("STIFCC0004"),my_data.text_street,my_data.text_pobox, langcode("STIFCC0005"),my_data.city, langcode("STIFCC0006"),my_data.state, langcode("STIFCC0007"),my_data.zipcode); XmTextInsert(si_text,0,temp); XmTextShowPosition(si_text,0); fcc_lookup_pushed = 1; } } void Station_data_add_rac(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char temp[512]; char club[512]; rac_record my_data; char *station = (char *) clientData; xastir_snprintf(temp, sizeof(temp), " "); (void)check_rac_data(); //busy_cursor(XtParent(w)); busy_cursor(appshell); if (search_rac_data(station, &my_data)==1) { /*fprintf(stderr,"IC call %s\n",station);*/ xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s\n%s, %s\n%s\n", langcode("STIFCC0002"),my_data.first_name,my_data.last_name,my_data.address, my_data.city,my_data.province,my_data.postal_code); if (my_data.qual_a[0] == 'A') strncat(temp, langcode("STIFCC0008"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_d[0] == 'D') strncat(temp, langcode("STIFCC0009"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_b[0] == 'B' && my_data.qual_c[0] != 'C') strncat(temp, langcode("STIFCC0010"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_c[0] == 'C') strncat(temp, langcode("STIFCC0011"), sizeof(temp) - 1 - strlen(temp)); strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); if (strlen(my_data.club_name) > 1) { xastir_snprintf(club, sizeof(club), "%s\n%s\n%s, %s\n%s\n", my_data.club_name, my_data.club_address, my_data.club_city, my_data.club_province, my_data.club_postal_code); strncat(temp, club, sizeof(temp) - 1 - strlen(temp)); } strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); XmTextInsert(si_text,0,temp); XmTextShowPosition(si_text,0); rac_lookup_pushed = 1; } } void Station_query_trace(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRST", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_messages(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRSM", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_direct(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRSD", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_version(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?VER", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void General_query(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *location = (char *) clientData; char temp[50]; xastir_snprintf(temp, sizeof(temp), "?APRS?%s", location); output_my_data(temp,-1,0,0,0,NULL); // Not igating } void IGate_query(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { output_my_data("?IGATE?",-1,0,0,0,NULL); // Not igating } void WX_query(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { output_my_data("?WX?",-1,0,0,0,NULL); // Not igating } // Global variables for use with routines following Widget change_tactical_dialog = (Widget)NULL; Widget tactical_text = (Widget)NULL; DataRow *tactical_pointer = NULL; void Change_tactical_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); change_tactical_dialog = (Widget)NULL; } void Change_tactical_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; temp = XmTextGetString(tactical_text); if (tactical_pointer->tactical_call_sign == NULL) { // Malloc some memory to hold it. tactical_pointer->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); } if (tactical_pointer->tactical_call_sign != NULL) { // Check for blank tactical call. If so, free the space. if (temp[0] == '\0') { free(tactical_pointer->tactical_call_sign); tactical_pointer->tactical_call_sign = NULL; } else { xastir_snprintf(tactical_pointer->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", temp); } fprintf(stderr, "Assigned tactical call \"%s\" to %s\n", temp, tactical_pointer->call_sign); // Log the change in the tactical_calls.log file. // Also adds it to the tactical callsign hash here. log_tactical_call(tactical_pointer->call_sign, tactical_pointer->tactical_call_sign); } else { fprintf(stderr, "Couldn't malloc space for tactical callsign\n"); } XtFree(temp); redraw_on_new_data = 2; // redraw now Change_tactical_destroy_shell(widget,clientData,callData); } void Change_tactical(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close, label, scrollwindow; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count if (!change_tactical_dialog) { change_tactical_dialog = XtVaCreatePopupShell(langcode("WPUPSTI065"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Change Tactical pane", xmPanedWindowWidgetClass, change_tactical_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("Change Tactical scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Change Tactical my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // set args for color ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Display the callsign or object/item name we're working on // in a label at the top of the dialog. Otherwise we don't // know what station we're operating on. // label = XtVaCreateManagedWidget(tactical_pointer->call_sign, xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); tactical_text = XtVaCreateManagedWidget("Change_Tactical text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, MAX_TACTICAL_CALL, XmNwidth, ((MAX_TACTICAL_CALL*7)+2), XmNmaxLength, MAX_TACTICAL_CALL, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // Fill in the current value of tactical callsign XmTextSetString(tactical_text, tactical_pointer->tactical_call_sign); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tactical_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tactical_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Change_tactical_change_data, change_tactical_dialog); XtAddCallback(button_close, XmNactivateCallback, Change_tactical_destroy_shell, change_tactical_dialog); pos_dialog(change_tactical_dialog); delw = XmInternAtom(XtDisplay(change_tactical_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(change_tactical_dialog, delw, Change_tactical_destroy_shell, (XtPointer)change_tactical_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, change_tactical_dialog); XtPopup(change_tactical_dialog,XtGrabNone); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(change_tactical_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(change_tactical_dialog), XtWindow(change_tactical_dialog)); } } /* * Assign a tactical call to a station */ void Assign_Tactical_Call( Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; //fprintf(stderr,"Object Name: %s\n", p_station->call_sign); tactical_pointer = p_station; Change_tactical(w, p_station, NULL); } /* * Change the trail color for a station */ void Change_trail_color( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; int temp; temp = p_station->trail_color; // Increment to the next color, round-robin style temp = (temp + 1) % MAX_TRAIL_COLORS; // Test for and skip if my trail color if (temp == MY_TRAIL_COLOR) { temp = (temp + 1) % MAX_TRAIL_COLORS; } p_station->trail_color = temp; redraw_on_new_data = 2; // redraw symbols now } static void PosTestExpose(Widget parent, XtPointer UNUSED(clientData), XEvent * UNUSED(event), Boolean * UNUSED(continueToDispatch) ) { Position x, y; XtVaGetValues(parent, XmNx, &x, XmNy, &y, NULL); if (debug_level & 1) { fprintf(stderr,"Window Decoration Offsets: X:%d\tY:%d\n", x, y); } // Store the new-found offets in global variables decoration_offset_x = (int)x; decoration_offset_y = (int)y; // Get rid of the event handler and the test dialog XtRemoveEventHandler(parent, ExposureMask, True, (XtEventHandler) PosTestExpose, (XtPointer)NULL); // XtRemoveGrab(XtParent(parent)); // Not needed? XtDestroyWidget(XtParent(parent)); } // Here's a stupid trick that we have to do in order to find out how big // window decorations are. We need to know this information in order to // be able to kill/recreate dialogs in the same place each time. If we // were to just get and set the X/Y values of the dialog, we would creep // across the screen by the size of the decorations each time. // I've seen it. It's ugly. // void compute_decorations( void ) { Widget cdtest = (Widget)NULL; Widget cdform = (Widget)NULL; Cardinal n = 0; Arg args[50]; // We'll create a dummy dialog at 0,0, then query its // position. That'll give us back the position of the // widget. Subtract 0,0 from it (easy huh?) and we get // the size of the window decorations. Store these values // in global variables for later use. n = 0; XtSetArg(args[n], XmNx, 0); n++; XtSetArg(args[n], XmNy, 0); n++; cdtest = (Widget) XtVaCreatePopupShell("compute_decorations test", xmDialogShellWidgetClass, appshell, args, n, NULL); n = 0; XtSetArg(args[n], XmNwidth, 0); n++; // Make it tiny XtSetArg(args[n], XmNheight, 0); n++; // Make it tiny cdform = XmCreateForm(cdtest, "compute_decorations test form", args, n); XtAddEventHandler(cdform, ExposureMask, True, (XtEventHandler) PosTestExpose, (XtPointer)NULL); XtManageChild(cdform); XtManageChild(cdtest); } // Enable/disable auto-update of Station_data dialog void station_data_auto_update_toggle ( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { station_data_auto_update = 1; } else { station_data_auto_update = 0; } } // Fill in the station data window with real data void station_data_fill_in ( Widget w, XtPointer clientData, XtPointer calldata ) { DataRow *p_station; char *station = (char *) clientData; char temp[300]; int pos, last_pos; char temp_my_distance[20]; char temp_my_course[25]; char temp1_my_course[20]; float temp_out_C, e, humidex; long l_lat, l_lon; float value; WeatherRow *weather; time_t sec; struct tm *time; int i; int track_count = 0; // Maximum tracks listed in Station Info dialog. This prevents // lockups on extremely long tracks. #define MAX_TRACK_LIST 50 db_station_info_callsign = (char *) clientData; // Used for auto-updating this dialog temp_out_C=0; pos=0; begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); if (db_station_info == NULL) // We don't have a dialog to write to { end_critical_section(&db_station_info_lock, "db.c:Station_data" ); return; } if (!search_station_name(&p_station,station,1) // Can't find call, || (p_station->flag & ST_ACTIVE) == 0) // or found deleted objects { end_critical_section(&db_station_info_lock, "db.c:Station_data" ); return; } // Clear the text XmTextSetString(si_text,NULL); // Weather Data ... if (p_station->weather_data != NULL // Make sure the timestamp on the weather is current && (int)(((sec_old + p_station->weather_data->wx_sec_time)) >= sec_now()) ) { last_pos = pos; weather = p_station->weather_data; pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI024"),weather->wx_type,weather->wx_station); XmTextInsert(si_text,pos,temp); pos += strlen(temp); sprintf(temp, "\n"); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI026"),weather->wx_course,weather->wx_speed); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI025"),weather->wx_course,(int)(atof(weather->wx_speed)*1.6094)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (strlen(weather->wx_gust) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI028"),weather->wx_gust); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI027"),(int)(atof(weather->wx_gust)*1.6094)); } strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); } else { xastir_snprintf(temp, sizeof(temp), "\n"); } XmTextInsert(si_text, pos, temp); pos += strlen(temp); if (strlen(weather->wx_temp) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI030"),weather->wx_temp); } else { temp_out_C =(((atof(weather->wx_temp)-32)*5.0)/9.0); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI029"),temp_out_C); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_hum) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI031"),weather->wx_hum); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // NOTE: The below (Humidex) is not coded for english units, only for metric. // What is Humidex anyway? Heat Index? Wind Chill? --we7u // DK7IN: ??? english_units ??? if (strlen(weather->wx_hum) > 0 && strlen(weather->wx_temp) > 0 && (!english_units) && (atof(weather->wx_hum) > 0.0) ) { e = (float)(6.112 * pow(10,(7.5 * temp_out_C)/(237.7 + temp_out_C)) * atof(weather->wx_hum) / 100.0); humidex = (temp_out_C + ((5.0/9.0) * (e-10.0))); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI032"),humidex); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_baro) > 0) { if (!english_units) // hPa { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI033"), weather->wx_baro); } else // Inches Mercury { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI063"), atof(weather->wx_baro)*0.02953); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if(last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } } if (strlen(weather->wx_snow) > 0) { if(english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI035"),atof(weather->wx_snow)); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI034"),atof(weather->wx_snow)*2.54); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain) > 0 || strlen(weather->wx_prec_00) > 0 || strlen(weather->wx_prec_24) > 0) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI036")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI038"),atof(weather->wx_rain)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI037"),atof(weather->wx_rain)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_prec_24) > 0) { if(english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI040"),atof(weather->wx_prec_24)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI039"),atof(weather->wx_prec_24)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_prec_00) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI042"),atof(weather->wx_prec_00)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI041"),atof(weather->wx_prec_00)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain_total) > 0) { xastir_snprintf(temp, sizeof(temp), "\n%s",langcode("WPUPSTI046")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI048"),atof(weather->wx_rain_total)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI047"),atof(weather->wx_rain_total)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Fuel temp/moisture for RAWS weather stations if (strlen(weather->wx_fuel_temp) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI061"),weather->wx_fuel_temp); } else { temp_out_C =(((atof(weather->wx_fuel_temp)-32)*5.0)/9.0); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI060"),temp_out_C); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_fuel_moisture) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI062"),weather->wx_fuel_moisture); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Packets received ... xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI005"),p_station->num_packets); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time); temp[2]='/'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+2); temp[2]='/'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+4); temp[4]=' '; temp[5]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+8); temp[2]=':'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+10); temp[2]=':'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+12); temp[2]='\n'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Object if (strlen(p_station->origin) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI000"),p_station->origin); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Print the tactical call, if any if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI065"), p_station->tactical_call_sign); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Heard via TNC ... if ((p_station->flag & ST_VIATNC) != 0) // test "via TNC" flag { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI006"),p_station->heard_via_tnc_port); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI007")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } switch(p_station->data_via) { case('L'): xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI008")); break; case('T'): xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI009"),p_station->last_port_heard); break; case('I'): xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI010"),p_station->last_port_heard); break; case('F'): xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI011")); break; case(DATA_VIA_DATABASE): xastir_snprintf(temp, sizeof(temp), "last via db on interface %d",p_station->last_port_heard); break; default: xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI012")); break; } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->newest_trackpoint != NULL) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI013")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Echoed from: ... // Callsign check here includes checking SSID // if (is_my_call(p_station->call_sign,1)) { if ( is_my_station(p_station) ) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI055")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); for (i=0; i<6; i++) { if (echo_digis[i][0] == '\0') { break; } xastir_snprintf(temp, sizeof(temp), " %s",echo_digis[i]); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Data Path ... if (p_station->node_path_ptr != NULL) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI043"),p_station->node_path_ptr); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI043"), ""); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Status ... if(p_station->status_data != NULL) // Found at least one record { CommentRow *ptr; ptr = p_station->status_data; while (ptr != NULL) { // We don't care if the pointer is NULL. This will // succeed anyway. It'll just make an empty string. // Note that text_ptr may be an empty string. That's // ok. //Also print the sec_heard timestamp. sec = ptr->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI059"), time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, ptr->text_ptr); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); ptr = ptr->next; // Advance to next record (if any) } } // // Comments ... // if(strlen(p_station->comments)>0) { // xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI044"),p_station->comments); // XmTextInsert(si_text,pos,temp); // pos += strlen(temp); // xastir_snprintf(temp, sizeof(temp), "\n"); // XmTextInsert(si_text,pos,temp); // pos += strlen(temp); // } // Comments ... if(p_station->comment_data != NULL) // Found at least one record { CommentRow *ptr; ptr = p_station->comment_data; while (ptr != NULL) { // We don't care if the pointer is NULL. This will // succeed anyway. It'll just make an empty string. // Note that text_ptr can be an empty string. That's // ok. //Also print the sec_heard timestamp. sec = ptr->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI044"), time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, ptr->text_ptr); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); ptr = ptr->next; // Advance to next record (if any) } } // Current Power Gain ... if (strlen(p_station->power_gain) == 7) { // Check for RNG instead of PHG if (p_station->power_gain[0] == 'R') { // Found a Range xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI067"), atoi(&p_station->power_gain[3])); } else { // Found PHG phg_decode(langcode("WPUPSTI014"), // "Current Power Gain" p_station->power_gain, temp, sizeof(temp) ); } // Check for Map View symbol: Eyeball symbol with // RNG // extension. if ( strncmp(p_station->power_gain,"RNG",3) == 0 && p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'E' ) { //fprintf(stderr,"Found a Map View 'eyeball' symbol!\n"); // Center_Zoom() normally fills in the values with the // current zoom/center for the map window. We want to // be able to override these with our own values in this // case, derived from the object info. center_zoom_override++; Center_Zoom(w,NULL,(XtPointer)p_station); } } else if (p_station->flag & (ST_OBJECT | ST_ITEM)) { xastir_snprintf(temp, sizeof(temp), "%s %s", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI068") ); // "none" } else if (english_units) { xastir_snprintf(temp, sizeof(temp), "%s %s (9W @ 20ft %s, 3dB %s, %s 6.2mi)", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI069"), // "default" langcode("WPUPSTI070"), // "HAAT" langcode("WPUPSTI071"), // "omni" langcode("WPUPSTI072") ); // "range" // "default (9W @ 20ft HAAT, 3dB omni, range 6.2mi)"); } else { xastir_snprintf(temp, sizeof(temp), "%s %s (9W @ 6.1m %s, 3dB %s, %s 10.0km)", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI069"), // "default" langcode("WPUPSTI070"), // "HAAT" langcode("WPUPSTI071"), // "omni" langcode("WPUPSTI072") ); // "range" // "default (9W @ 6.1m HAAT, 3dB omni, range 10.0km)"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Current DF Info ... if (strlen(p_station->signal_gain) == 7) { shg_decode(langcode("WPUPSTI057"), p_station->signal_gain, temp, sizeof(temp) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(p_station->bearing) == 3) { bearing_decode(langcode("WPUPSTI058"), p_station->bearing, p_station->NRQ, temp, sizeof(temp) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Signpost Data if (strlen(p_station->signpost) > 0) { xastir_snprintf(temp, sizeof(temp), "%s: %s",langcode("POPUPOB029"), p_station->signpost); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Altitude ... last_pos=pos; if (strlen(p_station->altitude) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI016"),atof(p_station->altitude)*3.28084,"ft"); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI016"),atof(p_station->altitude),"m"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Course ... if (strlen(p_station->course) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI017"),p_station->course); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Speed ... if (strlen(p_station->speed) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI019"),atof(p_station->speed)*1.1508); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI018"),atof(p_station->speed)*1.852); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Distance ... last_pos = pos; // do my course // if (!is_my_call(p_station->call_sign,1)) { // Checks SSID as well if ( !(is_my_station(p_station)) ) // Checks SSID as well { l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(l_lat,l_lon,p_station->coord_lat, p_station->coord_lon,temp1_my_course,sizeof(temp1_my_course)); // n7tap: This is a quick hack to get some more useful values for // distance to near objects. if (english_units) { if (value*1.15078 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.15078*1760), langcode("SPCHSTR004")); // yards } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI020"), // miles value*1.15078); } } else { if (value*1.852 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.852*1000), langcode("UNIOP00031")); // 'm' as in meters } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI021"), // km value*1.852); } } xastir_snprintf(temp_my_course, sizeof(temp_my_course), "%s\xB0",temp1_my_course); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI022"),temp_my_distance,temp_my_course); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if(last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Last Position sec = p_station->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), "%s%02d/%02d %02d:%02d ",langcode("WPUPSTI023"), time->tm_mon + 1, time->tm_mday,time->tm_hour,time->tm_min); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { convert_xastir_to_UTM_str(temp, sizeof(temp), p_station->coord_lon, p_station->coord_lat); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str(temp, sizeof(temp), p_station->coord_lon, p_station->coord_lat, 0); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), " "); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_DDDDDD) { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (p_station->altitude[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %5.0f%s", atof(p_station->altitude)*cvt_m2len, un_alt); } else { substr(temp," ",1+5+strlen(un_alt)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->speed[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %4.0f%s",atof(p_station->speed)*cvt_kn2len,un_spd); } else { substr(temp," ",1+4+strlen(un_spd)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->course[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %3d\xB0",atoi(p_station->course)); } else { xastir_snprintf(temp, sizeof(temp), " "); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // dl9sau // Maidenhead Grid Locator xastir_snprintf(temp, sizeof(temp), " %s", sec_to_loc(p_station->coord_lon, p_station->coord_lat) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if ((p_station->flag & ST_DIRECT) != 0) { xastir_snprintf(temp, sizeof(temp), " *\n"); } else { xastir_snprintf(temp, sizeof(temp), " \n"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // list rest of trail data if (p_station->newest_trackpoint != NULL) { TrackRow *ptr; ptr = p_station->newest_trackpoint; // Skip the first (latest) trackpoint as if it exists, it'll // be the same as the data in the station record, which we // just printed out. if (ptr->prev != NULL) { ptr = ptr->prev; } while ( (ptr != NULL) && (track_count <= MAX_TRACK_LIST) ) { track_count++; sec = ptr->sec; time = localtime(&sec); if ((ptr->flag & TR_NEWTRK) != '\0') xastir_snprintf(temp, sizeof(temp), " + %02d/%02d %02d:%02d ", time->tm_mon + 1,time->tm_mday,time->tm_hour,time->tm_min); else xastir_snprintf(temp, sizeof(temp), " %02d/%02d %02d:%02d ", time->tm_mon + 1,time->tm_mday,time->tm_hour,time->tm_min); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { convert_xastir_to_UTM_str(temp, sizeof(temp), ptr->trail_long_pos, ptr->trail_lat_pos); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str(temp, sizeof(temp), ptr->trail_long_pos, ptr->trail_lat_pos, 0); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), " "); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_DDDDDD) { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (ptr->altitude > -99999l) xastir_snprintf(temp, sizeof(temp), " %5.0f%s", ptr->altitude * cvt_dm2len, un_alt); else { substr(temp," ",1+5+strlen(un_alt)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (ptr->speed >= 0) xastir_snprintf(temp, sizeof(temp), " %4.0f%s", ptr->speed * cvt_hm2len, un_spd); else { substr(temp," ",1+4+strlen(un_spd)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (ptr->course >= 0) xastir_snprintf(temp, sizeof(temp), " %3d\xB0", ptr->course); else { xastir_snprintf(temp, sizeof(temp), " "); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // dl9sau xastir_snprintf(temp, sizeof(temp), " %s", sec_to_loc(ptr->trail_long_pos, ptr->trail_lat_pos) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if ((ptr->flag & TR_LOCAL) != '\0') { xastir_snprintf(temp, sizeof(temp), " *\n"); } else { xastir_snprintf(temp, sizeof(temp), " \n"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Go back in time one trackpoint ptr = ptr->prev; } } if (fcc_lookup_pushed) { Station_data_add_fcc(w, clientData, calldata); } else if (rac_lookup_pushed) { Station_data_add_rac(w, clientData, calldata); } XmTextShowPosition(si_text,0); end_critical_section(&db_station_info_lock, "db.c:Station_data" ); } /* * Track from Station_data * * Called by Station_data function below from the Track Station * button in Station Info. */ void Track_from_Station_data(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; if (p_station->call_sign[0] != '\0') { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", p_station->call_sign); track_station_on = 1; } else { tracking_station_call[0] = '\0'; } } /* * Clear DF from Station_data * * Called by Station_data function below from the Clear DF Bearing * button in Station Info. */ void Clear_DF_from_Station_data(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; if (strlen(p_station->bearing) == 3) { // we have DF data to clear p_station->bearing[0]='\0'; p_station->NRQ[0]='\0'; } } /* * List station info and trail * If calldata is non-NULL, then we drop straight through to the * Modify->Object or Assign_Tactical_Call dialogs. * * Input parameters: * clientData: Station callsign * * calldata: NULL = Station Info * "1" = Object -> Modify * "2" = Move Object * "3" = Assign Tactical Call * "4" = Send Message To * */ void Station_data(Widget w, XtPointer clientData, XtPointer calldata) { DataRow *p_station; char *station = (char *) clientData; static char local_station[25]; char temp[300]; unsigned int n; Atom delw; static Widget pane, form, button_cancel, button_message, button_nws, button_fcc, button_rac, button_clear_track, button_trace, button_messages, button_object_modify, button_direct, button_version, station_icon, station_call, station_type, station_data_auto_update_w, button_tactical, button_change_trail_color, button_track_station,button_clear_df,scrollwindow; Arg args[50]; Pixmap icon; Position x,y; // For saving current dialog position //fprintf(stderr,"db.c:Station_data start\n"); busy_cursor(appshell); db_station_info_callsign = (char *) clientData; // Used for auto-updating this dialog // Make a copy of the name. xastir_snprintf(local_station,sizeof(local_station),"%s",station); if (search_station_name(&p_station,station,1) // find call && (p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { } else { fprintf(stderr,"Couldn't find station in database\n"); return; // Don't update current/create new dialog } if (calldata != NULL) // We were called from the { // Object->Modify, Assign Tactical Call, // or Send Message To menu items. if (strncmp(calldata,"1",1) == 0) { Modify_object(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"2",1) == 0) { Modify_object(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"3",1) == 0) { Assign_Tactical_Call(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"4",1) == 0) { //fprintf(stderr,"Send Message To: %s\n", p_station->call_sign); Send_message_call(NULL, (XtPointer) p_station->call_sign, NULL); } return; } // If we haven't calculated our decoration offsets yet, do so now if ( (decoration_offset_x == 0) && (decoration_offset_y == 0) ) { compute_decorations(); } if (db_station_info != NULL) // We already have a dialog { // This is a pain. We can get the X/Y position, but when // we restore the new dialog to the same position we're // off by the width/height of our window decorations. Call // above was added to pre-compute the offsets that we'll need. XtVaGetValues(db_station_info, XmNx, &x, XmNy, &y, NULL); // This call doesn't work. It returns the widget location, // just like the XtVaGetValues call does. I need the window // decoration location instead. //XtTranslateCoords(db_station_info, 0, 0, &xnew, &ynew); //fprintf(stderr,"%d:%d\t%d:%d\n", x, xnew, y, ynew); if (last_station_info_x == 0) { last_station_info_x = x - decoration_offset_x; } if (last_station_info_y == 0) { last_station_info_y = y - decoration_offset_y; } // Now get rid of the old dialog Station_data_destroy_shell(db_station_info, db_station_info, NULL); } else { // Clear the global state variables fcc_lookup_pushed = 0; rac_lookup_pushed = 0; } begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); if (db_station_info == NULL) { // Start building the dialog from the bottom up. That way // we can keep the buttons attached to the bottom of the // form and the correct height, and let the text widget // grow/shrink as the dialog is resized. db_station_info = XtVaCreatePopupShell(langcode("WPUPSTI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station Data pane", xmPanedWindowWidgetClass, db_station_info, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("State Data scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Station Data form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 4, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Start with the bottom row, left button button_clear_track = NULL; // Need this later, don't delete! if (p_station->newest_trackpoint != NULL) { // [ Clear Track ] button_clear_track = XtVaCreateManagedWidget(langcode("WPUPSTI045"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear_track, XmNactivateCallback, Station_data_destroy_track,(XtPointer)p_station); } else { // DK7IN: I drop the version button for mobile stations // we just have too much buttons... // and should find another solution // [ Station Version Query ] button_version = XtVaCreateManagedWidget(langcode("WPUPSTI052"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_version, XmNactivateCallback, Station_query_version,(XtPointer)p_station->call_sign); } // [ Trace Query ] button_trace = XtVaCreateManagedWidget(langcode("WPUPSTI049"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_trace, XmNactivateCallback, Station_query_trace,(XtPointer)p_station->call_sign); // [ Un-Acked Messages Query ] button_messages = XtVaCreateManagedWidget(langcode("WPUPSTI050"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_messages, XmNactivateCallback, Station_query_messages,(XtPointer)p_station->call_sign); // [ Direct Stations Query ] button_direct = XtVaCreateManagedWidget(langcode("WPUPSTI051"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_direct, XmNactivateCallback, Station_query_direct,(XtPointer)p_station->call_sign); // Now proceed to the row above it, left button first // [ Store Track ] or single Position button_store_track = XtVaCreateManagedWidget(langcode("WPUPSTI054"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, //XmNtopWidget,XtParent(si_text), XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, (button_clear_track) ? button_clear_track : button_version, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_store_track, XmNactivateCallback, Station_data_store_track,(XtPointer)p_station); if ( ((p_station->flag & ST_OBJECT) == 0) && ((p_station->flag & ST_ITEM) == 0) ) // Not an object/ { // fprintf(stderr,"Not an object or item...\n"); // [Send Message] button_message = XtVaCreateManagedWidget(langcode("WPUPSTI002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_trace, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_message, XmNactivateCallback, Send_message_call,(XtPointer)p_station->call_sign); } else { // fprintf(stderr,"Found an object or item...\n"); button_object_modify = XtVaCreateManagedWidget(langcode("WPUPSTI053"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_trace, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_object_modify, XmNactivateCallback, Modify_object, (XtPointer)p_station); } // Check whether it is a non-weather alert object/item. If // so, try to use the origin callsign instead of the object // for FCC/RAC lookups. // if ( (p_station->flag & ST_OBJECT) || (p_station->flag & ST_ITEM) ) { // It turns out that objects transmitted by a station // called "WINLINK" are what mess up the RAC button for // Canadian stations. Xastir sees the 'W' of WINLINK // (the originating station) and assumes it is a U.S. // station. Here's a sample packet: // // WINLINK>APWL2K,TCPIP*,qAC,T2MIDWEST:;VE7SEP-10*240521z4826.2 NW12322.5 Wa145.690MHz 1200b R11m RMSPacket EMCOMM // // If match on "WINLINK": Don't copy origin callsign // into local_station. Use the object name instead // which should be a callsign. if (strncmp(p_station->origin,"WINLINK",7)) { xastir_snprintf(local_station,sizeof(local_station),"%s",p_station->origin); } } // Add "Fetch NWS Info" button if it is an object or item // and has "WXSVR" in its path somewhere. // // Note from Dale Huguley: // "I would say an object with 6 upper alpha chars for the // "from" call and " {AAAAA" (space curly 5 alphanumerics) // at the end is almost guaranteed to be from Wxsvr. // Fingering for the six alphas and the first three // characters after the curly brace should be a reliable // finger - as in SEWSVR>APRS::a_bunch_of_info_in_here_ // {H45AA finger SEWSVRH45@wxsvr.net" // // Note from Curt: I had to remove the space from the // search as well, 'cuz the multipoint objects don't have // the space before the final curly-brace. // if ( ( (p_station->flag & ST_OBJECT) || (p_station->flag & ST_ITEM) ) && (p_station->comment_data != NULL) && ( strstr(p_station->comment_data->text_ptr, "{") != NULL ) ) { static char temp[25]; char *ptr3; button_nws = XtVaCreateManagedWidget(langcode("WPUPSTI064"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // We need to construct the "special" finger address. // We'll use the FROM callsign and the first three chars // of the curly-brace portion of the comment field. // Callsign in this case is from the "origin" field. // The curly-brace text is at the end of one of the // "comment_data" records, hopefully the first one // checked (most recent). // xastir_snprintf(temp, sizeof(temp), "%s", p_station->origin); temp[6] = '\0'; ptr3 = strstr(p_station->comment_data->text_ptr,"{"); ptr3++; // Skip over the '{' character strncat(temp,ptr3,3); //fprintf(stderr,"New Handle: %s\n", temp); XtAddCallback(button_nws, XmNactivateCallback, Station_data_wx_alert, (XtPointer)temp); } // Add FCC button only if probable match. The U.S. has // these prefixes assigned but not all are used for amateur // stations: // // AAA-ALZ // KAA-KZZ // NAA-NZZ // WAA-WZZ // else if ((! strncmp(local_station,"A",1)) || (! strncmp(local_station,"K",1)) || (! strncmp(local_station,"N",1)) || (! strncmp(local_station,"W",1)) ) { button_fcc = XtVaCreateManagedWidget(langcode("WPUPSTI003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_fcc, XmNactivateCallback, Station_data_add_fcc, (XtPointer)local_station); if ( ! check_fcc_data()) { XtSetSensitive(button_fcc,FALSE); } } // Add RAC button only if probable match. Canada has these // prefixes assigned but not all are used for amateur // stations: // // CFA-CKZ // CYA-CZZ // VAA-VGZ // VOA-VOZ // VXA-VYZ // XJA-XOZ // else if (!strncmp(local_station,"VA",2) || !strncmp(local_station,"VE",2) || !strncmp(local_station,"VO",2) || !strncmp(local_station,"VY",2)) { button_rac = XtVaCreateManagedWidget(langcode("WPUPSTI004"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_rac, XmNactivateCallback, Station_data_add_rac, (XtPointer)local_station); if ( ! check_rac_data()) { XtSetSensitive(button_rac,FALSE); } } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_direct, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Station_data_destroy_shell, db_station_info); // Button to clear DF bearing data if we actually have some. if (strlen(p_station->bearing) == 3) { button_clear_df = XtVaCreateManagedWidget(langcode("WPUPSTI092"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_cancel, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear_df, XmNactivateCallback,Clear_DF_from_Station_data, (XtPointer)p_station); } button_track_station = XtVaCreateManagedWidget(langcode("WPUPTSP001"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_store_track, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, // XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_track_station, XmNactivateCallback,Track_from_Station_data, (XtPointer)p_station); // Now build from the top of the dialog to the buttons. icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)), 20,20,DefaultDepthOfScreen(XtScreen(appshell))); symbol(db_station_info,0,p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay,icon,0,0,0,' '); station_icon = XtVaCreateManagedWidget("Station Data icon", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNlabelType, XmPIXMAP, XmNlabelPixmap,icon, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); station_type = XtVaCreateManagedWidget("Station Data type", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns,5, XmNwidth,((5*7)+2), XmNbackground, colors[0xff], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,station_icon, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%c%c%c", p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay); XmTextFieldSetString(station_type, temp); XtManageChild(station_type); station_call = XtVaCreateManagedWidget("Station Data call", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns,10, XmNwidth,((10*7)+2), XmNbackground, colors[0xff], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_type, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); XmTextFieldSetString(station_call,p_station->call_sign); XtManageChild(station_call); station_data_auto_update_w = XtVaCreateManagedWidget(langcode("WPUPSTI056"), xmToggleButtonGadgetClass, form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_call, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNbackground,colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(station_data_auto_update_w,XmNvalueChangedCallback,station_data_auto_update_toggle,"1"); //Add tactical button at the top/right // "Assign Tactical Call" button_tactical = XtVaCreateManagedWidget(langcode("WPUPSTI066"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftOffset, 10, XmNleftWidget, station_data_auto_update_w, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_tactical, XmNactivateCallback, Assign_Tactical_Call, (XtPointer)p_station); if (p_station->flag & (ST_OBJECT | ST_ITEM)) { // We don't allow setting tac-calls for objects/items, // so make the button insensitive. XtSetSensitive(button_tactical,FALSE); } //Add change_trail_color button at the top/right // "Trail Color" button_change_trail_color = XtVaCreateManagedWidget(langcode("WPUPSTI091"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftOffset, 10, XmNleftWidget, button_tactical, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_change_trail_color, XmNactivateCallback, Change_trail_color, (XtPointer)p_station); n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 100); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNbackground, colors[0xff]); n++; XtSetArg(args[n], XmNscrollHorizontal, FALSE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, station_icon); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; // XtSetArg(args[n], XmNbottomWidget, button_store_track); n++; XtSetArg(args[n], XmNbottomWidget, button_track_station); n++; XtSetArg(args[n], XmNbottomOffset, 1); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; si_text = NULL; si_text = XmCreateScrolledText(form,"Station_data",args,n); end_critical_section(&db_station_info_lock, "db.c:Station_data" ); // Fill in the si_text widget with real data station_data_fill_in( w, (XtPointer)db_station_info_callsign, NULL); begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); pos_dialog(db_station_info); delw = XmInternAtom(XtDisplay(db_station_info),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(db_station_info, delw, Station_data_destroy_shell, (XtPointer)db_station_info); XtManageChild(form); XtManageChild(si_text); XtVaSetValues(si_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(form, db_station_info); if (station_data_auto_update) { XmToggleButtonSetState(station_data_auto_update_w,TRUE,FALSE); } if (calldata == NULL) // We're not going straight to the Modify dialog { // and will actually use the dialog we just drew XtPopup(db_station_info,XtGrabNone); XmTextShowPosition(si_text,0); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } } end_critical_section(&db_station_info_lock, "db.c:Station_data" ); } // Used for auto-refreshing the Station_info dialog. Called from // main.c:UpdateTime() every 30 seconds. // void update_station_info(Widget w) { begin_critical_section(&db_station_info_lock, "db.c:update_station_info" ); // If we have a dialog to update and a callsign to pass to it if (( db_station_info != NULL) && (db_station_info_callsign != NULL) && (strlen(db_station_info_callsign) != 0) ) { end_critical_section(&db_station_info_lock, "db.c:update_station_info" ); // Fill in the si_text widget with real data station_data_fill_in( w, (XtPointer)db_station_info_callsign, NULL); } else { end_critical_section(&db_station_info_lock, "db.c:update_station_info" ); } } /* * Station Info Selection PopUp window: Canceled */ void Station_info_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; // We used to close the detailed Station Info dialog here too, which // makes no sense. Commenting this out so that we can close the // Station Chooser but leave the Station Info dialog open. // // if (db_station_info!=NULL) // Station_data_destroy_shell(db_station_info, db_station_info, NULL); XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),SiS_icon0); (void)XFreePixmap(XtDisplay(appshell),SiS_icon); begin_critical_section(&db_station_popup_lock, "db.c:Station_info_destroy_shell" ); XtDestroyWidget(shell); db_station_popup = (Widget)NULL; end_critical_section(&db_station_popup_lock, "db.c:Station_info_destroy_shell" ); } // Global parameter so that we can pass another value to the below // function from the Station_info() function. We need to be able to // pass this value off to the Station_data() function for special // operations like moves, where objects are on top of each other. // XtPointer station_info_select_global = NULL; /* * Station Info Selection PopUp window: Quit with selected station */ void Station_info_select_destroy_shell(Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *temp; char temp2[50]; XmString *list; int found; //Widget shell = (Widget) clientData; found=0; begin_critical_section(&db_station_popup_lock, "db.c:Station_info_select_destroy_shell" ); if (db_station_popup) { XtVaGetValues(station_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(station_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } // DK7IN ?? should we not first close the PopUp, then call Station_data ?? if (found) { xastir_snprintf(temp2, sizeof(temp2), "%s", temp); // Only keep the station info, remove Tactical Call Sign temp2[strcspn(temp2, "(")] = '\0'; remove_trailing_spaces(temp2); // Call it with the global parameter at the last, so we // can pass special parameters down that we couldn't // directly pass to Station_info_select_destroy_shell(). Station_data(widget, temp2, station_info_select_global); // Clear the global variable so that nothing else calls // it with the wrong parameter station_info_select_global = NULL; XtFree(temp); } /* // This section of code gets rid of the Station Chooser. Frank wanted to // be able to leave the Station Chooser up after selection so that other // stations could be selected, therefore I commented this out. XtPopdown(shell); // Get rid of the station chooser popup here (void)XFreePixmap(XtDisplay(appshell),SiS_icon0); (void)XFreePixmap(XtDisplay(appshell),SiS_icon); XtDestroyWidget(shell); // and here db_station_popup = (Widget)NULL; // and here */ } end_critical_section(&db_station_popup_lock, "db.c:Station_info_select_destroy_shell" ); } /* * Station Info PopUp * if only one station in view it shows the data with Station_data() * otherwise we get a selection box * clientData will be non-null if we wish to drop through to the object->modify * or Assign Tactical Call dialogs. * * clientData: NULL = Station Info * "1" = Object -> Modify * "2" = Move Object * "3" = Assign Tactical Call * "4" = Send Message To */ void Station_info(Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station; DataRow *p_found; int num_found = 0; unsigned long min_diff_x, diff_x, min_diff_y, diff_y; XmString str_ptr; unsigned int n; Atom delw; static Widget pane, form, button_ok, button_cancel; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ char tactical_string[50]; busy_cursor(appshell); min_diff_y = scale_y * 20; // Pixels each way in y-direction. min_diff_x = scale_x * 20; // Pixels each way in x-direction. p_found = NULL; p_station = n_first; // Here we just count them. We go through the same type of code // again later if we find more than one station. while (p_station != NULL) // search through database for nearby stations { if ( ( (p_station->flag & ST_INVIEW) != 0) && ok_to_draw_station(p_station) ) // only test stations in view { if (!altnet || is_altnet(p_station)) { // Here we calculate diff in terms of XX pixels, // changed into lat/long values. This keeps the // affected rectangle the same at any zoom level. // scale_y/scale_x is Xastir units/pixel. Xastir // units are in 1/100 of a second. If we want to go // 10 pixels in any direction (roughly, scale_x // varies by latitude), then we want (10 * scale_y), // and (10 * scale_x) if we want to make a very // accurate square. diff_y = (unsigned long)( labs((NW_corner_latitude+(menu_y*scale_y)) - p_station->coord_lat)); diff_x = (unsigned long)( labs((NW_corner_longitude+(menu_x*scale_x)) - p_station->coord_lon)); // If the station fits within our bounding box, // count it if ((diff_y < min_diff_y) && (diff_x < min_diff_x)) { p_found = p_station; num_found++; } } } p_station = p_station->n_next; } if (p_found != NULL) // We found at least one station { if (num_found == 1) { // We only found one station, so it's easy Station_data(w,p_found->call_sign,clientData); } else // We found more: create dialog to choose a station { // Set up this global variable so that we can pass it // off to Station_data from the // Station_info_select_destroy_shell() function above. // Without this global variable we don't have enough // parameters passed to the final routine, so we can't // move an object that is on top of another. With it, // we can. station_info_select_global = clientData; if (db_station_popup != NULL) { Station_info_destroy_shell(db_station_popup, db_station_popup, NULL); } begin_critical_section(&db_station_popup_lock, "db.c:Station_info" ); if (db_station_popup == NULL) { // Set up a selection box: db_station_popup = XtVaCreatePopupShell(langcode("STCHO00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station_info pane",xmPanedWindowWidgetClass, db_station_popup, XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Station_info form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Attach buttons first to the bottom of the form, // so that we'll be able to stretch this thing // vertically to see all the callsigns. // button_ok = XtVaCreateManagedWidget("Info",xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Station_info_destroy_shell, db_station_popup); XtAddCallback(button_ok, XmNactivateCallback, Station_info_select_destroy_shell, db_station_popup); /*set args for color */ ac = 0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 6); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNbottomWidget, button_ok); ac++; XtSetArg(al[ac], XmNbottomOffset, 5); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_list = XmCreateScrolledList(form,"Station_info list",al,ac); // DK7IN: I want to add the symbol in front of the call... // icon SiS_icon0 = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); SiS_icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); /* SiS_symb = XtVaCreateManagedWidget("Station_info icon", xmLabelWidgetClass, ob_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, SiS_icon, XmNbackground, colors[0xff], XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL); */ /*fprintf(stderr,"What station\n");*/ n = 1; p_station = n_first; while (p_station != NULL) // search through database for nearby stations { if ( ( (p_station->flag & ST_INVIEW) != 0) && ok_to_draw_station(p_station) ) // only test stations in view { if (!altnet || is_altnet(p_station)) { diff_y = (unsigned long)( labs((NW_corner_latitude+(menu_y*scale_y)) - p_station->coord_lat)); diff_x = (unsigned long)( labs((NW_corner_longitude+(menu_x*scale_x)) - p_station->coord_lon)); // If the station fits within our // bounding box, count it. if ((diff_y < min_diff_y) && (diff_x < min_diff_x)) { /*fprintf(stderr,"Station %s\n",p_station->call_sign);*/ if (p_station->tactical_call_sign) { xastir_snprintf(tactical_string, sizeof(tactical_string), "%s (%s)", p_station->call_sign, p_station->tactical_call_sign); XmListAddItem(station_list, str_ptr = XmStringCreateLtoR(tactical_string, XmFONTLIST_DEFAULT_TAG), (int)n++); } else { XmListAddItem(station_list, str_ptr = XmStringCreateLtoR(p_station->call_sign, XmFONTLIST_DEFAULT_TAG), (int)n++); } XmStringFree(str_ptr); } } } p_station = p_station->n_next; } pos_dialog(db_station_popup); delw = XmInternAtom(XtDisplay(db_station_popup),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(db_station_popup, delw, Station_info_destroy_shell, (XtPointer)db_station_popup); XtManageChild(form); XtManageChild(station_list); XtVaSetValues(station_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XtPopup(db_station_popup,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } end_critical_section(&db_station_popup_lock, "db.c:Station_info" ); } } } int heard_via_tnc_in_past_hour(char *call) { DataRow *p_station; int in_hour; in_hour=0; if (search_station_name(&p_station,call,1)) // find call { // Check the heard_via_tnc_last_time timestamp. This is a // timestamp that is saved each time a station is heard via // RF. It is initially set to 0. It does not get reset // when a packet comes in via a non-TNC interface. // if (p_station->heard_via_tnc_last_time) // non-zero entry { // Should we check to see if the last packet was message // capable? // Decide whether it was heard on a TNC interface within // the hour in_hour = (int)((p_station->heard_via_tnc_last_time+3600l) > sec_now()); if(debug_level & 2) fprintf(stderr, "Call %s: %ld %ld ok %d\n", call, (long)(p_station->heard_via_tnc_last_time), (long)sec_now(), in_hour); } else { if (debug_level & 2) { fprintf(stderr,"Call %s Not heard via tnc\n",call); } } } else { if (debug_level & 2) { fprintf(stderr,"IG:station not found\n"); } } return(in_hour); } //////////////////////////////////// Weather Data ////////////////////////////////////////////////// /* valid characters for APRS weather data fields */ int is_aprs_chr(char ch) { if (isdigit((int)ch) || ch==' ' || ch=='.' || ch=='-') { return(1); } else { return(0); } } int count_filler_chars(char ch) { if (isdigit((int)ch) || ch==' ' || ch=='.' || ch=='-') { return(1); } else { return(0); } } /* check data format 123 ___ ... */ // We wish to count how many ' ' or '.' characters we find. If it // equals zero or the field width, it might be a weather field. If // not, then it might be part of a comment field or something else. // int is_weather_data(char *data, int len) { int ok = 1; int i; int count = 0; for (i=0; ok && i= 8 && data[0] =='g' && is_weather_data(&data[1],3) && data[4] =='t' && is_weather_data(&data[5],3)) { // Snag WX course/speed from compressed position data. // This speed is in knots. This assumes that we've // already extracted speed/course from the compressed // packet. extract_comp_position() extracts // course/speed as well. memcpy(speed, p_station->speed, sizeof(speed)); speed[sizeof(speed)-1] = '\0'; // Terminate string memcpy(course, p_station->course, sizeof(course)); course[sizeof(course)-1] = '\0'; // Terminate string in_knots = 1; //fprintf(stderr,"Found compressed wx\n"); } // Look for weather data in non-fixed locations (RAWS WX // Stations?) else if ( strlen(data) >= 8 && test_extract_weather_item(data,'g',3) && test_extract_weather_item(data,'t',3) ) { // Snag WX course/speed from compressed position data. // This speed is in knots. This assumes that we've // already extracted speed/course from the compressed // packet. extract_comp_position() extracts // course/speed as well. memcpy(speed, p_station->speed, sizeof(speed)); speed[sizeof(speed)-1] = '\0'; // Terminate string memcpy(course, p_station->course, sizeof(course)); course[sizeof(course)-1] = '\0'; // Terminate string in_knots = 1; //fprintf(stderr,"Found compressed WX in non-fixed locations! %s:%s\n", // p_station->call_sign,data); } else // No weather data found { ok = 0; //fprintf(stderr,"No compressed wx\n"); } } else // Look for non-compressed weather data { // Look for weather data in defined locations first if (strlen(data)>=15 && data[3]=='/' && is_weather_data(data,3) && is_weather_data(&data[4],3) && data[7] =='g' && is_weather_data(&data[8], 3) && data[11]=='t' && is_weather_data(&data[12],3)) // Complete Weather Report { // Get speed/course. Speed is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { // Try to get speed/course from 's' and 'c' fields // (another wx format). Speed is in mph. (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found Complete Weather Report\n"); } // Look for date/time and weather in fixed locations first else if (strlen(data)>=16 && data[0] =='c' && is_weather_data(&data[1], 3) && data[4] =='s' && is_weather_data(&data[5], 3) && data[8] =='g' && is_weather_data(&data[9], 3) && data[12]=='t' && is_weather_data(&data[13],3)) // Positionless Weather Data { //fprintf(stderr,"Found positionless wx data\n"); // Try to snag speed/course out of first 7 bytes. Speed // is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { //fprintf(stderr,"Trying again for course/speed\n"); // Also try to get speed/course from 's' and 'c' fields // (another wx format) (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found weather\n"); } // Look for weather data in non-fixed locations (RAWS WX // Stations?) else if (strlen (data) >= 16 && test_extract_weather_item(data,'h',2) && test_extract_weather_item(data,'g',3) && test_extract_weather_item(data,'t',3) ) { // Try to snag speed/course out of first 7 bytes. Speed // is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { // Also try to get speed/course from 's' and 'c' fields // (another wx format) (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found WX in non-fixed locations! %s:%s\n", // p_station->call_sign,data); } else // No weather data found { ok = 0; //fprintf(stderr,"No wx found\n"); } } if (ok) { ok = get_weather_record(p_station); // get existing or create new weather record } if (ok) { weather = p_station->weather_data; // Copy into weather speed variable. Convert knots to mph // if necessary. if (in_knots) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", atoi(speed) * 1.1508); // Convert knots to mph } else { // Already in mph. Copy w/no conversion. xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%s", speed); } xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%s", course); if (compr) // course/speed was taken from normal data, delete that { // fix me: we delete a potential real speed/course now // we should differentiate between normal and weather data in compressed position decoding... // p_station->speed_time[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; } (void)extract_weather_item(data,'g',3,weather->wx_gust); // gust (peak wind speed in mph in the last 5 minutes) (void)extract_weather_item(data,'t',3,weather->wx_temp); // temperature (in deg Fahrenheit), could be negative (void)extract_weather_item(data,'r',3,weather->wx_rain); // rainfall (1/100 inch) in the last hour (void)extract_weather_item(data,'p',3,weather->wx_prec_24); // rainfall (1/100 inch) in the last 24 hours (void)extract_weather_item(data,'P',3,weather->wx_prec_00); // rainfall (1/100 inch) since midnight if (extract_weather_item(data,'h',2,weather->wx_hum)) // humidity (in %, 00 = 100%) { xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d",(atoi(weather->wx_hum)+99)%100+1); } if (extract_weather_item(data,'b',5,weather->wx_baro)) // barometric pressure (1/10 mbar / 1/10 hPascal) xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", (float)(atoi(weather->wx_baro)/10.0)); // If we parsed a speed/course, a second 's' parameter means // snowfall. Try to parse it, but only in the case where // we've parsed speed out of this packet already. if ( (speed[0] != '\0') && (course[0] != '\0') ) { (void)extract_weather_item(data,'s',3,weather->wx_snow); // snowfall, inches in the last 24 hours } (void)extract_weather_item(data,'L',3,temp); // luminosity (in watts per square meter) 999 and below (void)extract_weather_item(data,'l',3,temp); // luminosity (in watts per square meter) 1000 and above (void)extract_weather_item(data,'#',3,temp); // raw rain counter (void)extract_weather_item(data,'F',3,weather->wx_fuel_temp); // Fuel Temperature in °F (RAWS) if (extract_weather_item(data,'f',2,weather->wx_fuel_moisture))// Fuel Moisture (RAWS) (in %, 00 = 100%) xastir_snprintf(weather->wx_fuel_moisture, sizeof(weather->wx_fuel_moisture), "%03d", (atoi(weather->wx_fuel_moisture)+99)%100+1); // extract_weather_item(data,'w',3,temp); // ?? text wUII // now there should be the name of the weather station... // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); // Set the timestamp in the weather record so that we can // decide whether or not to "ghost" the weather data later. weather->wx_sec_time=sec_now(); // weather->wx_data=1; // we don't need this // case ('.'):/* skip */ // wx_strpos+=4; // break; // default: // wx_done=1; // weather->wx_type=data[wx_strpos]; // if(strlen(data)>wx_strpos+1) // xastir_snprintf(weather->wx_station, // sizeof(weather->wx_station), // "%s", // data+wx_strpos+1); // break; } return(ok); } // Initial attempt at decoding tropical storm, tropical depression, // and hurricane data. // // This data can be in an Object report, but can also be in an Item // or position report. // "/TS" = Tropical Storm // "/HC" = Hurricane // "/TD" = Tropical Depression // "/TY" = Typhoon // "/ST" = Super Typhoon // "/SC" = Severe Cyclone // The symbol will be either "\@" for current position, or "/@" for // predicted position. // int extract_storm(DataRow *p_station, char *data, int UNUSED(compr) ) { char time_data[MAX_TIME]; int ok = 1; WeatherRow *weather; char course[4]; char speed[4]; // Speed in knots char *p, *p2; // Should probably encode the storm type in the weather object and // print it out in plain text in the Station Info dialog. if ((p = strstr(data, "/TS")) != NULL) { // We have a Tropical Storm //fprintf(stderr,"Tropical Storm! %s\n",data); } else if ((p = strstr(data, "/TD")) != NULL) { // We have a Tropical Depression //fprintf(stderr,"Tropical Depression! %s\n",data); } else if ((p = strstr(data, "/HC")) != NULL) { // We have a Hurricane //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/TY")) != NULL) { // We have a Typhoon //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/ST")) != NULL) { // We have a Super Typhoon //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/SC")) != NULL) { // We have a Severe Cyclone //fprintf(stderr,"Hurricane! %s\n",data); } else // Not one of the three we're trying to decode { ok = 0; return(ok); } //fprintf(stderr,"\n%s\n",data); // Back up 7 spots to try to extract the next items p2 = p - 7; if (p2 >= data) { // Attempt to extract course/speed. Speed in knots. if (!extract_speed_course(p2,speed,course)) { // No speed/course to extract //fprintf(stderr,"No speed/course found\n"); ok = 0; return(ok); } } else // Not enough characters for speed/course. Must have { // guessed wrong on what type of data it is. //fprintf(stderr,"No speed/course found 2\n"); ok = 0; return(ok); } //fprintf(stderr,"%s\n",data); if (ok) { // If we got this far, we have speed/course and know what type // of storm it is. //fprintf(stderr,"Speed: %s, Course: %s\n",speed,course); ok = get_weather_record(p_station); // get existing or create new weather record } if (ok) { // p_station->speed_time[0] = '\0'; p_station->weather_data->wx_storm = 1; // We found a storm // Note that speed is in knots. If we were stuffing it into // "wx_speed" we'd have to convert it to MPH. if (strcmp(speed," ") != 0 && strcmp(speed,"...") != 0) { xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%s", speed); } else { p_station->speed[0] = '\0'; } if (strcmp(course," ") != 0 && strcmp(course,"...") != 0) xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", course); else { p_station->course[0] = '\0'; } weather = p_station->weather_data; p2++; // Skip the description text, "/TS", "/HC", "/TD", "/TY", "/ST", or "/SC" // Extract the sustained wind speed in knots if(extract_weather_item(p2,'/',3,weather->wx_speed)) // Convert from knots to MPH xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%0.1f", atof(weather->wx_speed) * 1.1508); //fprintf(stderr,"%s\n",data); // Extract gust speed in knots if (extract_weather_item(p2,'^',3,weather->wx_gust)) // gust (peak wind speed in knots) // Convert from knots to MPH xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%0.1f", atof(weather->wx_gust) * 1.1508); //fprintf(stderr,"%s\n",data); // Pressure is already in millibars/hPa. No conversion // needed. if (extract_weather_item(p2,'/',4,weather->wx_baro)) // barometric pressure (1/10 mbar / 1/10 hPascal) xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", atof(weather->wx_baro)); //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'>',3,weather->wx_hurricane_radius); // Nautical miles //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'&',3,weather->wx_trop_storm_radius); // Nautical miles //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'%',3,weather->wx_whole_gale_radius); // Nautical miles //fprintf(stderr,"%s\n",data); // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); // Set the timestamp in the weather record so that we can // decide whether or not to "ghost" the weather data later. weather->wx_sec_time=sec_now(); } return(ok); } /* * Look for information about other points associated with this station. * If found, compute the coordinates and save the information in the * station structure. * KG4NBB */ // If remove_string == 0, don't remove the string from the comment // field. Useful for objects/items where we need to retransmit the // string unchanged. #define MULTI_DEBUG 2048 #define LBRACE '{' #define RBRACE '}' #define START_STR " }" static void extract_multipoints(DataRow *p_station, char *data, int UNUSED(type), int remove_string) { // If they're in there, the multipoints start with the // sequence and end with a . // In addition, there must be no spaces in there, and there // must be an even number of characters (after the lead-in). char *p, *p2; int found = 0; char *end; int data_size; if (debug_level & MULTI_DEBUG) fprintf(stderr,"extract_multipoints: start processing %s\n", p_station->call_sign); if (data == NULL) { if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: No Data, returning\n"); } return; } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"Data: %s\t\t\n", data); } data_size = strlen(data); end = data + (strlen(data) - 7); // 7 == 3 lead-in chars, plus 2 points p_station->num_multipoints = 0; /* for (p = data; !found && p <= end; ++p) { if (*p == ' ' && *(p+1) == RBRACE && islower((int)*(p+2)) && isdigit((int)*(p+3)) && (p2 = strchr(p+4, LBRACE)) != NULL && ((p2 - p) % 2) == 1) { found = 1; } } */ // Start looking at the beginning of the data. p = data; if (debug_level & MULTI_DEBUG) { if (strstr(p,START_STR) == NULL) { fprintf(stderr," Data does not start with space-brace, it starts with %c%c\n", p[0],p[1]); } else { fprintf(stderr," Data starts with space-brace\n"); } } // Look for the opening string. while (!found && p < end && (p = strstr(p, START_STR)) != NULL) { // The opening string was found. Check the following information. if (debug_level & MULTI_DEBUG) fprintf(stderr," Found opening brace, next chars are %c %c %c\n", *(p+2),*(p+3),*(p+4)); if (islower((int)*(p+2)) && isdigit((int)*(p+3)) && (p2 = strchr(p+4, LBRACE)) != NULL && ((p2 - p) % 2) == 1) { // It all looks good! found = 1; } else { // The following characters are not right. Advance and // look again. if (debug_level & MULTI_DEBUG) { fprintf(stderr," Found opening string (}) but next characters are not right: %c %c %c\n",*(p+2),*(p+3),*(p+4)); } ++p; } } if (found) { long multiplier; double d; char *m_start = p; // Start of multipoint string char ok = 1; if (debug_level & MULTI_DEBUG) { fprintf(stderr,"station %s contains \"%s\"\n", p_station->call_sign, p); } // The second character (the lowercase) indicates additional style information, // such as color, line type, etc. p_station->style = *(p+2); // The third character (the digit) indicates the way the points should be // used. They may be used to draw a closed polygon, a series of line segments, // etc. p_station->type = *(p+3); // The fourth character indicates the scale of the coordinates that // follow. It may range from '!' to '|' (124). The value represents the // unit of measure (1, 0.1, 0.001, etc., in degrees) used in the offsets. // // Use the following formula to convert the char to the value: // (10 ^ ((c - 33) / 20)) / 10000 degrees // // Finally we have to convert to Xastir units. Xastir stores coordinates // as hudredths of seconds. There are 360,000 of those per degree, so we // need to multiply by that factor so our numbers will be converted to // Xastir units. p = p + 4; if (*p < '!' || *p > '|') { fprintf(stderr,"extract_multipoints: invalid scale character %d\n", *p); ok = 0; // Failure } else { d = (double)(*p); d = pow(10.0, ((d - 33) / 20)) / 10000.0 * 360000.0; multiplier = (long)d; if (debug_level & MULTI_DEBUG) { fprintf(stderr," multiplier factor is: %c %d %f (%ld)\n", *p, *p, d, multiplier); } ++p; // The remaining characters are in pairs. Each pair is the // offset lat and lon for one of the points. (The offset is // from the actual location of the object.) Convert each // character to its numeric value and save it. while (*p != LBRACE && p_station->num_multipoints < MAX_MULTIPOINTS) { // The characters are in the range '"' (34 decimal) to 'z' (122). They // encode values in the range -44 to +44. To convert to the correct // value 78 is subtracted from the character's value. int lat_val = *p - 78; int lon_val = *(p+1) - 78; // Check for correct values. if (lon_val < -44 || lon_val > 44 || lat_val < -44 || lat_val > 44) { char temp[MAX_LINE_SIZE+1]; int i; // Filter the string so we don't send strange // chars to the xterm for (i = 0; i < (int)strlen(data); i++) { temp[i] = data[i] & 0x7f; if ( (temp[i] < 0x20) || (temp[i] > 0x7e) ) { temp[i] = ' '; } } temp[strlen(data)] = '\0'; fprintf(stderr,"extract_multipoints: invalid value in (filtered) \"%s\": %d,%d\n", temp, lat_val, lon_val); p_station->num_multipoints = 0; // forget any points we already set ok = 0; // Failure to decode break; } // Malloc the storage area for this if we don't have // it yet. if (p_station->multipoint_data == NULL) { //fprintf(stderr, "Malloc'ing MultipointRow record, %s\n", p_station->call_sign); p_station->multipoint_data = malloc(sizeof(MultipointRow)); if (p_station->multipoint_data == NULL) { p_station->num_multipoints = 0; fprintf(stderr,"Couldn't malloc MultipointRow'\n"); if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: Malloc failure, returning\n"); } return; } } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"computed offset %d,%d\n", lat_val, lon_val); } // Add the offset to the object's position to obtain the position of the point. // Note that we're working in Xastir coordinates, and in North America they // are exactly opposite to lat/lon (larger numbers are farther east and south). // An offset with a positive value means that the point should be north and/or // west of the object, so we have to *subtract* the offset to get the correct // placement in Xastir coordinates. // TODO: Consider what we should do in the other geographic quadrants. Should we // check here for the correct sign of the offset? Or should the program that // creates the offsets take that into account? p_station->multipoint_data->multipoints[p_station->num_multipoints][0] = p_station->coord_lon - (lon_val * multiplier); p_station->multipoint_data->multipoints[p_station->num_multipoints][1] = p_station->coord_lat - (lat_val * multiplier); if (debug_level & MULTI_DEBUG) fprintf(stderr, "computed point %ld, %ld\n", p_station->multipoint_data->multipoints[p_station->num_multipoints][0], p_station->multipoint_data->multipoints[p_station->num_multipoints][1]); p += 2; ++p_station->num_multipoints; } // End of while loop } if (ok && remove_string) { // We've successfully decoded a multipoint object? // Remove the multipoint strings (and the sequence // number at the end if present) from the data string. // m_start points to the first character (a space). 'p' // should be pointing at the LBRACE character. // Make 'p' point to just after the end of the chars while ( (p < data+strlen(data)) && (*p != ' ') ) { p++; } // The string that 'p' points to now may be empty // Truncate "data" at the starting brace - 1 *m_start = '\0'; // Now we have two strings inside "data". Copy the 2nd // string directly onto the end of the first. strncat(data, p, data_size+1); // The multipoint string and sequence number should be // erased now from "data". //fprintf(stderr,"New Data: %s\n", data); } if (debug_level & MULTI_DEBUG) { fprintf(stderr," station has %d points\n", p_station->num_multipoints); } } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: Normal Return\n"); } } #undef MULTI_DEBUG //////////////////////////////////////////////////////////////////////////////////////////////////// void init_weather(WeatherRow *weather) // clear weather data { weather->wx_sec_time = (time_t)0; weather->wx_storm = 0; weather->wx_time[0] = '\0'; weather->wx_course[0] = '\0'; weather->wx_speed[0] = '\0'; weather->wx_speed_sec_time = 0; // ?? weather->wx_gust[0] = '\0'; weather->wx_hurricane_radius[0] = '\0'; weather->wx_trop_storm_radius[0] = '\0'; weather->wx_whole_gale_radius[0] = '\0'; weather->wx_temp[0] = '\0'; weather->wx_rain[0] = '\0'; weather->wx_rain_total[0] = '\0'; weather->wx_snow[0] = '\0'; weather->wx_prec_24[0] = '\0'; weather->wx_prec_00[0] = '\0'; weather->wx_hum[0] = '\0'; weather->wx_baro[0] = '\0'; weather->wx_fuel_temp[0] = '\0'; weather->wx_fuel_moisture[0] = '\0'; weather->wx_type = '\0'; weather->wx_station[0] = '\0'; } int get_weather_record(DataRow *fill) // get or create weather storage { int ok=1; if (fill->weather_data == NULL) // new weather data, allocate storage and init { fill->weather_data = malloc(sizeof(WeatherRow)); if (fill->weather_data == NULL) { fprintf(stderr,"Couldn't allocate memory in get_weather_record()\n"); ok = 0; } else { init_weather(fill->weather_data); } } return(ok); } int delete_weather(DataRow *fill) // delete weather storage, if allocated { if (fill->weather_data != NULL) { free(fill->weather_data); fill->weather_data = NULL; return(1); } return(0); } int delete_multipoints(DataRow *fill) // delete multipoint storage, if allocated { if (fill->multipoint_data != NULL) { //fprintf(stderr,"Removing multipoint data, %s\n", fill->call_sign); free(fill->multipoint_data); fill->multipoint_data = NULL; fill->num_multipoints = 0; return(1); } return(0); } ////////////////////////////////////////// Trails ////////////////////////////////////////////////// /* * See if current color is defined as active trail color */ int trail_color_active(int UNUSED(color_index)) { // this should be made configurable... // to select trail colors to use return(1); // accept this color } /* * Get new trail color for a call */ int new_trail_color(char *call) { int color, found, i; // If my_trail_diff_color is set a 0, then we'll // assign one color to every SSID from our callsign. If // 1, they get the next color available (round-robin style) just // like all the other stations. // // 0 for last parameter in is_my_call() means skip SSID in // callsign check. Non-zero means the callsign + SSID must be // an exact match. if (is_my_call(call,my_trail_diff_color)) { color = MY_TRAIL_COLOR; // It's my call, so use special color } else { // all other callsigns get some other color out of the color table color = current_trail_color; for(i=0,found=0; !found && icall_sign); if (debug_level & 256) { fprintf(stderr,"store_trail_point: for %s\n", p_station->call_sign); } // Allocate storage for the new track point ptr = malloc(sizeof(TrackRow)); if (ptr == NULL) { if (debug_level & 256) { fprintf(stderr,"store_trail_point: MALLOC failed for trail.\n"); } return(0); // Failed due to malloc } // Check whether we have any track data saved if (p_station->newest_trackpoint == NULL) { // new trail, do initialization if (debug_level & 256) { fprintf(stderr,"Creating new trail.\n"); } tracked_stations++; // Assign a new trail color 'cuz it's a new trail p_station->trail_color = new_trail_color(p_station->call_sign); } // Start linking the record to the new end of the chain ptr->prev = p_station->newest_trackpoint; // Link to record or NULL ptr->next = NULL; // Newest end of chain // Have an older record already? if (p_station->newest_trackpoint != NULL) // Yes { p_station->newest_trackpoint->next = ptr; } else // No, this is our first record { p_station->oldest_trackpoint = ptr; } // Link it in as our newest record p_station->newest_trackpoint = ptr; if (debug_level & 256) { fprintf(stderr,"store_trail_point: Storing data for %s\n", p_station->call_sign); } ptr->trail_long_pos = lon; ptr->trail_lat_pos = lat; ptr->sec = sec; if (alt[0] != '\0') { ptr->altitude = atoi(alt)*10; } else { ptr->altitude = -99999l; } if (speed[0] != '\0') { ptr->speed = (long)(atof(speed)*18.52); } else { ptr->speed = -1; } if (course[0] != '\0') { ptr->course = (int)(atof(course) + 0.5); // Poor man's rounding } else { ptr->course = -1; } flag = '\0'; // init flags if ((stn_flag & ST_DIRECT) != 0) { flag |= TR_LOCAL; // set "local" flag } if (ptr->prev != NULL) // we have at least two points... { // Check whether distance between points is too far. We // must convert from degrees to the Xastir coordinate system // units, which are 100th of a second. if ( labs(lon - ptr->prev->trail_long_pos) > (trail_segment_distance * 60*60*100) || labs(lat - ptr->prev->trail_lat_pos) > (trail_segment_distance * 60*60*100) ) { // Set "new track" flag if there's // "trail_segment_distance" degrees or more between // points. Originally was hard-coded to one degree, now // set by a slider in the timing dialog. flag |= TR_NEWTRK; } else { // Check whether trail went above our maximum time // between points. If so, don't draw segment. if (labs(sec - ptr->prev->sec) > (trail_segment_time *60)) { // Set "new track" flag if long delay between // reception of two points. Time is set by a slider // in the timing dialog. flag |= TR_NEWTRK; } } } else { // Set "new track" flag for first point received. flag |= TR_NEWTRK; } ptr->flag = flag; return(1); // We succeeded } /* * Check if current packet is a delayed echo */ int is_trailpoint_echo(DataRow *p_station) { int packets = 1; time_t checktime; char temp[50]; TrackRow *ptr; // Check whether we're to skip checking for dupes (reading in // objects/items from file is one such case). // if (skip_dupe_checking) { return(0); // Say that it isn't an echo } // Start at newest end of linked list and compare. Return if we're // beyond the checktime. ptr = p_station->newest_trackpoint; if (ptr == NULL) { return(0); // first point couldn't be an echo } checktime = p_station->sec_heard - TRAIL_ECHO_TIME*60; while (ptr != NULL) { if (ptr->sec < checktime) { return(0); // outside time frame, no echo found } if ((p_station->coord_lon == ptr->trail_long_pos) && (p_station->coord_lat == ptr->trail_lat_pos) && (p_station->speed[0] == '\0' || ptr->speed < 0 || (long)(atof(p_station->speed)*18.52) == ptr->speed) // current: char knots, trail: long 0.1m (-1 is undef) && (p_station->course[0] == '\0' || ptr->course <= 0 || atoi(p_station->course) == ptr->course) // current: char, trail: int (-1 is undef) && (p_station->altitude[0] == '\0' || ptr->altitude <= -99999l || atoi(p_station->altitude)*10 == ptr->altitude)) { // current: char, trail: int (-99999l is undef) if (debug_level & 1) { fprintf(stderr,"delayed echo for %s",p_station->call_sign); convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_HP_NORMAL); fprintf(stderr," at %s",temp); convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_HP_NORMAL); fprintf(stderr," %s, already heard %d packets ago\n",temp,packets); } return(1); // we found a delayed echo } ptr = ptr->prev; packets++; } return(0); // no echo found } // // Expire trail points. // // We now store track data in a doubly-linked list. Each record has a // pointer to the previous and the next record in the list. The main // station record has a pointer to the oldest and the newest end of the // chain, and the chain can be traversed in either order. We use // this to advantage by adding records at one end of the list and // expiring them at the other. // void expire_trail_points(DataRow *p_station, time_t sec) { int ii = 0; int done = 0; TrackRow *ptr; //fprintf(stderr,"expire_trail_points: %s\n",p_station->call_sign); if (debug_level & 256) { fprintf(stderr,"expire_trail_points: %s\n",p_station->call_sign); } // Check whether we have any track data saved if (p_station->oldest_trackpoint == NULL) { return; // Nothing to expire } // Iterate from oldest->newest trackpoints while (!done && p_station->oldest_trackpoint != NULL) { ptr = p_station->oldest_trackpoint; if ( (ptr->sec + sec) >= sec_now() ) { // New trackpoint, within expire time. Quit checking // the rest of the trackpoints for this station. done++; } else { //fprintf(stderr,"Found old trackpoint\n"); // Track too old. Unlink this trackpoint and free it. p_station->oldest_trackpoint = ptr->next; // End of chain in this direction if (p_station->oldest_trackpoint != NULL) { p_station->oldest_trackpoint->prev = NULL; } else { p_station->newest_trackpoint = NULL; } // Free up the space used by the expired trackpoint free(ptr); //fprintf(stderr,"Free'ing a trackpoint\n"); ii++; // Reduce our count of mobile stations if the size of // the track just went to zero. if (p_station->oldest_trackpoint == NULL) { tracked_stations--; } } } if ( (debug_level & 256) && ii ) { fprintf(stderr,"expire_trail_points: %d trackpoints free'd for %s\n", ii, p_station->call_sign); } } /* * Delete comment records and free memory */ int delete_comments_and_status(DataRow *fill) { // If the pointers are empty, we're done if ( (fill->comment_data == NULL) && (fill->status_data == NULL) ) { return(0); } if (fill->comment_data != NULL) // We have comment records { CommentRow *ptr; CommentRow *ptr_next; ptr = fill->comment_data; ptr_next = ptr->next; while (ptr != NULL) { // Free the actual text string that we malloc'ed if (ptr->text_ptr != NULL) { free(ptr->text_ptr); } free(ptr); ptr = ptr_next; // Advance to next record if (ptr != NULL) { ptr_next = ptr->next; } else { ptr_next = NULL; } } } if (fill->status_data != NULL) // We have status records { CommentRow *ptr; CommentRow *ptr_next; ptr = fill->status_data; ptr_next = ptr->next; while (ptr != NULL) { // Free the actual text string that we malloc'ed if (ptr->text_ptr != NULL) { free(ptr->text_ptr); } free(ptr); ptr = ptr_next; // Advance to next record if (ptr != NULL) { ptr_next = ptr->next; } else { ptr_next = NULL; } } } return(1); } /* * Delete trail and free memory */ int delete_trail(DataRow *fill) { if (fill->newest_trackpoint != NULL) { TrackRow *current; TrackRow *next; // Free the TrackRow records current = fill->oldest_trackpoint; while (current != NULL) { next = current->next; free(current); current = next; } fill->oldest_trackpoint = NULL; fill->newest_trackpoint = NULL; tracked_stations--; return(1); } return(0); } /* * Draw trail on screen. If solid=1, draw type LineSolid, else * draw type LineOnOffDash. * * If label_all_trackpoints=1, add the callsign next to each * trackpoint. We may modify this and just add the callsign at the * start/end of each new track segment. * */ void draw_trail(Widget w, DataRow *fill, int solid) { char short_dashed[2] = {(char)1,(char)5}; char medium_dashed[2] = {(char)5,(char)5}; unsigned long lat0, lon0, lat1, lon1; // trail segment points int col_trail, col_dot; XColor rgb; long brightness; char flag1; TrackRow *ptr; if (!ok_to_draw_station(fill)) { return; } // Expire old trackpoints first. We use the // remove-station-from-display time as the expire time for // trackpoints. This can be set from the Configure->Defaults // dialog. expire_trail_points(fill, sec_clear); ptr = fill->newest_trackpoint; // Trail should have at least two points if ( (ptr != NULL) && (ptr->prev != NULL) ) { int skip_dupes = 0; // Don't skip points first time through if (debug_level & 256) { fprintf(stderr,"draw_trail called for %s with %s.\n", fill->call_sign, (solid? "Solid" : "Non-Solid")); } col_trail = trail_colors[fill->trail_color]; // define color of position dots in trail rgb.pixel = col_trail; XQueryColor(XtDisplay(w),cmap,&rgb); brightness = (long)(0.3*rgb.red + 0.55*rgb.green + 0.15*rgb.blue); if (brightness > 32000l) { col_dot = trail_colors[0x05]; // black dot on light trails } else { col_dot = trail_colors[0x06]; // white dot on dark trail } if (solid) // Used to be "JoinMiter" and "CapButt" below { (void)XSetLineAttributes(XtDisplay(w), gc, 3, LineSolid, CapRound, JoinRound); } else { // Another choice is LineDoubleDash (void)XSetLineAttributes(XtDisplay(w), gc, 3, LineOnOffDash, CapRound, JoinRound); (void)XSetDashes(XtDisplay(w), gc, 0, short_dashed, 2); } // Traverse linked list of trail points from newest to // oldest while ( (ptr != NULL) && (ptr->prev != NULL) ) { lon0 = ptr->trail_long_pos; // Trail segment start lat0 = ptr->trail_lat_pos; lon1 = ptr->prev->trail_long_pos; // Trail segment end lat1 = ptr->prev->trail_lat_pos; flag1 = ptr->flag; // Are we at the start of a new trail? if ((flag1 & TR_NEWTRK) == '\0') { int lon0_screen, lat0_screen, lon1_screen, lat1_screen; // draw trail segment // (void)XSetForeground(XtDisplay(w),gc,col_trail); draw_vector(da, lon0, lat0, lon1, lat1, gc, pixmap_final, skip_dupes); // draw position point itself // (void)XSetForeground(XtDisplay(w),gc,col_dot); draw_point(w, lon0, lat0, gc, pixmap_final, skip_dupes); // Draw the callsign to go with the point if // label_all_trackpoints=1 // if (Display_.callsign && Display_.label_all_trackpoints) { // Convert to screen coordinates lon0_screen = (lon0 - NW_corner_longitude) / scale_x; lat0_screen = (lat0 - NW_corner_latitude) / scale_y; // Convert to screen coordinates. lon1_screen = (lon1 - NW_corner_longitude) / scale_x; lat1_screen = (lat1 - NW_corner_latitude) / scale_y; // The last position already gets its callsign // string drawn, plus that gets shifted based on // other parameters. Draw both points of all // line segments except that one. This will // result in strings getting drawn twice at // times, but they overlay on top of each other // so no big deal. // if (ptr != fill->newest_trackpoint) { draw_nice_string(da, pixmap_final, letter_style, lon0_screen+10, lat0_screen, fill->call_sign, 0x08, 0x0f, strlen(fill->call_sign)); // If not same screen position as last drawn if (lon0_screen != lon1_screen && lat0_screen != lat1_screen) { draw_nice_string(da, pixmap_final, letter_style, lon1_screen+10, lat1_screen, fill->call_sign, 0x08, 0x0f, strlen(fill->call_sign)); } } } } ptr = ptr->prev; skip_dupes = 1; } (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); } else if (debug_level & 256) { fprintf(stderr,"Trail for %s does not contain 2 or more points.\n", fill->call_sign); } } // DK7IN: there should be some library functions for the next two, // but I don't have any documentation while being in holidays... void month2str(int month, char *str, int str_size) { switch (month) { case 0: xastir_snprintf(str,str_size,"Jan"); break; case 1: xastir_snprintf(str,str_size,"Feb"); break; case 2: xastir_snprintf(str,str_size,"Mar"); break; case 3: xastir_snprintf(str,str_size,"Apr"); break; case 4: xastir_snprintf(str,str_size,"May"); break; case 5: xastir_snprintf(str,str_size,"Jun"); break; case 6: xastir_snprintf(str,str_size,"Jul"); break; case 7: xastir_snprintf(str,str_size,"Aug"); break; case 8: xastir_snprintf(str,str_size,"Sep"); break; case 9: xastir_snprintf(str,str_size,"Oct"); break; case 10: xastir_snprintf(str,str_size,"Nov"); break; case 11: xastir_snprintf(str,str_size,"Dec"); break; default: xastir_snprintf(str,str_size," "); break; } } void wday2str(int wday, char *str, int str_size) { switch (wday) { case 0: xastir_snprintf(str,str_size,"Sun"); break; case 1: xastir_snprintf(str,str_size,"Mon"); break; case 2: xastir_snprintf(str,str_size,"Tue"); break; case 3: xastir_snprintf(str,str_size,"Wed"); break; case 4: xastir_snprintf(str,str_size,"Thu"); break; case 5: xastir_snprintf(str,str_size,"Fri"); break; case 6: xastir_snprintf(str,str_size,"Sat"); break; default: xastir_snprintf(str,str_size," "); break; } } /* * Export trail point to file * * Don't call directly, call export_trail() or export_trail_as_kml() instead * as they need to open the file, set appropriate headers, and call export_trailstation() * to set the context for the position. */ void exp_trailpos(FILE *f,long lat,long lon,time_t sec,long speed,int course,long alt,int newtrk, int export_format) { struct tm *time; char lat_string[12+1]; char lon_string[12+1]; char month[3+1]; char wday[3+1]; float deg; time = gmtime(&sec); month2str(time->tm_mon, month, sizeof(month)); wday2str(time->tm_wday, wday, sizeof(wday)); switch (export_format) { case EXPORT_KML_TRACK: // kml format is longitude,latitude,altitude triplets with // a comma and no spaces separating elements of the triplet // and a single space separating sets of triplets in a // coordinates element. Latitude and longitude are // both in decimal degrees. deg = (float)(lon - 64800000l) / 360000.0; fprintf(f,"%09.5f,",deg); deg = -(float)(lat - 32400000l) / 360000.0; fprintf(f,"%08.5f,",deg); if (alt > -99999l) { fprintf(f,"%05.0f ",(float)(alt/10.0)); } else // undefined { fprintf(f,"0 "); } break; case EXPORT_XASTIR_TRACK: default: if (newtrk) { fprintf(f,"\nN New Track Start\n"); } // DK7IN: The format may change in the near future ! // Are there any standards? I want to be able to be compatible to // GPS data formats (e.g. G7TO) for easy interchange from/to GPS // How should we present undefined data? (speed/course/altitude) convert_lat_l2s(lat, lat_string, sizeof(lat_string), CONVERT_UP_TRK); convert_lon_l2s(lon, lon_string, sizeof(lon_string), CONVERT_UP_TRK); fprintf(f,"T %s",lat_string); fprintf(f," %s",lon_string); fprintf(f," %s %s %02d %02d:%02d:%02d %04d",wday,month,time->tm_mday,time->tm_hour,time->tm_min,time->tm_sec,time->tm_year+1900); if (alt > -99999l) { fprintf(f," %5.0fm",(float)(alt/10.0)); } else // undefined { fprintf(f," "); } if (speed >= 0) { fprintf(f," %4.0fkm/h",(float)(speed/10.0)); } else // undefined { fprintf(f," "); } if (course >= 0) // DK7IN: is 0 undefined ?? 1..360 ? { fprintf(f," %3d\xB0\n",course); } else // undefined { fprintf(f," \n"); } } } /* * Export trail for one station to file. * Don't call directly, call export_trail() or export_trail_as_kml() instead * as they need to open the file and set appropriate headers. * * @param f handle of file to write to * @param p_station pointer to station to write * @param export_format file format to use (xastir tracklog or kml). */ void exp_trailstation(FILE *f, DataRow *p_station, int export_format) { char timestring[101]; // string representation of the time heard or the current time long lat0, lon0; int newtrk; time_t sec; long speed; // 0.1km/h int course; // degrees long alt; // 0.1m TrackRow *current; newtrk = 1; current = p_station->oldest_trackpoint; switch (export_format) { case EXPORT_KML_TRACK: // This placemark is for a single position // or for the most recent position of a trail // in either case represented as a // and will show up as a labeled pushpin point. fprintf(f,""); get_iso_datetime(p_station->sec_heard,timestring,True,True); if (p_station->origin[0] == '\0') { fprintf(f,"%s\n",p_station->call_sign); fprintf(f,""); } else { fprintf(f,"%s\nObject from %s. \n",p_station->call_sign,p_station->origin); } // packets received %d last heard %s fprintf(f,langcode("WPUPSTI005"),p_station->num_packets, timestring); if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { // tactical call %s fprintf(f, langcode("WPUPSTI065"), p_station->tactical_call_sign); } fprintf(f,"\n"); // kml specifies w3c's date time format for timestamps if (get_w3cdtf_datetime(p_station->sec_heard, timestring, False, False)) if (strlen(timestring) > 0) { fprintf(f,"%s",timestring); } if (current != NULL) { // We have trail points, create both a set of time stamp labled point placemarks // and a linestring placemark to draw the trail. fprintf(f,"\n"); if (p_station->altitude[0] != '\0') { alt = atoi(p_station->altitude)*10; } else { alt = -99999l; } if (p_station->speed[0] != '\0') { speed = (long)(atof(p_station->speed)*18.52); } else { speed = -1; } if (p_station->course[0] != '\0') { course = atoi(p_station->course); } else { course = -1; } exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); fprintf(f,""); fprintf(f,"\n"); // follow with a set of timestamped placemarks for each point on trail while (current != NULL) { lon0 = current->trail_long_pos; // Trail segment start lat0 = current->trail_lat_pos; sec = current->sec; speed = current->speed; course = current->course; alt = current->altitude; // kml specifies w3c's date time format for timestamps if (get_w3cdtf_datetime(sec,timestring,False,False) && (int)sec>0) { // point has valid timestamp, write it fprintf(f,""); fprintf(f,"%s at %s\n",p_station->call_sign, timestring); fprintf(f,"%s",timestring); fprintf(f,""); exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); fprintf(f,""); fprintf(f,"\n"); } // Advance to the next point current = current->next; } // Prepare to follow with a trail (as a ). fprintf(f,""); if (p_station->origin[0] == '\0') { fprintf(f,"%s (trail)\n",p_station->call_sign); } else { fprintf(f,"%s (trail)\nObject from %s\n",p_station->call_sign,p_station->origin); } } break; case EXPORT_XASTIR_TRACK: default: if (p_station->origin[0] == '\0') { fprintf(f,"\n#C %s\n",p_station->call_sign); } else { fprintf(f,"\n#O %s %s\n",p_station->call_sign,p_station->origin); } } // A trail must have at least two points: One in the struct, // and one in the tracklog. If the station only has one point, // there won't be a tracklog. If the station has moved, then // it'll have both. // reset current, as we may have moved it past the last trackpoint // while generating kml above. current = p_station->oldest_trackpoint; if (current != NULL) // We have trail points, loop through { // them. Skip the most current position // because it is included in the // tracklog (if we have a tracklog!). switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n"); break; //default: // no heading for set of points } while (current != NULL) { lon0 = current->trail_long_pos; // Trail segment start lat0 = current->trail_lat_pos; sec = current->sec; speed = current->speed; course = current->course; alt = current->altitude; if ((current->flag & TR_NEWTRK) != '\0') { newtrk = 1; } // identical for kml and xastir tracks, but could be different for other formats switch (export_format) { case EXPORT_KML_TRACK: exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); break; case EXPORT_XASTIR_TRACK: default: exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); } newtrk = 0; // Advance to the next point current = current->next; } switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n\n"); break; //default: // no close for set of points } } else // We don't have any tracklog, so write out the most { // current position only. if (p_station->altitude[0] != '\0') { alt = atoi(p_station->altitude)*10; } else { alt = -99999l; } if (p_station->speed[0] != '\0') { speed = (long)(atof(p_station->speed)*18.52); } else { speed = -1; } if (p_station->course[0] != '\0') { course = atoi(p_station->course); } else { course = -1; } switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n\t"); exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); fprintf(f,"\n\t\n"); break; case EXPORT_XASTIR_TRACK: default: exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); } } switch (export_format) { case (EXPORT_KML_TRACK): fprintf(f,"\n"); break; case (EXPORT_XASTIR_TRACK): default: fprintf(f,"\n"); } } // // Export trail data for one or all stations to file // // If p_station == NULL, store all stations, else store only one // station. // void export_trail(DataRow *p_station) { char file[420]; FILE *f; time_t sec; struct tm *time; int storeall; char user_base_dir[MAX_VALUE]; sec = sec_now(); time = gmtime(&sec); if (p_station == NULL) { storeall = 1; } else { storeall = 0; } if (storeall) { // define filename for storing all station xastir_snprintf(file, sizeof(file), "%s/%04d%02d%02d-%02d%02d%02d.trk", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } else { // define filename for current station xastir_snprintf(file, sizeof(file), "%s/%s.trk", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), p_station->call_sign); } // create or open file (void)filecreate(file); // create empty file if it doesn't exist // DK7IN: owner should better be set to user, it is now root with kernel AX.25! f=fopen(file,"a"); // open file for append if (f != NULL) { fprintf(f, "# WGS-84 tracklog created by Xastir %04d/%02d/%02d %02d:%02d\n", time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min); if (storeall) { p_station = n_first; while (p_station != NULL) { exp_trailstation(f,p_station, EXPORT_XASTIR_TRACK); p_station = p_station->n_next; } } else { exp_trailstation(f,p_station, EXPORT_XASTIR_TRACK); } (void)fclose(f); } else { fprintf(stderr,"Couldn't create or open tracklog file %s\n",file); } } // // Export trail data for one or all stations to a klm file suitable for // loading into google earth/google maps/NASA worldwind etc. // For documentation of the KML (Keyhole Markup Language) format, // see: http:// // // @param p_station pointer to datarow containing station to export // If p_station == NULL, store all stations, else store only one // station. // void export_trail_as_kml(DataRow *p_station) { char file[420]; FILE *f; time_t sec; struct tm *time; int storeall; char user_base_dir[MAX_VALUE]; sec = sec_now(); time = gmtime(&sec); if (p_station == NULL) { storeall = 1; } else { storeall = 0; } if (storeall) { // define filename for storing all station xastir_snprintf(file, sizeof(file), "%s/%04d%02d%02d-%02d%02d%02d.kml", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } else { // define filename for current station, call + current time. xastir_snprintf(file, sizeof(file), "%s/%s_%04d%02d%02d-%02d%02d%02d.kml", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), p_station->call_sign, time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } // create or open file (void)filecreate(file); // create empty file if it doesn't exist // DK7IN: owner should better be set to user, it is now root with kernel AX.25! f=fopen(file,"w+"); // open file for writing if (f != NULL) { fprintf(f,"\n\n\nAPRS Data\n1\n"); fprintf(f, "WGS-84 tracklog created by Xastir %04d/%02d/%02d %02d:%02d\n", time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min); if (storeall) { p_station = n_first; while (p_station != NULL) { exp_trailstation(f,p_station,EXPORT_KML_TRACK); p_station = p_station->n_next; } } else { exp_trailstation(f,p_station,EXPORT_KML_TRACK); } fprintf(f,"\n"); (void)fclose(f); } else { fprintf(stderr,"Couldn't create or open tracklog file %s\n",file); } } ////////////////////////////////////// Station storage /////////////////////////////////////////// // Station storage is done in a double-linked list. In fact there are two such // pointer structures, one for sorting by name and one for sorting by time. // We store both the pointers to the next and to the previous elements. DK7IN /* * Setup station storage structure */ void init_station_data(void) { station_count = 0; // empty station list n_first = NULL; // pointer to next element in name sorted list n_last = NULL; // pointer to previous element in name sorted list t_oldest = NULL; // pointer to oldest element in time sorted list t_newest = NULL; // pointer to newest element in time sorted list last_sec = sec_now(); // check value for detecting changed seconds in time next_time_sn = 0; // serial number for unique time index current_trail_color = 0x00; // first trail color used will be 0x01 last_station_remove = sec_now(); // last time we checked for stations to remove } /* * Initialize station data */ void init_station(DataRow *p_station) { // the list pointers should already be set p_station->oldest_trackpoint = NULL; // no trail p_station->newest_trackpoint = NULL; // no trail p_station->trail_color = 0; p_station->weather_data = NULL; // no weather p_station->coord_lat = 0l; // 90°N \ undefined p_station->coord_lon = 0l; // 180°W / position p_station->pos_amb = 0; // No ambiguity p_station->error_ellipse_radius = 600; // In cm, default 6 meters p_station->lat_precision = 60; // In 100ths of seconds latitude (60 = 0.01 minutes) p_station->lon_precision = 60; // In 100ths of seconds longitude (60 = 0.01 minutes) p_station->call_sign[0] = '\0'; // ????? p_station->tactical_call_sign = NULL; p_station->sec_heard = 0; p_station->time_sn = 0; p_station->flag = 0; // set all flags to inactive p_station->object_retransmit = -1; // transmit forever p_station->last_transmit_time = sec_now(); // Used for object/item decaying algorithm p_station->transmit_time_increment = 0; // Used in data_add() // p_station->last_modified_time = 0; // Used for object/item dead-reckoning p_station->record_type = '\0'; p_station->data_via = '\0'; // L local, T TNC, I internet, F file p_station->heard_via_tnc_port = 0; p_station->heard_via_tnc_last_time = 0; p_station->last_port_heard = 0; p_station->num_packets = 0; p_station->aprs_symbol.aprs_type = '\0'; p_station->aprs_symbol.aprs_symbol = '\0'; p_station->aprs_symbol.special_overlay = '\0'; p_station->aprs_symbol.area_object.type = AREA_NONE; p_station->aprs_symbol.area_object.color = AREA_GRAY_LO; p_station->aprs_symbol.area_object.sqrt_lat_off = 0; p_station->aprs_symbol.area_object.sqrt_lon_off = 0; p_station->aprs_symbol.area_object.corridor_width = 0; // p_station->station_time_type = '\0'; p_station->origin[0] = '\0'; // no object p_station->packet_time[0] = '\0'; p_station->node_path_ptr = NULL; p_station->pos_time[0] = '\0'; // p_station->altitude_time[0] = '\0'; p_station->altitude[0] = '\0'; // p_station->speed_time[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; p_station->bearing[0] = '\0'; p_station->NRQ[0] = '\0'; p_station->power_gain[0] = '\0'; p_station->signal_gain[0] = '\0'; p_station->signpost[0] = '\0'; p_station->probability_min[0] = '\0'; p_station->probability_max[0] = '\0'; // p_station->station_time[0] = '\0'; p_station->sats_visible[0] = '\0'; p_station->status_data = NULL; p_station->comment_data = NULL; p_station->df_color = -1; // Show that there are no other points associated with this // station. We could also zero all the entries of the // multipoints[][] array, but nobody should be looking there // unless this is non-zero. // KG4NBB p_station->num_multipoints = 0; p_station->multipoint_data = NULL; } /* * Remove element from name ordered list */ void remove_name(DataRow *p_rem) // todo: return pointer to next element { int update_shortcuts = 0; int hash_key; // We use a 14-bit hash key // Do a quick check to see if we're removing a station record // that is pointed to by our pointer shortcuts array. // If so, update our pointer shortcuts after we're done. // // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((p_rem->call_sign[0] & 0x7f) << 7); hash_key = hash_key | (int)(p_rem->call_sign[1] & 0x7f); if (station_shortcuts[hash_key] == p_rem) { // Yes, we're trying to remove a record that a hash key // directly points to. We'll need to redo that hash key // after we remove the record. update_shortcuts++; } // Proceed to the station record removal // if (p_rem->n_prev == NULL) // Appears to be first element in list { if (n_first == p_rem) // Yes, head of list { // Make list head point to 2nd element in list (or NULL) // so that we can delete the current record. n_first = p_rem->n_next; } else // No, not first element in list. Problem! The { // list pointers are inconsistent for some reason. // The chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_name(): ERROR: p->n_prev == NULL but p != n_first\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up n_first to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the first element in the list. Fix up pointers { // to skip the current record. p_rem->n_prev->n_next = p_rem->n_next; } if (p_rem->n_next == NULL) // Appears to be last element in list { if (n_last == p_rem) // Yes, tail of list { // Make list tail point to previous element in list (or // NULL) so that we can delete the current record. n_last = p_rem->n_prev; } else // No, not last element in list. Problem! The list { // pointers are inconsistent for some reason. The // chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_name(): ERROR: p->n_next == NULL but p != n_last\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up n_last to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the last element in the list. Fix up pointers to { // skip the current record. p_rem->n_next->n_prev = p_rem->n_prev; } // Update our pointer shortcuts. Pass the removed hash_key to // the function so that we can try to redo just that hash_key // pointer. if (update_shortcuts) { //fprintf(stderr,"\t\t\t\t\t\tRemoval of hash key: %i\n", hash_key); // The -1 tells the function to redo all of the hash table // pointers because we deleted one of them. Later we could // optimize this so that only the specific pointer is fixed // up. station_shortcuts_update_function(-1, NULL); } } /* * Remove element from time ordered list */ void remove_time(DataRow *p_rem) // todo: return pointer to next element { if (p_rem->t_older == NULL) // Appears to be first element in list { if (t_oldest == p_rem) // Yes, head of list (oldest) { // Make oldest list head point to 2nd element in list (or NULL) // so that we can delete the current record. t_oldest = p_rem->t_newer; } else // No, not first (oldest) element in list. Problem! { // The list pointers are inconsistent for some // reason. The chain has been broken and we have // dangling pointers. fprintf(stderr, "remove_time(): ERROR: p->t_older == NULL but p != t_oldest\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up t_oldest to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the first (oldest) element in the list. Fix up { // pointers to skip the current record. p_rem->t_older->t_newer = p_rem->t_newer; } if (p_rem->t_newer == NULL) // Appears to be last (newest) element in list { if (t_newest == p_rem) // Yes, head of list (newest) { // Make newest list head point to previous element in // list (or NULL) so that we can delete the current // record. t_newest = p_rem->t_older; } else // No, not newest element in list. Problem! The { // list pointers are inconsistent for some reason. // The chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_time(): ERROR: p->t_newer == NULL but p != t_newest\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up t_newest to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the newest element in the list. Fix up pointers { // to skip the current record. p_rem->t_newer->t_older = p_rem->t_older; } } /* * Insert existing element into name ordered list before p_name. * If p_name is NULL then we add it to the end instead. */ void insert_name(DataRow *p_new, DataRow *p_name) { // Set up pointer to next record (or NULL), sorted by name p_new->n_next = p_name; if (p_name == NULL) // Add to end of list { p_new->n_prev = n_last; if (n_last == NULL) // If we have an empty list { n_first = p_new; // Add it to the head of the list } else // List wasn't empty, add to the end of the list. { n_last->n_next = p_new; } n_last = p_new; } else // Insert new record ahead of p_name record { p_new->n_prev = p_name->n_prev; if (p_name->n_prev == NULL) // add to begin of list { n_first = p_new; } else { p_name->n_prev->n_next = p_new; } p_name->n_prev = p_new; } } /* * Insert existing element into time ordered list before p_time * The p_new record ends up being on the "older" side of p_time when * all done inserting (closer in the list to the t_oldest pointer). * If p_time == NULL, insert at newest end of list. */ void insert_time(DataRow *p_new, DataRow *p_time) { // Set up pointer to next record (or NULL), sorted by time p_new->t_newer = p_time; if (p_time == NULL) // add to end of list (becomes newest station) { p_new->t_older = t_newest; // connect to previous end of list if (t_newest == NULL) // if list empty, create list { t_oldest = p_new; // it's now our only station on the list } else { t_newest->t_newer = p_new; // list not empty, link original last record to our new one } t_newest = p_new; // end of list (newest record pointer) points to our new record } else // Else we're inserting into the middle of the list somewhere { p_new->t_older = p_time->t_older; if (p_time->t_older == NULL) // add to end of list (new record becomes oldest station) { t_oldest = p_new; } else { p_time->t_older->t_newer = p_new; // else } p_time->t_older = p_new; } } /* * Free station memory for one entry */ void delete_station_memory(DataRow *p_del) { if (p_del == NULL) { return; } remove_name(p_del); remove_time(p_del); free(p_del); station_count--; } /* * Create new uninitialized element in station list * and insert it before p_name after p_time entries. * * Returns NULL if malloc error. */ /*@null@*/ DataRow *insert_new_station(DataRow *p_name, DataRow *p_time) { DataRow *p_new; p_new = (DataRow *)calloc(1, sizeof(DataRow)); if (p_new != NULL) // we really got the memory { insert_name(p_new,p_name); // insert element into name ordered list insert_time(p_new,p_time); // insert element into time ordered list } else // p_new == NULL { fprintf(stderr,"ERROR: we got no memory for station storage\n"); } return(p_new); // return pointer to new element } /* * Create new initialized element for call in station list * and insert it before p_name after p_time entries. * * Returns NULL if mallc error. */ /*@null@*/ DataRow *add_new_station(DataRow *p_name, DataRow *p_time, char *call) { DataRow *p_new; int hash_key; // We use a 14-bit hash key char *tactical_call; if (call[0] == '\0') { // Do nothing. No update needed. Callsign is empty. return(NULL); } //fprintf(stderr,"Adding new station: %s\n",call); p_new = insert_new_station(p_name,p_time); // allocate memory if (p_new == NULL) { // Couldn't allocate space for the station return(NULL); } init_station(p_new); // initialize new station record xastir_snprintf(p_new->call_sign, sizeof(p_new->call_sign), "%s", call); station_count++; // Do some quick checks to see if we just inserted a new hash // key or inserted at the beginning of a hash key (making the // old pointer incorrect). If so, update our pointers to match. // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((call[0] & 0x7f) << 7); hash_key = hash_key | (int)(call[1] & 0x7f); if (station_shortcuts[hash_key] == NULL) { // New hash key entry point found. Fill in the pointer. //fprintf(stderr,"New hash key: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } else if (p_new->n_prev == NULL) { // We just inserted at the beginning of the list. Assume // that we inserted at the beginning of our hash_key // segment. //fprintf(stderr,"Start of list hash_key: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } else { // Check whether either of the first two chars of the new // callsign and the previous callsign are different. If so, // we need to update the hash table entry for our new record // 'cuz we're at the start of a new hash table entry. if (p_new->n_prev->call_sign[0] != call[0] || p_new->n_prev->call_sign[1] != call[1]) { //fprintf(stderr,"Hash segment start: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } } //if (p_new->n_prev != NULL) { // fprintf(stderr,"\tprev: %s", // p_new->n_prev->call_sign); //} //if (p_new->n_next != NULL) { // fprintf(stderr,"\t\tnext: %s", // p_new->n_next->call_sign); //} // //fprintf(stderr,"\n"); // Check whether we have a tactical call to assign to this // station in our tactical hash table. //fprintf(stderr,"Call:'%s'\n", call); tactical_call = get_tactical_from_hash(call); // If tactical call found and not blank if (tactical_call && tactical_call[0] != '\0') { // Malloc some memory to hold it in the station record. p_new->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); CHECKMALLOC(p_new->tactical_call_sign); //fprintf(stderr,"***Assigning tactical call to new record***\n"); xastir_snprintf(p_new->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", tactical_call); //if (tactical_call[0] == '\0') // fprintf(stderr,"Blank tactical call\n"); } else { //fprintf(stderr,"."); } return(p_new); // return pointer to new element } #ifdef HAVE_DB /* function add_simple_station() * adds an xastir DataRow using station and additional data from a simpleStation * record in a SQL database. * @param p_new_station Pointer to a DataRow for the new station, probably initialized as DataRow p_new_station = NULL * @param station String pointer for the callsign or object name * @param origin String pointer for the callsign for an object * @param symbol String pointer to an aprs symbol, will take the first character * @param overlay String pointer to an aprs overlay, will take the first character * @param aprs_type String pointer to an aprs type, will take the first character * @param latitude in decimal degrees * @param longitude in decimal degrees * @param record_type * @param node_path * @param transmit_time Time at which the station position was transmitted in a string pointer with format described by timeformat * @param timeformat Format for the transmit_time, e.g. "%Y-%M-%D %h:%d:%m" see documentation for strptime * * @returns 0 if unable to add new station (p_new_station should be null) * otherwise returns 1 (and p_new_station should be a pointer to the DataRow * for the new station record. */ int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time, char *timeformat) { int returnvalue = 0; unsigned long x; // xastir coordinate for longitude unsigned long y; // xastir coordinate for latitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string DataRow *p_time; // pointer to new station record //DataRow *p_new_station_unused; struct tm time; time_t sec; char timestring[100+1]; char empty[MAX_ALTITUDE]; // for storing trailpoint data (altitude, course, speed) we don't know here. empty[0]='\0'; // Add a datarow using the retrieved station record from the postgis/mysql database. p_time = NULL; p_new_station = NULL; if (debug_level & 4096) { fprintf(stderr,"add_simple_station(%s)\n",station); } if (search_station_name(&p_new_station,station,1)) { // A datarow for this station exists, find out if the new record // is older or younger than the existing DataRow for this station strptime(transmit_time,timeformat,&time); p_new_station->sec_heard = mktime(&time); if(p_new_station->sec_heard > mktime(&time)) { // Add the new record as a trailpoint. if (strlen(transmit_time) > 0) { strptime(transmit_time, timeformat, &time); sec = mktime(&time); lat = strtof(latitude,NULL); lon = strtof(longitude,NULL); if (convert_to_xastir_coordinates (&x, &y, lon, lat)) { (void)store_trail_point(p_new_station, x, y, sec, empty, empty, empty, 0); } } // all done returnvalue = 1; } else { // Append the position of the existing record as a trailpoint // and set the station DataRow to the new values. (void)store_trail_point(p_new_station, p_new_station->coord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } } else { // add a new station p_new_station = add_new_station(p_new_station,p_time,station); } if(returnvalue==0) { // Set the values for the p_new_station DataRow based on the // supplied parameters. At this point p_new_station might // be either a brand new station record, or an existing // station record for the callsign that we were passed. if (!(p_new_station==NULL)) { // set values for new station based on the database row xastir_snprintf(p_new_station->origin,58,"%s",origin); p_new_station->aprs_symbol.aprs_symbol = symbol[0]; p_new_station->aprs_symbol.special_overlay = overlay[0]; p_new_station->aprs_symbol.aprs_type = aprs_type[0]; lat = strtof(latitude,NULL); lon = strtof(longitude,NULL); if (convert_to_xastir_coordinates (&x, &y, lon, lat)) { p_new_station->coord_lon = x; p_new_station->coord_lat = y; } p_new_station->record_type = record_type[0]; // free node path, Malloc, and store the new path if (p_new_station->node_path_ptr != NULL) { free(p_new_station->node_path_ptr); } p_new_station->node_path_ptr = (char *)malloc(strlen(node_path) + 1); CHECKMALLOC(p_new_station->node_path_ptr); substr(p_new_station->node_path_ptr,node_path,strlen(node_path)); // also set flags for the station p_new_station->flag |= ST_ACTIVE; if (position_on_extd_screen(p_new_station->coord_lat,p_new_station->coord_lon)) { p_new_station->flag |= (ST_INVIEW); // set "In View" flag } else { p_new_station->flag &= (~ST_INVIEW); // clear "In View" flag } p_new_station->data_via = DATA_VIA_DATABASE; // treat as data from a file. if (strlen(transmit_time) > 0) { //strptime(transmit_time,"%Y-%m-%d %H:%M:%S",&time); strptime(transmit_time,timeformat,&time); p_new_station->sec_heard = mktime(&time); if (debug_level & 4096) { get_iso_datetime(p_new_station->sec_heard,timestring,False,False); fprintf(stderr,"time %s to [%s] using [%s]\n",transmit_time,timestring,timeformat); } if (p_new_station->sec_heard > sec_now()) { p_new_station->sec_heard = sec_now(); } (void)strftime(timestring,MAX_TIME,"%m%d%Y%H%M%S",&time); xastir_snprintf(p_new_station->pos_time, sizeof(p_new_station->pos_time), "%s", timestring); } returnvalue = 1; } } return returnvalue; } #endif /* HAVE_DB */ /* * Move station record before p_time in time ordered list */ void move_station_time(DataRow *p_curr, DataRow *p_time) { if (p_curr != NULL) // need a valid record { remove_time(p_curr); insert_time(p_curr,p_time); } } /* * Move station record before p_name in name ordered list */ void move_station_name(DataRow *p_curr, DataRow *p_name) { if (p_curr != NULL) // need a valid record { remove_name(p_curr); insert_name(p_curr,p_name); } } // Update all of the pointers so that they accurately reflect the // current state of the station database. // // NOTE: This part of the code could be made smarter so that the // pointers are updated whenever they are found to be out of whack, // instead of zeroing all of them and starting from scratch each // time. Alternate: Follow the current pointer if non-NULL then go // up/down the list to find the current switchover point between // letters. // // Better: Tie into the station insert function. If a new letter // is inserted, or a new station at the beginning of a letter group, // run this function to keep things up to date. That way we won't // have to traverse in both directions to find a callsign in the // search_station_name() function. // // If hash_key_in is -1, we need to redo all of the hash keys. If // it is between 0 and 16383, then we need to redo just that one // hash key. The 2nd parameter is either NULL for a removed record, // or a pointer to a new station record in the case of an addition. // void station_shortcuts_update_function(int hash_key_in, DataRow *p_rem) { int ii; DataRow *ptr; int prev_hash_key = 0x0000; int hash_key; // I just changed the function so that we can pass in the hash_key // that we wish to update: We should be able to speed things up by // updating one hash key instead of all 16384 pointers. if ( (hash_key_in != -1) && (hash_key_in >= 0) && (hash_key_in < 16384) ) { // We're adding/changing a hash key entry station_shortcuts[hash_key_in] = p_rem; //fprintf(stderr,"%i ",hash_key_in); } else // We're removing a hash key entry. { // Clear and rebuild the entire hash table. //?????????????????????????????????????????????????? // Clear all of the pointers before we begin???? //?????????????????????????????????????????????????? for (ii = 0; ii < 16384; ii++) { station_shortcuts[ii] = NULL; } ptr = n_first; // Start of list // Loop through entire list, writing the pointer into the // station_shortcuts array whenever a new character is // encountered. Do this until the end of the array or the end // of the list. // while ( (ptr != NULL) && (prev_hash_key < 16384) ) { // We create the hash key out of the lower 7 bits of the // first two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((ptr->call_sign[0] & 0x7f) << 7); hash_key = hash_key | (int)(ptr->call_sign[1] & 0x7f); if (hash_key > prev_hash_key) { // We found the next hash_key. Store the pointer at the // correct location. if (hash_key < 16384) { station_shortcuts[hash_key] = ptr; //fprintf(stderr,"%i ", hash_key); } prev_hash_key = hash_key; } ptr = ptr->n_next; } //fprintf(stderr,"\n"); } } // // Search station record by callsign // Returns a station with a call equal or after the searched one // // We use a doubly-linked list for the stations, so we can traverse // in either direction. We also use a 14-bit hash table created // from the first two letters of the call to dump us into the // beginning of the correct area that may hold the callsign, which // reduces search time quite a bit. We end up doing a linear search // only through a small area of the linked list. // // DK7IN: I don't look at case, objects and internet names could // have lower case. // int search_station_name(DataRow **p_name, char *call, int exact) { int kk; int hash_key; int result; int ok = 1; (*p_name) = n_first; // start of alphabet if (call[0] == '\0') { // If call we're searching for is empty, return n_first as // the pointer. return(0); } // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((call[0] & 0x7f) << 7); hash_key = hash_key | (int)(call[1] & 0x7f); // Look for a match using hash table lookup // (*p_name) = station_shortcuts[hash_key]; if ((*p_name) == NULL) // No hash-table entry found. { int mm; //fprintf(stderr,"No hash-table entry found: call:%s\n",call); // No index found for that letter. Walk the array until // we find an entry that is filled. That'll be our // potential insertion point (insertion into the list will // occur just ahead of the hash entry). for (mm = hash_key; mm < 16384; mm++) { if (station_shortcuts[mm] != NULL) { (*p_name) = station_shortcuts[mm]; break; } } } // else { //fprintf(stderr,"Hash key %d=%s, searching for call: %s\n", // hash_key, // (*p_name)->call_sign, // call); // } // If we got to this point, we either have a NULL pointer or a // real hash-table pointer entry. A non-NULL pointer means that // we have a match for the lower seven bits of the first two // characters of the callsign. Check the rest of the callsign, // and jump out of the loop if we get outside the linear search // area (if first two chars are different). kk = (int)strlen(call); // Search linearly through list. Stop at end of list or break. while ( (*p_name) != NULL) { if (exact) { // Check entire string for exact match result = strcmp( call, (*p_name)->call_sign ); } else { // Check first part of string for match result = strncmp( call, (*p_name)->call_sign, kk ); } if (result < 0) // We went past the right location. { // We're done. ok = 0; //fprintf(stderr,"Went past possible entry point, searching for call: %s\n",call); break; } else if (result == 0) // Found a possible match { //fprintf(stderr,"Found possible match: list:%s call:%s\n", // (*p_name)->call_sign, // call); break; } else // Result > 0. We haven't found it yet. { (*p_name) = (*p_name)->n_next; // Next element in list } } // Did we find anything? if ( (*p_name) == NULL) { ok = 0; //fprintf(stderr,"End of list reached, call: %s\n",call); return(ok); // Nope. No match found. } // If "exact" is set, check that the string lengths match as // well. If not, we didn't find it. if (exact && ok && strlen((*p_name)->call_sign) != strlen(call)) { ok = 0; } return(ok); // if not ok: p_name points to correct insert position in name list } /* * Search station record by time and time serial number, serial ignored if -1 * Returns a station that is equal or older than the search criterium */ int search_station_time(DataRow **p_time, time_t heard, int serial) { int ok = 1; (*p_time) = t_newest; // newest station if (heard == 0) // we want the newest station { if (t_newest == NULL) { ok = 0; // empty list } } else { while((*p_time) != NULL) // check time { if ((*p_time)->sec_heard <= heard) // compare { break; // found time or earlier } (*p_time) = (*p_time)->t_older; // next element } // we now probably have found the entry if ((*p_time) != NULL && (*p_time)->sec_heard == heard) { // we got a match, but there may be more of them if (serial >= 0) // check serial number, ignored if -1 { while((*p_time) != NULL) // for unique time index { if ((*p_time)->sec_heard == heard && (*p_time)->time_sn <= serial) // compare { break; // found it (same time, maybe earlier SN) } if ((*p_time)->sec_heard < heard) // compare { break; // found it (earlier time) } (*p_time) = (*p_time)->t_older; // consider next element } if ((*p_time) == NULL || (*p_time)->sec_heard != heard || (*p_time)->time_sn != serial) { ok = 0; // no perfect match } } } else { ok = 0; // no perfect match } } return(ok); } /* * Get pointer to next station in name sorted list */ int next_station_name(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = n_first; } else { (*p_curr) = (*p_curr)->n_next; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to previous station in name sorted list */ int prev_station_name(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = n_last; } else { (*p_curr) = (*p_curr)->n_prev; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to newer station in time sorted list */ int next_station_time(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = t_oldest; // Grab oldest station if NULL passed to us??? } else { (*p_curr) = (*p_curr)->t_newer; // Else grab newer station } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to older station in time sorted list */ int prev_station_time(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = t_newest; // Grab newest station if NULL passed to us??? } else { (*p_curr) = (*p_curr)->t_older; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Set flag for all stations in current view area or a margin area around it * That are the stations we look at if we want to draw symbols or trails */ void setup_in_view(void) { DataRow *p_station; long min_lat, max_lat; // screen borders plus space long min_lon, max_lon; // for trails from off-screen stations long marg_lat, marg_lon; // margin around screen marg_lat = (long)(3 * screen_height * scale_y/2); marg_lon = (long)(3 * screen_width * scale_x/2); if (marg_lat < IN_VIEW_MIN*60*100) // allow a minimum area, { marg_lat = IN_VIEW_MIN*60*100; // there could be outside stations } if (marg_lon < IN_VIEW_MIN*60*100) // with trail parts on screen { marg_lon = IN_VIEW_MIN*60*100; } // Only screen view // min_lat = SE_corner_latitude // max_lat = NW_corner_latitude; // min_lon = NW_corner_longitude; // max_lon = SE_corner_longitude; // Screen view plus one screen wide margin // There could be stations off screen with on screen trails // See also the use of position_on_extd_screen() min_lat = center_latitude - marg_lat; max_lat = center_latitude + marg_lat; min_lon = center_longitude - marg_lon; max_lon = center_longitude + marg_lon; p_station = n_first; while (p_station != NULL) { if ((p_station->flag & ST_ACTIVE) == 0 // ignore deleted objects || p_station->coord_lon < min_lon || p_station->coord_lon > max_lon || p_station->coord_lat < min_lat || p_station->coord_lat > max_lat || (p_station->coord_lat == 0 && p_station->coord_lon == 0)) { // outside view and undefined stations: p_station->flag &= (~ST_INVIEW); // clear "In View" flag } else { p_station->flag |= ST_INVIEW; // set "In View" flag } p_station = p_station->n_next; } } /* * Check if position is inside screen borders */ int position_on_screen(long lat, long lon) { if ( lon > NW_corner_longitude && lon < SE_corner_longitude && lat > NW_corner_latitude && lat < SE_corner_latitude && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the screen } else { return(0); } } /* * Check if position is inside extended screen borders * (real screen + one screen margin for trails) * used for station "In View" flag */ int position_on_extd_screen(long lat, long lon) { long marg_lat, marg_lon; // margin around screen marg_lat = (long)(3 * screen_height * scale_y/2); marg_lon = (long)(3 * screen_width * scale_x/2); if (marg_lat < IN_VIEW_MIN*60*100) // allow a minimum area, { marg_lat = IN_VIEW_MIN*60*100; // there could be outside stations } if (marg_lon < IN_VIEW_MIN*60*100) // with trail parts on screen { marg_lon = IN_VIEW_MIN*60*100; } if ( labs(lon - center_longitude) < marg_lon && labs(lat - center_latitude) < marg_lat && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the area } else { return(0); } } /* * Check if position is inside inner screen area * (real screen + minus 1/6 screen margin) * used for station tracking */ int position_on_inner_screen(long lat, long lon) { if ( lon > center_longitude-(long)(screen_width *scale_x/3) && lon < center_longitude+(long)(screen_width *scale_x/3) && lat > center_latitude -(long)(screen_height*scale_y/3) && lat < center_latitude +(long)(screen_height*scale_y/3) && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the area } else { return(0); } } /* * Delete single station with all its data ?? delete messages ?? * This function is called with a callsign parameter. Only used for * my callsign, not for any other. */ void station_del(char *call) { DataRow *p_name; // DK7IN: do it with move... ? if (search_station_name(&p_name, call, 1)) { (void)delete_trail(p_name); // Free track storage if it exists. (void)delete_weather(p_name); // Free weather memory, if allocated (void)delete_multipoints(p_name); // Free multipoint memory, if allocated (void)delete_comments_and_status(p_name); // Free comment storage if it exists if (p_name->node_path_ptr != NULL)// Free malloc'ed path { free(p_name->node_path_ptr); } if (p_name->tactical_call_sign != NULL) { free(p_name->tactical_call_sign); } delete_station_memory(p_name); // Free memory } } /* * Delete single station with all its data ?? delete messages ?? * This function is called with a pointer instead of a callsign. */ void station_del_ptr(DataRow *p_name) { //fprintf(stderr,"db.c:station_del_ptr(): %s\n",p_name->call_sign); if (p_name != NULL) { // A bit of debug code: Attempting to find out if we're // deleting our own objects from time to time. Leave this // in until we're sure the problem has been fixed. //// if (is_my_call(p_name->origin,1)) { // Check SSID as well // if ( is_my_object_item(p_name) ) { // Check SSID as well // fprintf(stderr,"station_del_ptr: Removing my own object: %s\n", // p_name->call_sign); // } #ifdef EXPIRE_DEBUG fprintf(stderr,"Removing: %s heard %d seconds ago\n",p_name->call_sign, (int)(sec_now() - p_name->sec_heard)); #endif (void)delete_trail(p_name); // Free track storage if it exists. (void)delete_weather(p_name); // free weather memory, if allocated (void)delete_multipoints(p_name); // Free multipoint memory, if allocated (void)delete_comments_and_status(p_name); // Free comment storage if it exists if (p_name->node_path_ptr != NULL) // Free malloc'ed path { free(p_name->node_path_ptr); } if (p_name->tactical_call_sign != NULL) { free(p_name->tactical_call_sign); } delete_station_memory(p_name); // free memory, update // linked lists, update // station_count //fprintf(stderr,"db.c:station_del_ptr(): Deleted station\n"); } } /* * Delete all stations ?? delete messages ?? */ void delete_all_stations(void) { DataRow *p_name; DataRow *p_curr; int ii; // Clear all of the pointers before we begin for (ii = 0; ii < 16384; ii++) { station_shortcuts[ii] = NULL; } p_name = n_first; while (p_name != NULL) { p_curr = p_name; p_name = p_name->n_next; station_del_ptr(p_curr); //(void)delete_trail(p_curr); // free trail memory, if allocated //(void)delete_weather(p_curr); // free weather memory, if allocated //(void)delete_multipoints(p_curr);// Free multipoint memory, if allocated //delete_station_memory(p_curr); // free station memory } if (station_count != 0) { fprintf(stderr, "ERROR: station_count should be 0 after stations delete, is %d\n", station_count); station_count = 0; } } /* * Check if we have to delete old stations. * * Called from main.c:UpdateTime() on a periodic basis. * */ void check_station_remove(time_t curr_sec) { DataRow *p_station, *p_station_t_newer; time_t t_rem; int done; // Run through this routine every STATION_REMOVE_CYCLE // seconds (currently every five minutes) #ifdef EXPIRE_DEBUG // Check every 15 seconds, useful for debug only. if (last_station_remove < (curr_sec - DEBUG_STATION_REMOVE_CYCLE)) // DEBUG #else if (last_station_remove < (curr_sec - STATION_REMOVE_CYCLE)) #endif { //fprintf(stderr,"db.c:check_station_remove() is running\n"); // Compute the cutoff time. Any stations older than t_rem // will be removed, unless they have a tactical call or // belong to us. t_rem = curr_sec - sec_remove; #ifdef EXPIRE_DEBUG // Expire every 15 seconds, useful for debug only. t_rem = curr_sec - (1 * DEBUG_STATION_REMOVE); #endif for (done = 0, p_station = t_oldest; p_station != NULL && !done; p_station = p_station_t_newer) { // Save a pointer to the next record in time-order // before we delete a record and lose it. p_station_t_newer = p_station->t_newer; if (p_station->sec_heard < t_rem) { // if ( (is_my_call(p_station->call_sign,1)) // It's my station (including SSID) or // || ( (is_my_call(p_station->origin,1)) // Station is owned by me (including SSID) // && ( ((p_station->flag & ST_OBJECT) != 0) // and it's an object // || ((p_station->flag & ST_ITEM ) != 0) ) ) ) { // or an item if ( is_my_station(p_station) || is_my_object_item(p_station)) { // It's one of mine, leave it alone! #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"mine\n"); #endif } /* else if (p_station->tactical_call_sign) { // Station has a tactical callsign assigned, // don't delete it. #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"tactical\n"); #endif } */ else // Not one of mine, doesn't have a tactical { // callsign assigned, so start deleting //The debug output needs to be before the delete, as // we're freeing the data pointed to by p_station! #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"deleting\n"); fprintf(stderr,"Last heard time: %ld\n",p_station->sec_heard); fprintf(stderr," t_rem: %ld\n",t_rem); fprintf(stderr," next older record has time %ld\n",p_station_t_newer->sec_heard); #endif mdelete_messages(p_station->call_sign); // Delete messages station_del_ptr(p_station); //(void)delete_trail(p_station); // Free track storage if it exists. //(void)delete_weather(p_station); // Free weather memory, if allocated //(void)delete_multipoints(p_station); // Free multipoint memory, if allocated //delete_station_memory(p_station); // Free memory } } else { #ifdef EXPIRE_DEBUG DataRow *testPtr = sanity_check_time_list(t_rem); if (testPtr) { fprintf(stderr,"TIME-SORTED LIST SANITY CHECK FAILED!\n"); fprintf(stderr," At least one station left after expire with time older than %ld\n",t_rem); fprintf(stderr," Station name: %s\n", testPtr->call_sign); fprintf(stderr," Last heard time %ld\n",testPtr->sec_heard); fprintf(stderr," Seconds ago: %ld\n",curr_sec-testPtr->sec_heard); fprintf(stderr," Seconds older than expire time: %ld\n",t_rem-testPtr->sec_heard); fprintf(stderr,"--------\n"); dump_time_sorted_list(); } #endif done++; // all other stations are newer... } } last_station_remove = curr_sec; } } /* * Delete an object (mark it as deleted) */ void delete_object(char *name) { DataRow *p_station; //fprintf(stderr,"delete_object\n"); p_station = NULL; if (search_station_name(&p_station,name,1)) // find object name { p_station->flag &= (~ST_ACTIVE); // clear flag p_station->flag &= (~ST_INVIEW); // clear "In View" flag if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { redraw_on_new_data = 2; // redraw now } // there is some problem... it is not redrawn immediately! ???? // but deleted from list immediatetly redo_list = (int)TRUE; // and update lists } } /////////////////////////////////////// APRS Decoding //////////////////////////////////////////// /* * Try to find a !DAO! format datum and extra precision string from the * comment field of an APRS location packet (incl. objects and items). * If !DAO! is found, it is removed from the comment. * See http://web.ew.usna.edu/~bruninga/aprs/datum.txt * * lat and lon will contain the thousandth and ten thousandth * minute digits of the location, if valid (see below). * For example, if the final location is 70 deg 12.3456 minutes, * lat or lon will contain 56. If the final location is * 50 deg 56.2104 minutes, lat or lon will contain 4. So remember * to zero pad! The range for lat/lon, when valid, is 0-99. * datumch will contain the datum character, if found. * * daocomment must be null-terminated and must contain the comment field * * returns 3 if dao was found and contained a base-91 position * (= datumch, lat, and lon contents are all valid) * returns 2 if dao was found and contained a human readable position * (= datumch, lat, and lon contents are all valid) * returns 1 if dao was found but only included datum information * (= only datumch is valid) * returns 0 if no valid dao was found * (= datumch, lat, and lon contents are all invalid, daocomment is unmodified) * * Tapio Sokura OH2KKU 2007-11-15 */ int decode_dao (int *lat, int *lon, char *datumch, char *daocomment) { char *searchval, *rval; size_t slen; // Loop around searching for !DAO!, return the first valid match. // The first '!' is found using strchr, the rest of the // string is validated more manually. searchval = daocomment; rval = strchr(searchval, '!'); while (rval != NULL) { // Check the remaining string length so we don't // run past string end slen = strlen(rval); if (slen < 5) { break; } if (rval[4] == '!' && rval[1] >= '!' && rval[1] <= '{') { // found the !DAO! terminator and datum char is // within the allowable range if (rval[1] >= 'A' && rval[1] <= 'Z') { // looks like human readable format if (rval[2] == ' ' && rval[3] == ' ') { // only datum information present *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 1; } else if (rval[2] >= '0' && rval[2] <= '9' && rval[3] >= '0' && rval[3] <= '9') { // human readable format 0-9 lat/lon ok // ASCII - 48 = the integer digit we want. // Multiply by 10, because we only get // thousandths of a minute with human // readable format. *lat = ((int)rval[2] - 48) * 10; *lon = ((int)rval[3] - 48) * 10; *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 2; } // not ok for human readable format, continue searching } else if (rval[1] >= 'a' && rval[1] <= 'z') { // looks like base-91 format if (rval[2] == ' ' && rval[3] == ' ') { // only datum information present *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 1; } else if (rval[2] >= '!' && rval[2] <= '{' && rval[3] >= '!' && rval[3] <= '{') { // base-91 lat/lon ok unsigned int lats, lons; float latval, lonval; lats = rval[2] - 33; // get base91 values lons = rval[3] - 33; latval = lats / 91.0 * 100; // do proper scaling lonval = lons / 91.0 * 100; *lat = (int)(latval + 0.5); // round and store *lon = (int)(lonval + 0.5); *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 3; } // not ok for base91 format, continue searching } // Datum chars outside A-Z and a-z are not // handled (here at least). } // If we end up here, we didn't find a match. // Search for the next '!' char. searchval = rval + 1; rval = strchr(searchval, '!'); } // No more string left to search and no match. return 0; } /* * Extract Uncompressed Position Report from begin of line * * If a position is found, it is deleted from the data. */ int extract_position(DataRow *p_station, char **info, int type) { int ok, dao_lat, dao_lon, dao_rval; char temp_lat[10+1]; char temp_lon[11+1]; char temp_grid[8+1]; char *my_data; char dao_datumch; float gridlat; float gridlon; my_data = (*info); if (type != APRS_GRID) // Not a grid { ok = (int)(strlen(my_data) >= 19); ok = (int)(ok && my_data[4]=='.' && my_data[14]=='.' && (toupper(my_data[7]) =='N' || toupper(my_data[7]) =='S') && (toupper(my_data[17])=='E' || toupper(my_data[17])=='W')); // errors found: [4]: X [7]: n s [17]: w e if (ok) { ok = is_num_chr(my_data[0]); // 5230.31N/01316.88E> ok = (int)(ok && is_num_chr(my_data[1])); // 0123456789012345678 ok = (int)(ok && is_num_or_sp(my_data[2])); ok = (int)(ok && is_num_or_sp(my_data[3])); ok = (int)(ok && is_num_or_sp(my_data[5])); ok = (int)(ok && is_num_or_sp(my_data[6])); ok = (int)(ok && is_num_chr(my_data[9])); ok = (int)(ok && is_num_chr(my_data[10])); ok = (int)(ok && is_num_chr(my_data[11])); ok = (int)(ok && is_num_or_sp(my_data[12])); ok = (int)(ok && is_num_or_sp(my_data[13])); ok = (int)(ok && is_num_or_sp(my_data[15])); ok = (int)(ok && is_num_or_sp(my_data[16])); } if (ok) { overlay_symbol(my_data[18], my_data[8], p_station); p_station->pos_amb = 0; // spaces in latitude set position ambiguity, spaces in longitude do not matter // we will adjust the lat/long to the center of the rectangle of ambiguity if (my_data[2] == ' ') // nearest degree { p_station->pos_amb = 4; my_data[2] = my_data[12] = '3'; my_data[3] = my_data[5] = my_data[6] = '0'; my_data[13] = my_data[15] = my_data[16] = '0'; } else if (my_data[3] == ' ') // nearest 10 minutes { p_station->pos_amb = 3; my_data[3] = my_data[13] = '5'; my_data[5] = my_data[6] = '0'; my_data[15] = my_data[16] = '0'; } else if (my_data[5] == ' ') // nearest minute { p_station->pos_amb = 2; my_data[5] = my_data[15] = '5'; my_data[6] = '0'; my_data[16] = '0'; } else if (my_data[6] == ' ') // nearest 1/10th minute { p_station->pos_amb = 1; my_data[6] = my_data[16] = '5'; } xastir_snprintf(temp_lat, sizeof(temp_lat), "%s", my_data); temp_lat[9] = toupper(my_data[7]); temp_lat[10] = '\0'; xastir_snprintf(temp_lon, sizeof(temp_lon), "%s", my_data+9); temp_lon[10] = toupper(my_data[17]); temp_lon[11] = '\0'; // Check for !DAO!, beginning from the comment field. // Datum is not used for the time being. // Note: error/precision information (the white box on the map) is // not updated here, because changes to p_station->lat/lon_precision // are overridden in the calling function. dao_rval = decode_dao(&dao_lat, &dao_lon, &dao_datumch, my_data + 19); if (dao_rval == 2 || dao_rval == 3) { // 48 is the magic number to add to a single digit integer to // get the same digit in ASCII. temp_lat[7] = (char)(dao_lat / 10 + 48); temp_lat[8] = (char)(dao_lat % 10 + 48); temp_lon[8] = (char)(dao_lon / 10 + 48); temp_lon[9] = (char)(dao_lon % 10 + 48); // Signal that this is an accuracy-enhanced !DAO! position, // so the calling function can set the error boxes accordingly // (once somebody implements it). ok = dao_rval; } else { // no valid !DAO! _location_ found, pad with zeroes instead temp_lat[7] = '0'; temp_lat[8] = '0'; temp_lon[8] = '0'; temp_lon[9] = '0'; } // Callsign check here also checks SSID for an exact // match // if (!is_my_call(p_station->call_sign,1)) { // don't change my position, I know it better... if ( !(is_my_station(p_station)) ) // don't change my position, I know it better... { p_station->coord_lat = convert_lat_s2l(temp_lat); // ...in case of position ambiguity p_station->coord_lon = convert_lon_s2l(temp_lon); } (*info) += 19; // delete position from comment } } else // It is a grid { // first sanity checks, need more ok = (int)(is_num_chr(my_data[2])); ok = (int)(ok && is_num_chr(my_data[3])); ok = (int)(ok && ((my_data[0]>='A')&&(my_data[0]<='R'))); ok = (int)(ok && ((my_data[1]>='A')&&(my_data[1]<='R'))); if (ok) { xastir_snprintf(temp_grid, sizeof(temp_grid), "%s", my_data); // this test treats >6 digit grids as 4 digit grids; >6 are uncommon. // the spec mentioned 4 or 6, I'm not sure >6 is even allowed. if ( (temp_grid[6] != ']') || (temp_grid[4] == 0) || (temp_grid[5] == 0)) { p_station->pos_amb = 6; // 1deg lat x 2deg lon temp_grid[4] = 'L'; temp_grid[5] = 'L'; } else { p_station->pos_amb = 5; // 2.5min lat x 5min lon temp_grid[4] = toupper(temp_grid[4]); temp_grid[5] = toupper(temp_grid[5]); } // These equations came from what I read in the qgrid source code and // various mailing list archives. gridlon= (20.*((float)temp_grid[0]-65.) + 2.*((float)temp_grid[2]-48.) + 5.*((float)temp_grid[4]-65.)/60.) - 180.; gridlat= (10.*((float)temp_grid[1]-65.) + ((float)temp_grid[3]-48.) + 5.*(temp_grid[5]-65.)/120.) - 90.; // could check for my callsign here, and avoid changing it... p_station->coord_lat = (unsigned long)(32400000l + (360000.0 * (-gridlat))); p_station->coord_lon = (unsigned long)(64800000l + (360000.0 * gridlon)); p_station->aprs_symbol.aprs_type = '/'; p_station->aprs_symbol.aprs_symbol = 'G'; } // is it valid grid or not - "ok" // could cut off the grid square from the comment here, but why bother? } // is it grid or not return(ok); } // DK7IN 99 /* * Extract Compressed Position Report Data Formats from begin of line * [APRS Reference, chapter 9] * * If a position is found, it is deleted from the data. If a * compressed position is found, delete the three csT bytes as well, * even if all spaces. * Returns 0 if the packet is NOT a properly compressed position * packet, returns 1 if ok. */ int extract_comp_position(DataRow *p_station, char **info, int UNUSED(type) ) { int ok; int x1, x2, x3, x4, y1, y2, y3, y4; int c = 0; int s = 0; int T = 0; int len; char *my_data; float lon = 0; float lat = 0; // We were extracting the range from the posit, but never using it. // GCC 6.x whines // float range; int skip = 0; char L; if (debug_level & 1) { fprintf(stderr,"extract_comp_position: Start\n"); } //fprintf(stderr,"extract_comp_position start: %s\n",*info); // compressed data format /YYYYXXXX$csT is a fixed 13-character field // used for ! / @ = data IDs // / Symbol Table ID or overlay: '/' '\' A-Z a-j // YYYY compressed latitude // XXXX compressed longitude // $ Symbol Code // cs compressed // course/speed // radio range // altitude // T compression type ID my_data = (*info); // Check leading char. Must be one of these: // '/' // '\' // A-Z // a-j // L = my_data[0]; if ( L == '/' || L == '\\' || ( L >= 'A' && L <= 'Z' ) || ( L >= 'a' && L <= 'j' ) ) { // We're good so far } else { // Note one of the symbol table or overlay characters, so // there's something funky about this packet. It's not a // properly formatted compressed position. return(0); } //fprintf(stderr,"my_data: %s\n",my_data); // If c = space, csT bytes are ignored. Minimum length: 8 // bytes for lat/lon, 2 for symbol, 3 for csT for a total of 13. len = strlen(my_data); ok = (int)(len >= 13); if (ok) { y1 = (int)my_data[1] - '!'; y2 = (int)my_data[2] - '!'; y3 = (int)my_data[3] - '!'; y4 = (int)my_data[4] - '!'; x1 = (int)my_data[5] - '!'; x2 = (int)my_data[6] - '!'; x3 = (int)my_data[7] - '!'; x4 = (int)my_data[8] - '!'; // csT bytes if (my_data[10] == ' ') // Space { c = -1; // This causes us to ignore csT } else { c = (int)my_data[10] - '!'; s = (int)my_data[11] - '!'; T = (int)my_data[12] - '!'; } skip = 13; // Convert ' ' to '0'. Not specified in APRS Reference! Do // we need it? if (x1 == -1) { x1 = '\0'; } if (x2 == -1) { x2 = '\0'; } if (x3 == -1) { x3 = '\0'; } if (x4 == -1) { x4 = '\0'; } if (y1 == -1) { y1 = '\0'; } if (y2 == -1) { y2 = '\0'; } if (y3 == -1) { y3 = '\0'; } if (y4 == -1) { y4 = '\0'; } ok = (int)(ok && (x1 >= '\0' && x1 < 91)); // /YYYYXXXX$csT ok = (int)(ok && (x2 >= '\0' && x2 < 91)); // 0123456789012 ok = (int)(ok && (x3 >= '\0' && x3 < 91)); ok = (int)(ok && (x4 >= '\0' && x4 < 91)); ok = (int)(ok && (y1 >= '\0' && y1 < 91)); ok = (int)(ok && (y2 >= '\0' && y2 < 91)); ok = (int)(ok && (y3 >= '\0' && y3 < 91)); ok = (int)(ok && (y4 >= '\0' && y4 < 91)); T &= 0x3F; // DK7IN: force Compression Byte to valid format // mask off upper two unused bits, they should be zero!? ok = (int)(ok && (c == -1 || ((c >=0 && c < 91) && (s >= 0 && s < 91) && (T >= 0 && T < 64)))); if (ok) { lat = (((y1 * 91 + y2) * 91 + y3) * 91 + y4 ) / 380926.0; // in deg, 0: 90°N lon = (((x1 * 91 + x2) * 91 + x3) * 91 + x4 ) / 190463.0; // in deg, 0: 180°W lat *= 60 * 60 * 100; // in 1/100 sec lon *= 60 * 60 * 100; // in 1/100 sec // The below check should _not_ be done. Compressed // format can resolve down to about 1 foot worldwide // (0.3 meters). //if ((((long)(lat+4) % 60) > 8) || (((long)(lon+4) % 60) > 8)) // ok = 0; // check max resolution 0.01 min to // catch even more errors } } if (ok) { overlay_symbol(my_data[9], my_data[0], p_station); // Symbol / Table // Callsign check here includes checking SSID for an exact // match // if (!is_my_call(p_station->call_sign,1)) { // don't change my position, I know it better... if ( !(is_my_station(p_station)) ) // don't change my position, I know it better... { // Record the uncompressed lat/long that we just // computed. p_station->coord_lat = (long)((lat)); // in 1/100 sec p_station->coord_lon = (long)((lon)); // in 1/100 sec } if (c >= 0) // ignore csT if c = ' ' { if (c < 90) // Found course/speed or altitude bytes { if ((T & 0x18) == 0x10) // check for GGA (with altitude) { xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%06.0f",pow(1.002,(double)(c*91+s))*0.3048); } else // Found compressed course/speed bytes { // Convert 0 degrees to 360 degrees so that // Xastir will see it as a valid course and do // dead-reckoning properly on this station if (c == 0) { c = 90; } // Compute course in degrees xastir_snprintf(p_station->course, sizeof(p_station->course), "%03d", c*4); // Compute speed in knots xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%03.0f", pow( 1.08,(double)s ) - 1.0); //fprintf(stderr,"Decoded speed:%s, course:%s\n",p_station->speed,p_station->course); } } else // Found pre-calculated radio range bytes { if (c == 90) { // pre-calculated radio range // Commented out to silence GCC 6.x warning about // "set but unused" variables. // range = 2 * pow(1.08,(double)s); // miles // DK7IN: dirty hack... but better than nothing if (s <= 5) // 2.9387 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "000"); } else if (s <= 17) // 7.40 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "111"); } else if (s <= 36) // 31.936 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "222"); } else if (s <= 75) // 642.41 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "333"); } else // max 90: 2037.8 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "444"); } } } } (*info) += skip; // delete position from comment } if (debug_level & 1) { if (ok) { fprintf(stderr,"*** extract_comp_position: Succeeded: %ld\t%ld\n", p_station->coord_lat, p_station->coord_lon); } else { fprintf(stderr,"*** extract_comp_position: Failed!\n"); } } //fprintf(stderr," extract_comp_position end: %s\n",*info); return(ok); } // // Extract speed and/or course from beginning of info field // // Returns course in degrees, speed in KNOTS. // int extract_speed_course(char *info, char *speed, char *course) { int i,found,len; len = (int)strlen(info); found = 0; speed[0] = course[0] = '\0'; if (len >= 7) { found = 1; for(i=0; found && i<7; i++) // check data format { if (i==3) // check separator { if (info[i]!='/') { found = 0; } } else { if( !( isdigit((int)info[i]) || (info[i] == ' ') // Spaces and periods are allowed. Need these || (info[i] == '.') ) ) // here so that we can get the field deleted { found = 0; } } } } if (found) { substr(course,info,3); substr(speed,info+4,3); for (i=0; i<=len-7; i++) // delete speed/course from info field { info[i] = info[i+7]; } } if (!found || atoi(course) < 1) // course 0 means undefined { // speed[0] ='\0'; // Don't do this! We can have a valid // speed without a valid course. course[0]='\0'; } else // recheck data format looking for undefined fields { for(i=0; i<2; i++) { if( !(isdigit((int)speed[i]) ) ) { speed[0] = '\0'; } if( !(isdigit((int)course[i]) ) ) { course[0] = '\0'; } } } return(found); } /* * Extract bearing and number/range/quality from beginning of info field */ int extract_bearing_NRQ(char *info, char *bearing, char *nrq) { int i,found,len; len = (int)strlen(info); found = 0; if (len >= 8) { found = 1; for(i=1; found && i<8; i++) // check data format if(!(isdigit((int)info[i]) || (i==4 && info[i]=='/'))) { found=0; } } if (found) { substr(bearing,info+1,3); substr(nrq,info+5,3); //fprintf(stderr,"Bearing: %s\tNRQ: %s\n", bearing, nrq); for (i=0; i<=len-8; i++) // delete bearing/nrq from info field { info[i] = info[i+8]; } } // if (!found || nrq[2] == '0') { // Q of 0 means useless bearing if (!found) { bearing[0] ='\0'; nrq[0]='\0'; } return(found); } /* * Extract altitude from APRS info field "/A=012345" in feet */ int extract_altitude(char *info, char *altitude) { int i,ofs,found,len; found=0; len = (int)strlen(info); for(ofs=0; !found && ofs= 9 && strncmp(info2,"PHG",3)==0 && info2[7]=='/' && info2[8]!='A' // trailing '/' not defined in Reference... && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-8; i++) // delete powergain from data extension field { info2[i] = info2[i+8]; } } else { if (len >= 7 && strncmp(info2,"PHG",3)==0 && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-7; i++) // delete powergain from data extension field { info2[i] = info2[i+7]; } } else if (len >= 7 && strncmp(info2,"RNG",3)==0 && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-7; i++) // delete powergain from data extension field { info2[i] = info2[i+7]; } } else { phgd[0] = '\0'; } } return(found); } /* * Extract omnidf from APRS info field "DFS1234/" from APRS data extension */ int extract_omnidf(char *info, char *phgd) { int i,len; len = (int)strlen(info); if (len >= 8 && strncmp(info,"DFS",3)==0 && info[7]=='/' // trailing '/' not defined in Reference... && isdigit((int)info[3]) && isdigit((int)info[5]) && isdigit((int)info[6])) { substr(phgd,info,7); for (i=0; i<=len-8; i++) // delete omnidf from data extension field { info[i] = info[i+8]; } return(1); } else { phgd[0] = '\0'; return(0); } } /* * Extract signpost data from APRS info field: "{123}", an APRS data extension * Format can be {1}, {12}, or {123}. Letters or digits are ok. */ int extract_signpost(char *info, char *signpost) { int i,found,len,done; //0123456 //{1} //{12} //{121} found=0; len = (int)strlen(info); if ( (len > 2) && (info[0] == '{') && ( (info[2] == '}' ) || (info[3] == '}' ) || (info[4] == '}' ) ) ) { i = 1; done = 0; while (!done) // Snag up to three digits { if (info[i] == '}') // We're done { found = i; // found = position of '}' character done++; } else { signpost[i-1] = info[i]; } i++; if ( (i > 4) && !done) // Something is wrong, we should be done by now { done++; signpost[0] = '\0'; return(0); } } substr(signpost,info+1,found-1); found++; for (i=0; i<=len-found; i++) // delete omnidf from data extension field { info[i] = info[i+found]; } return(1); } else { signpost[0] = '\0'; return(0); } } /* * Extract probability_min data from APRS info field: "Pmin1.23," * Please note the ending comma. We use it to delimit the field. */ int extract_probability_min(char *info, char *prob_min, int prob_min_size) { int len,done; char *c; char *d; //fprintf(stderr,"%s\n",info); len = (int)strlen(info); if (len < 6) // Too short { //fprintf(stderr,"Pmin too short: %s\n",info); prob_min[0] = '\0'; return(0); } c = strstr(info,"Pmin"); if (c == NULL) // Pmin not found { //fprintf(stderr,"Pmin not found: %s\n",info); prob_min[0] = '\0'; return(0); } c = c+4; // Skip the Pmin part // Find the ending comma d = c; done = 0; while (!done) { if (*d == ',') // We're done { done++; } else { d++; } // Check for string too long if ( ((d-c) > 10) && !done) // Something is wrong, we should be done by now { //fprintf(stderr,"Pmin too long: %d,%s\n",d-c,info); prob_min[0] = '\0'; return(0); } } // Copy the substring across xastir_snprintf(prob_min, prob_min_size, "%s", c); prob_min[d-c] = '\0'; prob_min[10] = '\0'; // Just to make sure // Delete data from data extension field d++; // Skip the comma done = 0; while (!done) { *(c-4) = *d; if (*d == '\0') { done++; } c++; d++; } return(1); } /* * Extract probability_max data from APRS info field: "Pmax1.23," * Please note the ending comma. We use it to delimit the field. */ int extract_probability_max(char *info, char *prob_max, int prob_max_size) { int len,done; char *c; char *d; //fprintf(stderr,"%s\n",info); len = (int)strlen(info); if (len < 6) // Too short { //fprintf(stderr,"Pmax too short: %s\n",info); prob_max[0] = '\0'; return(0); } c = strstr(info,"Pmax"); if (c == NULL) // Pmax not found { //fprintf(stderr,"Pmax not found: %s\n",info); prob_max[0] = '\0'; return(0); } c = c+4; // Skip the Pmax part // Find the ending comma d = c; done = 0; while (!done) { if (*d == ',') // We're done { done++; } else { d++; } // Check for string too long if ( ((d-c) > 10) && !done) // Something is wrong, we should be done by now { //fprintf(stderr,"Pmax too long: %d,%s\n",d-c,info); prob_max[0] = '\0'; return(0); } } // Copy the substring across xastir_snprintf(prob_max, prob_max_size, "%s", c); prob_max[d-c] = '\0'; prob_max[10] = '\0'; // Just to make sure // Delete data from data extension field d++; // Skip the comma done = 0; while (!done) { *(c-4) = *d; if (*d == '\0') { done++; } c++; d++; } return(1); } static void clear_area(DataRow *p_station) { p_station->aprs_symbol.area_object.type = AREA_NONE; p_station->aprs_symbol.area_object.color = AREA_GRAY_LO; p_station->aprs_symbol.area_object.sqrt_lat_off = 0; p_station->aprs_symbol.area_object.sqrt_lon_off = 0; p_station->aprs_symbol.area_object.corridor_width = 0; } /* * Extract Area Object */ void extract_area(DataRow *p_station, char *data) { int i, val, len; unsigned int uval; AreaObject temp_area; /* NOTE: If we are here, the symbol was the area symbol. But if this is a slightly corrupted packet, we shouldn't blow away the area info for this station, since it could be from a previously received good packet. So we will work on temp_area and only copy to p_station at the end, returning on any error as we parse. N7TAP */ //fprintf(stderr,"Area Data: %s\n", data); len = (int)strlen(data); val = data[0] - '0'; if (val >= 0 && val <= AREA_MAX) { temp_area.type = val; val = data[4] - '0'; temp_area.color = AREA_BLACK_HI; // Initial value if (data[3] == '/') { if (val >=0 && val <= 9) { temp_area.color = val; } else { if (debug_level & 2) { fprintf(stderr,"Bad area color (/)"); } return; } } else if (data[3] == '1') { if (val >=0 && val <= 5) { temp_area.color = 10 + val; } else { if (debug_level & 2) { fprintf(stderr,"Bad area color (1)"); } return; } } val = 0; if (isdigit((int)data[1]) && isdigit((int)data[2])) { val = (10 * (data[1] - '0')) + (data[2] - '0'); } else { if (debug_level & 2) { fprintf(stderr,"Bad area sqrt_lat_off"); } return; } temp_area.sqrt_lat_off = val; val = 0; if (isdigit((int)data[5]) && isdigit((int)data[6])) { val = (10 * (data[5] - '0')) + (data[6] - '0'); } else { if (debug_level & 2) { fprintf(stderr,"Bad area sqrt_lon_off"); } return; } temp_area.sqrt_lon_off = val; for (i = 0; i <= len-7; i++) // delete area object from data extension field { data[i] = data[i+7]; } len -= 7; if (temp_area.type == AREA_LINE_RIGHT || temp_area.type == AREA_LINE_LEFT) { if (data[0] == '{') { if (sscanf(data, "{%u}", &uval) == 1) { temp_area.corridor_width = uval & 0xffff; for (i = 0; i <= len; i++) if (data[i] == '}') { break; } uval = i+1; for (i = 0; i <= (int)(len-uval); i++) { data[i] = data[i+uval]; // delete corridor width } } else { if (debug_level & 2) { fprintf(stderr,"Bad corridor width identifier"); } temp_area.corridor_width = 0; return; } } else { if (debug_level & 2) { fprintf(stderr,"No corridor width specified"); } temp_area.corridor_width = 0; } } else { temp_area.corridor_width = 0; } } else { if (debug_level & 2) { fprintf(stderr,"Bad area type: %c\n", data[0]); } return; } memcpy(&(p_station->aprs_symbol.area_object), &temp_area, sizeof(AreaObject)); if (debug_level & 2) { fprintf(stderr,"AreaObject: type=%d color=%d sqrt_lat_off=%d sqrt_lon_off=%d corridor_width=%d\n", p_station->aprs_symbol.area_object.type, p_station->aprs_symbol.area_object.color, p_station->aprs_symbol.area_object.sqrt_lat_off, p_station->aprs_symbol.area_object.sqrt_lon_off, p_station->aprs_symbol.area_object.corridor_width); } } /* * Extract Time from begin of line [APRS Reference, chapter 6] * * If a time string is found in "data", it is deleted from the * beginning of the string. */ int extract_time(DataRow * UNUSED(p_station), char *data, int type) { int len, i; int ok = 0; // todo: better check of time data ranges len = (int)strlen(data); if (type == APRS_WX2) { // 8 digit time from stand-alone positionless weather stations... if (len > 8) { // MMDDHHMM zulu time // MM 01-12 todo: better check of time data ranges // DD 01-31 // HH 01-23 // MM 01-59 ok = 1; for (i=0; ok && i<8; i++) if (!isdigit((int)data[i])) { ok = 0; } if (ok) { // substr(p_station->station_time,data+2,6); // p_station->station_time_type = 'z'; for (i=0; i<=len-8; i++) // delete time from data { data[i] = data[i+8]; } } } } else { if (len > 6) { // Status messages only with optional zulu format // DK7IN: APRS ref says one of 'z' '/' 'h', but I found 'c' at HB9TJM-8 ??? if (toupper(data[6])=='Z' || data[6]=='/' || toupper(data[6])=='H') { ok = 1; } for (i=0; ok && i<6; i++) if (!isdigit((int)data[i])) { ok = 0; } if (ok) { // substr(p_station->station_time,data,6); // p_station->station_time_type = data[6]; for (i=0; i<=len-7; i++) // delete time from data { data[i] = data[i+7]; } } } } return(ok); } // APRS Data Extensions [APRS Reference p.27] // .../... Course & Speed, may be followed by others (see p.27) // .../... Wind Dir and Speed // PHG.... Station Power and Effective Antenna Height/Gain // RNG.... Pre-Calculated Radio Range // DFS.... DF Signal Strength and Effective Antenna Height/Gain // T../C.. Area Object Descriptor /* Extract one of several possible APRS Data Extensions */ void process_data_extension(DataRow *p_station, char *data, int UNUSED(type) ) { char temp1[7+1]; char temp2[3+1]; char temp3[10+1]; char bearing[3+1]; char nrq[3+1]; if (p_station->aprs_symbol.aprs_type == '\\' && p_station->aprs_symbol.aprs_symbol == 'l') { /* This check needs to come first because the area object extension can look exactly like what extract_speed_course will attempt to decode. */ extract_area(p_station, data); } else { clear_area(p_station); // we got a packet with a non area symbol, so clear the data if (extract_speed_course(data,temp1,temp2)) // ... from Mic-E, etc. { //fprintf(stderr,"extracted speed/course\n"); if (atof(temp2) > 0) { //fprintf(stderr,"course is non-zero\n"); xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%06.2f", atof(temp1)); xastir_snprintf(p_station->course, // in degrees sizeof(p_station->course), "%s", temp2); } if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } // Don't try to extract speed & course if a compressed // object. Test for beam headings for compressed packets // here else if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } else { if (extract_powergain_range(data,temp1)) { //fprintf(stderr,"Found power_gain: %s\n", temp1); xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "%s", temp1); if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } else { if (extract_omnidf(data,temp1)) { xastir_snprintf(p_station->signal_gain, sizeof(p_station->signal_gain), "%s", temp1); // Grab the SHGD values p_station->bearing[0] = '\0'; // And blank out the bearing/NRQ values p_station->NRQ[0] = '\0'; // The spec shows speed/course before DFS, but example packets that // come with DOSaprs show DFSxxxx/speed/course. We'll take care of // that possibility by trying to decode speed/course again. if (extract_speed_course(data,temp1,temp2)) // ... from Mic-E, etc. { //fprintf(stderr,"extracted speed/course\n"); if (atof(temp2) > 0) { //fprintf(stderr,"course is non-zero\n"); xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%06.2f", atof(temp1)); xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", temp2); // in degrees } } // The spec shows that omnidf and bearing/NRQ can be in the same // packet, which makes no sense, but we'll try to decode it that // way anyway. if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); //p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } } } if (extract_signpost(data, temp2)) { //fprintf(stderr,"extracted signpost data\n"); xastir_snprintf(p_station->signpost, sizeof(p_station->signpost), "%s", temp2); } if (extract_probability_min(data, temp3, sizeof(temp3))) { if (strncasecmp(temp3, "0.0", sizeof(temp3)) == 0) { p_station->probability_min[0] = '\0'; // Clear it out } else if (strncasecmp(temp3, "0", sizeof(temp3)) == 0) { p_station->probability_min[0] = '\0'; // Clear it out } else { //fprintf(stderr,"extracted probability_min data: %s\n",temp3); xastir_snprintf(p_station->probability_min, sizeof(p_station->probability_min), "%s", temp3); } } else { p_station->probability_min[0] = '\0'; // Clear it out } if (extract_probability_max(data, temp3, sizeof(temp3))) { if (strncasecmp(temp3, "0.0", sizeof(temp3)) == 0) { p_station->probability_max[0] = '\0'; // Clear it out } else if (strncasecmp(temp3, "0", sizeof(temp3)) == 0) { p_station->probability_max[0] = '\0'; // Clear it out } else { //fprintf(stderr,"extracted probability_max data: %s\n",temp3); xastir_snprintf(p_station->probability_max, sizeof(p_station->probability_max), "%s", temp3); } } else { p_station->probability_max[0] = '\0'; // Clear it out } } } /* extract all available information from info field */ void process_info_field(DataRow *p_station, char *info, int UNUSED(type) ) { char temp_data[6+1]; // char time_data[MAX_TIME]; if (extract_altitude(info,temp_data)) // get altitude { xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%.2f",atof(temp_data)*0.3048); //fprintf(stderr,"%.2f\n",atof(temp_data)*0.3048); } // do other things... } //////////////////////////////////////////////////////////////////////////////////////////////////// // type: 18 // call_sign: VE6GRR-15 // path: GPSLV,TCPIP,VE7DIE* // data: GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0, // from: T // port: 0 // origin: // third_party: 1 // // Extract data for $GPRMC, it fails if there is no position!! // // GPRMC,UTC-Time,status(A/V),lat,N/S,lon,E/W,SOG,COG,UTC-Date,Mag-Var,E/W,Fix-Quality[*CHK] // GPRMC,hhmmss[.sss],{A|V},ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},[dd]d.d[ddddd],[dd]d.d[d],ddmmyy,[ddd.d],[{E|W}][,A|D|E|N|S][*CHK] // // The last field before the checksum is entirely optional, and in // fact first appeared in NMEA 2.3 (fairly recently). Most GPS's do // not currently put out that field. The field may be null or // nonexistent including the comma. Only "A" or "D" are considered // to be active and reliable fixes if this field is present. // Fix-Quality: // A: Autonomous // D: Differential // E: Estimated // N: Not Valid // S: Simulator // // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 // $GPRMC,104748.821,A,4301.1492,N,08803.0374,W,0.085048,102.36,010605,,*1A // $GPRMC,104749.821,A,4301.1492,N,08803.0377,W,0.054215,74.60,010605,,*2D // int extract_RMC(DataRow *p_station, char *data, char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[12]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; if (debug_level & 256) { fprintf(stderr,"extract_RMC\n"); } // should we copy it before processing? it changes data: ',' gets substituted by '\0' !! ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 34) ) // Not enough data to parse position from. { if (debug_level & 256) { fprintf(stderr,"Invalid RMC string: Too short\n"); } return(ok); } p_station->record_type = NORMAL_GPS_RMC; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 12, ','); // The Substring[] array contains pointers to each substring in // the original data string. // GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0,E*7D // 0 1 2 3 4 5 6 7 8 9 10 11 if (Substring[0] == NULL) // No GPRMC string { return(ok); } if (Substring[1] == NULL) // No time string { return(ok); } if (Substring[2] == NULL) // No valid fix char { return(ok); } if (Substring[2][0] != 'A' && Substring[2][0] != 'V') { return(ok); } // V is a warning but we can get good data still ? // DK7IN: got no position with 'V' ! if (Substring[3] == NULL) // No latitude string { return(ok); } if (Substring[4] == NULL) // No latitude N/S { return(ok); } // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234) or leave one out (4801.12). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[3],'.')) { *num_digits = strlen(Substring[3]) - (int)(strchr(Substring[3],'.') - Substring[3]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[4][0]); if (temp_char != 'N' && temp_char != 'S') // Bad N/S { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[3], temp_char); if (Substring[5] == NULL) // No longitude string { return(ok); } if (Substring[6] == NULL) // No longitude E/W { return(ok); } // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' temp_char = toupper((int)Substring[6][0]); if (temp_char != 'E' && temp_char != 'W') // Bad E/W { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[5], temp_char); p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); // If we've made it this far, We have enough for a position now! ok = 1; // Now that we have a basic position, let's see what other data // can be parsed from the packet. The rest of it can still be // corrupt, so we're proceeding carefully under yellow alert on // impulse engines only. // GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0,E*7D // 0 1 2 3 4 5 6 7 8 9 10 11 if (Substring[7] == NULL) // No speed string { p_station->speed[0] = '\0'; // No speed available return(ok); } else { xastir_snprintf(p_station->speed, MAX_SPEED, "%s", Substring[7]); // Is it always knots, otherwise we need a conversion! } if (Substring[8] == NULL) // No course string { xastir_snprintf(p_station->course, sizeof(p_station->course), "000.0"); // No course available return(ok); } else { xastir_snprintf(p_station->course, MAX_COURSE, "%s", Substring[8]); } if (debug_level & 256) { if (ok) { fprintf(stderr,"extract_RMC succeeded: %s\n",data); } else { fprintf(stderr,"extract_RMC failed: %s\n",data); } } return(ok); } // // Extract data for $GPGGA // // GPGGA,UTC-Time,lat,N/S,long,E/W,GPS-Quality,nsat,HDOP,MSL-Meters,M,Geoidal-Meters,M,DGPS-Data-Age(seconds),DGPS-Ref-Station-ID[*CHK] // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // // GPS-Quality: // 0: Invalid Fix // 1: GPS Fix // 2: DGPS Fix // 3: PPS Fix // 4: RTK Fix // 5: Float RTK Fix // 6: Estimated (dead-reckoning) Fix // 7: Manual Input Mode // 8: Simulation Mode // // $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75 // $GPGGA,104438.833,4301.1439,N,08803.0338,W,1,05,1.8,185.8,M,-34.2,M,0.0,0000*40 // // nsat=Number of Satellites being tracked // // int extract_GGA(DataRow *p_station,char *data,char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[15]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; int temp_num; if (debug_level & 256) { fprintf(stderr, "extract_GGA\n"); } ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 32) ) // Not enough data to parse position from. { return(ok); } p_station->record_type = NORMAL_GPS_GGA; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 15, ','); // The Substring[] array contains pointers to each substring in // the original data string. // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // 0 1 2 3 4 5 6 7 8 9 1 1 1 1 1 // 0 1 2 3 4 if (Substring[0] == NULL) // No GPGGA string { return(ok); } if (Substring[1] == NULL) // No time string { return(ok); } if (Substring[2] == NULL) // No latitude string { return(ok); } if (Substring[3] == NULL) // No latitude N/S { return(ok); } // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[2],'.')) { *num_digits = strlen(Substring[2]) - (int)(strchr(Substring[2],'.') - Substring[2]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[3][0]); if (temp_char != 'N' && temp_char != 'S') // Bad N/S { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[2], temp_char); if (Substring[4] == NULL) // No longitude string { return(ok); } if (Substring[5] == NULL) // No longitude E/W { return(ok); } // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' temp_char = toupper((int)Substring[5][0]); if (temp_char != 'E' && temp_char != 'W') // Bad E/W { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[4], temp_char); p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); // If we've made it this far, We have enough for a position now! ok = 1; // Now that we have a basic position, let's see what other data // can be parsed from the packet. The rest of it can still be // corrupt, so we're proceeding carefully under yellow alert on // impulse engines only. // Check for valid fix { if (Substring[6] == NULL || Substring[6][0] == '0' // Fix quality || Substring[7] == NULL // Sat number || Substring[8] == NULL // hdop || Substring[9] == NULL) // Altitude in meters { p_station->sats_visible[0] = '\0'; // Store empty sats visible p_station->altitude[0] = '\0';; // Store empty altitude return(ok); // A field between fix quality and altitude is missing } // Need to check for validity of this number. Should be 0-12? Perhaps a few more with WAAS, GLONASS, etc? temp_num = atoi(Substring[7]); if (temp_num < 0 || temp_num > 30) { return(ok); // Number of satellites not valid } else { // Store xastir_snprintf(p_station->sats_visible, sizeof(p_station->sats_visible), "%d", temp_num); } // Check for valid number for HDOP instead of just throwing it away? xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%s", Substring[9]); // Get altitude // Need to check for valid altitude before conversion // unit is in meters, if not adjust value ??? if (Substring[10] == NULL) // No units for altitude { return(ok); } if (Substring[10][0] != 'M') { //fprintf(stderr,"ERROR: should adjust altitude for meters\n"); //} else { // Altitude units wrong. Assume altitude bad p_station->altitude[0] = '\0'; } if (debug_level & 256) { if (ok) { fprintf(stderr,"extract_GGA succeeded: %s\n",data); } else { fprintf(stderr,"extract_GGA failed: %s\n",data); } } return(ok); } // // Extract data for $GPGLL // // $GPGLL,4748.811,N,12219.564,W,033850,A*3C // lat, long, UTCtime in hhmmss, A=Valid, checksum // // GPGLL,4748.811,N,12219.564,W,033850,A*3C // 0 1 2 3 4 5 6 // int extract_GLL(DataRow *p_station,char *data,char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[7]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; if (debug_level & 256) { fprintf(stderr, "extract_GLL\n"); } ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 28) ) // Not enough data to parse position from. { return(ok); } p_station->record_type = NORMAL_GPS_GLL; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 7, ','); // The Substring[] array contains pointers to each substring in // the original data string. if (Substring[0] == NULL) // No GPGGA string { return(ok); } if (Substring[1] == NULL) // No latitude string { return(ok); } if (Substring[2] == NULL) // No N/S string { return(ok); } if (Substring[3] == NULL) // No longitude string { return(ok); } if (Substring[4] == NULL) // No E/W string { return(ok); } temp_char = toupper((int)Substring[2][0]); if (temp_char != 'N' && temp_char != 'S') { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[1], temp_char); // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[1],'.')) { *num_digits = strlen(Substring[1]) - (int)(strchr(Substring[1],'.') - Substring[1]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[4][0]); if (temp_char != 'E' && temp_char != 'W') { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[3], temp_char); // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); ok = 1; // We have enough for a position now xastir_snprintf(p_station->course, sizeof(p_station->course), "000.0"); // Fill in with dummy values p_station->speed[0] = '\0'; // Fill in with dummy values // A is valid, V is a warning but we can get good data still? // We don't currently check the data valid flag. return(ok); } // Add a status line to the linked-list of status records // associated with a station. Note that a blank status line is // allowed, but we don't store that unless we have seen a non-blank // status line previously. // void add_status(DataRow *p_station, char *status_string) { CommentRow *ptr; int add_it = 0; int len; len = strlen(status_string); // Eliminate line-end chars if (len > 1) { if ( (status_string[len-1] == '\n') || (status_string[len-1] == '\r') ) { status_string[len-1] = '\0'; } } // Shorten it //fprintf(stderr,"1Status: (%s)\n",status_string); (void)remove_trailing_spaces(status_string); //fprintf(stderr,"2Status: (%s)\n",status_string); (void)remove_leading_spaces(status_string); //fprintf(stderr,"3Status: (%s)\n",status_string); len = strlen(status_string); // Check for valid pointer if (p_station != NULL) { // We should probably create a new station record for this station // if there isn't one. This allows us to collect as much info about // a station as we can until a posit comes in for it. Right now we // don't do this. If we decide to do this in the future, we also // need a method to find out the info about that station without // having to click on an icon, 'cuz the symbol won't be on our map // until we have a posit. //fprintf(stderr,"Station:%s\tStatus:%s\n",p_station->call_sign,status_string); // Check whether we have any data stored for this station if (p_station->status_data == NULL) { if (len > 0) { // No status stored yet and new status is non-NULL, // so add it to the list. add_it++; } } else // We have status data stored already { // Check for an identical string CommentRow *ptr2; int ii = 0; ptr = p_station->status_data; ptr2 = ptr; while (ptr != NULL) { // Note that both text_ptr and comment_string can be // empty strings. if (strcasecmp(ptr->text_ptr, status_string) == 0) { // Found a matching string //fprintf(stderr,"Found match: //%s:%s\n",p_station->call_sign,status_string); // Instead of updating the timestamp, we'll delete the record from // the list and add it to the top in the code below. Make sure to // tweak the "ii" pointer so that we don't end up shortening the // list unnecessarily. if (ptr == p_station->status_data) { // Only update the timestamp: We're at the // beginning of the list already. ptr->sec_heard = sec_now(); return; // No need to add a new record } else // Delete the record { CommentRow *ptr3; // Keep a pointer to the record ptr3 = ptr; // Close the chain, skipping this record ptr2->next = ptr3->next; // Skip "ptr" over the record we wish to // delete ptr = ptr3->next; // Free the record free(ptr3->text_ptr); free(ptr3); // Muck with the counter 'cuz we just // deleted one record ii--; } } ptr2 = ptr; // Back one record if (ptr != NULL) { ptr = ptr->next; } ii++; } // No matching string found, or new timestamp found for // old record. Add it to the top of the list. add_it++; //fprintf(stderr,"No match: //%s:%s\n",p_station->call_sign,status_string); // We counted the records. If we have more than // MAX_STATUS_LINES records we'll delete/free the last // one to make room for the next. This keeps us from // storing unique status records ad infinitum for active // stations, limiting the total space used. // if (ii >= MAX_STATUS_LINES) { // We know we didn't get a match, and that our list // is full (as full as we want it to be). Traverse // the list again, looking for ptr2->next->next == // NULL. If found, free last record and set the // ptr2->next pointer to NULL. ptr2 = p_station->status_data; while (ptr2->next->next != NULL) { ptr2 = ptr2->next; } // At this point, we have a pointer to the last // record in ptr2->next. Free it and the text // string in it. free(ptr2->next->text_ptr); free(ptr2->next); ptr2->next = NULL; } } if (add_it) // We add to the beginning so we don't have { // to traverse the linked list. This also // puts new records at the beginning of the // list to keep them in sorted order. ptr = p_station->status_data; // Save old pointer to records p_station->status_data = (CommentRow *)malloc(sizeof(CommentRow)); CHECKMALLOC(p_station->status_data); p_station->status_data->next = ptr; // Link in old records or NULL // Malloc the string space we'll need, attach it to our // new record p_station->status_data->text_ptr = (char *)malloc(sizeof(char) * (len+1)); CHECKMALLOC(p_station->status_data->text_ptr); // Fill in the string xastir_snprintf(p_station->status_data->text_ptr, len+1, "%s", status_string); // Fill in the timestamp p_station->status_data->sec_heard = sec_now(); //fprintf(stderr,"Station:%s\tStatus:%s\n\n",p_station->call_sign,p_station->status_data->text_ptr); } } } // Add a comment line to the linked-list of comment records // associated with a station. Note that a blank comment is allowed // and necessary for the times when we wish to blank out the comment // on an object/item, but we don't store that unless we have seen a // non-blank comment line previously. // void add_comment(DataRow *p_station, char *comment_string) { CommentRow *ptr; int add_it = 0; int len; len = strlen(comment_string); // Eliminate line-end chars if (len > 1) { if ( (comment_string[len-1] == '\n') || (comment_string[len-1] == '\r') ) { comment_string[len-1] = '\0'; } } // Shorten it //fprintf(stderr,"1Comment: (%s)\n",comment_string); (void)remove_trailing_spaces(comment_string); //fprintf(stderr,"2Comment: (%s)\n",comment_string); ///////TVR DEBUGGING RESULTS 28 March 2007: //NO! DON'T DO THIS --- it breaks multipoint objects! // (void)remove_leading_spaces(comment_string); /////////////////////////////////////////// //fprintf(stderr,"3Comment: (%s)\n",comment_string); len = strlen(comment_string); // Check for valid pointer if (p_station != NULL) { // Check whether we have any data stored for this station if (p_station->comment_data == NULL) { if (len > 0) { // No comments stored yet and new comment is // non-NULL, so add it to the list. add_it++; } } else // We have comment data stored already { // Check for an identical string CommentRow *ptr2; int ii = 0; ptr = p_station->comment_data; ptr2 = ptr; while (ptr != NULL) { // Note that both text_ptr and comment_string can be // empty strings. if (strcasecmp(ptr->text_ptr, comment_string) == 0) { // Found a matching string //fprintf(stderr,"Found match: %s:%s\n",p_station->call_sign,comment_string); // Instead of updating the timestamp, we'll delete the record from // the list and add it to the top in the code below. Make sure to // tweak the "ii" pointer so that we don't end up shortening the // list unnecessarily. if (ptr == p_station->comment_data) { // Only update the timestamp: We're at the // beginning of the list already. ptr->sec_heard = sec_now(); return; // No need to add a new record } else // Delete the record { CommentRow *ptr3; // Keep a pointer to the record ptr3 = ptr; // Close the chain, skipping this record ptr2->next = ptr3->next; // Skip "ptr" over the record we with to // delete ptr = ptr3->next; // Free the record free(ptr3->text_ptr); free(ptr3); // Muck with the counter 'cuz we just // deleted one record ii--; } } ptr2 = ptr; // Keep this pointer one record back as // we progress. if (ptr != NULL) { ptr = ptr->next; } ii++; } // No matching string found, or new timestamp found for // old record. Add it to the top of the list. add_it++; //fprintf(stderr,"No match: %s:%s\n",p_station->call_sign,comment_string); // We counted the records. If we have more than // MAX_COMMENT_LINES records we'll delete/free the last // one to make room for the next. This keeps us from // storing unique comment records ad infinitum for // active stations, limiting the total space used. // if (ii >= MAX_COMMENT_LINES) { // We know we didn't get a match, and that our list // is full (as we want it to be). Traverse the list // again, looking for ptr2->next->next == NULL. If // found, free that last record and set the // ptr2->next pointer to NULL. ptr2 = p_station->comment_data; while (ptr2->next->next != NULL) { ptr2 = ptr2->next; } // At this point, we have a pointer to the last // record in ptr2->next. Free it and the text // string in it. free(ptr2->next->text_ptr); free(ptr2->next); ptr2->next = NULL; } } if (add_it) // We add to the beginning so we don't have { // to traverse the linked list. This also // puts new records at the beginning of the // list to keep them in sorted order. ptr = p_station->comment_data; // Save old pointer to records p_station->comment_data = (CommentRow *)malloc(sizeof(CommentRow)); CHECKMALLOC(p_station->comment_data); p_station->comment_data->next = ptr; // Link in old records or NULL // Malloc the string space we'll need, attach it to our // new record p_station->comment_data->text_ptr = (char *)malloc(sizeof(char) * (len+1)); CHECKMALLOC(p_station->comment_data->text_ptr); // Fill in the string xastir_snprintf(p_station->comment_data->text_ptr, len+1, "%s", comment_string); // Fill in the timestamp p_station->comment_data->sec_heard = sec_now(); } } } /* * Add data from APRS information field to station database * Returns a 1 if successful */ int data_add(int type, char *call_sign, char *path, char *data, char from, int port, char *origin, int third_party, int station_is_mine, int object_is_mine) { DataRow *p_station; DataRow *p_time; char call[MAX_CALLSIGN+1]; char new_station; long last_lat, last_lon; char last_alt[MAX_ALTITUDE]; char last_speed[MAX_SPEED+1]; char last_course[MAX_COURSE+1]; time_t last_stn_sec; short last_flag; char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... long l_lat, l_lon; double distance; char station_id[600]; int found_pos; float value; WeatherRow *weather; int moving; int changed_pos; int screen_update; int ok, store; int ok_to_display; int compr_pos; char *p = NULL; // KC2ELS - used for WIDEn-N int direct = 0; int new_origin_is_mine = 0; int num_digits = 0; // Number of digits after decimal point in NMEA string #ifdef HAVE_DB int ii; // loop counter for interfaces list #endif /* HAVE_DB */ // call and path had been validated before // Check "data" against the max APRS length, and dump the packet if too long. if ( (data != NULL) && (strlen(data) > MAX_INFO_FIELD_SIZE) ) // Overly long packet. Throw it away. { if (debug_level & 1) { fprintf(stderr,"data_add: Overly long packet. Throwing it away.\n"); } return(0); // Not an ok packet } // Check for some reasonable string in call_sign parameter if (call_sign == NULL || strlen(call_sign) == 0) { if (debug_level & 1) { fprintf(stderr,"data_add():call_sign was NULL or empty, exiting\n"); } return(0); } if (debug_level & 1) fprintf(stderr,"data_add:\n\ttype: %d\n\tcall_sign: %s\n\tpath: %s\n\tdata: %s\n\tfrom: %c\n\tport: %d\n\torigin: %s\n\tthird_party: %d\n", type, call_sign, path, data ? data : "NULL", // This parameter may be NULL, if exp1 then exp2 else exp3 from, port, origin ? origin : "NULL", // This parameter may be NULL third_party); if (origin && is_my_call(origin, 1)) { new_origin_is_mine++; // The new object/item is owned by me } weather = NULL; // only to make the compiler happy... found_pos = 1; xastir_snprintf(call, sizeof(call), "%s", call_sign); p_station = NULL; new_station = (char)FALSE; // to make the compiler happy... last_lat = 0L; last_lon = 0L; last_stn_sec = sec_now(); last_alt[0] = '\0'; last_speed[0] = '\0'; last_course[0] = '\0'; last_flag = 0; ok = 0; store = 0; p_time = NULL; // add to end of time sorted list (newest) compr_pos = 0; if (search_station_name(&p_station,call,1)) // If we found the station in our list { if (debug_level & 1) { fprintf(stderr,"data_add: Found existing station record.\n"); } move_station_time(p_station,p_time); // update time, change position in time sorted list new_station = (char)FALSE; // we have seen this one before if (is_my_station(p_station)) { station_is_mine++; // Station is me } //fprintf(stderr,"checks ok\n"); } else { //fprintf(stderr,"data_add()\n"); if (debug_level & 1) { fprintf(stderr,"data_add: No existing station record found.\n"); } p_station = add_new_station(p_station,p_time,call); // create storage new_station = (char)TRUE; // for new station } if (p_station != NULL) { last_lat = p_station->coord_lat; // remember last position last_lon = p_station->coord_lon; last_stn_sec = p_station->sec_heard; xastir_snprintf(last_alt, sizeof(last_alt), "%s", p_station->altitude); xastir_snprintf(last_speed, sizeof(last_speed), "%s", p_station->speed); xastir_snprintf(last_course, sizeof(last_course), "%s", p_station->course); last_flag = p_station->flag; // Wipe out old data so that it doesn't hang around forever p_station->altitude[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; ok = 1; // succeed as default switch (type) { case (APRS_MICE): // Mic-E format case (APRS_FIXED): // '!' case (APRS_MSGCAP): // '=' if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } if (ok) { // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for weather data first process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); p_station->record_type = NORMAL_APRS; if (type == APRS_MSGCAP) { p_station->flag |= ST_MSGCAP; // set "message capable" flag } else { p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag } // Assign a non-default value for the error // ellipse? if (type == APRS_MICE || !compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; /* case (APRS_DOWN): // '/' ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) { // uncompressed lat/lon compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon ok = 0; else p_station->pos_amb = 0; // No ambiguity in compressed posits } } if (ok) { // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) extract_multipoints(p_station, data, type, 1); add_comment(p_station,data); p_station->record_type = DOWN_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; */ case (APRS_DF): // '@' case (APRS_MOBILE): // '@' ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } if (ok) { process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); if(type == APRS_MOBILE) { p_station->record_type = MOBILE_APRS; } else { p_station->record_type = DF_APRS; } //@ stations have messaging per spec p_station->flag |= (ST_MSGCAP); // set "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_GRID): ok = extract_position(p_station, &data, type); if (ok) { if (debug_level & 1) { fprintf(stderr,"data_add: Got grid data for %s\n", call); } process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); // Assign a non-default value for the error // ellipse? // p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution // WE7U // This needs to change based on the number of grid letters/digits specified // p_station->lat_precision = 60; // p_station->lon_precision = 60; } else { if (debug_level & 1) { fprintf(stderr,"data_add: Bad grid data for %s : %s\n", call, data); } } break; case (STATION_CALL_DATA): p_station->record_type = NORMAL_APRS; found_pos = 0; break; case (APRS_STATUS): // '>' Status Reports [APRS Reference, chapter 16] (void)extract_time(p_station, data, type); // we need a time // todo: could contain Maidenhead or beam heading+power if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_status(p_station,data); p_station->flag |= (ST_STATUS); // set "Status" flag p_station->record_type = NORMAL_APRS; // ??? found_pos = 0; break; case (OTHER_DATA): // Other Packets [APRS Reference, chapter 19] // non-APRS beacons, treated as status reports until we get a real one if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } if ((p_station->flag & (~ST_STATUS)) == 0) // only store if no status yet { add_status(p_station,data); p_station->record_type = NORMAL_APRS; // ??? } found_pos = 0; break; case (APRS_OBJECT): if (debug_level & 2048) { fprintf (stderr," Object: before any extractions at all, data is \"%s\"\n",data); } // If old match is a killed Object (owner doesn't // matter), new one is an active Object and owned by // us, remove the old record and create a new one // for storing this Object. Do the same for Items // in the next section below. // // The easiest implementation might be to remove the // old record and then call this routine again with // the same parameters, which will cause a brand-new // record to be created. // // The new record we're processing is an active // object, as data_add() won't be called on a killed // object. // // if ( is_my_call(origin,1) // If new Object is owned by me (including SSID) if (new_origin_is_mine && !(p_station->flag & ST_ACTIVE) && (p_station->flag & ST_OBJECT) ) // Old record was a killed Object { station_del_ptr(p_station); // Remove old killed Object // *completely* redo_list = (int)TRUE; return( data_add(type, call_sign, path, data, from, port, origin, third_party, 0, 1) ); } ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } p_station->flag |= ST_OBJECT; // Set "Object" flag if (ok) { // If object was owned by me but another station // is transmitting it now, write entries into // the object.log file showing that we don't own // this object anymore. // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) // If station was owned by me (include SSID) && !new_origin_is_mine) // But isn't now { disown_object_item(call_sign, origin); } // If station is owned by me (including SSID) // but it's a new object/item // if ( (is_my_call(p_station->origin,1)) if (new_origin_is_mine && (p_station->transmit_time_increment == 0) ) { // This will get us transmitting this object // on the decaying algorithm schedule. // We've transmitted it once if we've just // gotten to this code. p_station->transmit_time_increment = OBJECT_CHECK_RATE; //fprintf(stderr,"data_add(): Setting transmit_time_increment to %d\n", OBJECT_CHECK_RATE); } // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // define it as object if (debug_level & 2048) { fprintf (stderr," Object: before any extractions, data is \"%s\"\n",data); } (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for wx info process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if (debug_level & 2048) { fprintf (stderr," Object: calling extract_multipoints with data \"%s\"\n",data); } if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 0); } add_comment(p_station,data); // the last char always was missing... //p_station->comments[ strlen(p_station->comments) - 1 ] = '\0'; // Wipe out '\n' // moved that to decode_ax25_line // and don't added a '\n' in interface.c p_station->record_type = NORMAL_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_ITEM): // If old match is a killed Item (owner doesn't // matter), new one is an active Item and owned by // us, remove the old record and create a new one // for storing this Item. Do the same for Objects // in the previous section above. // // The easiest implementation might be to remove the // old record and then call this routine again with // the same parameters, which will cause a brand-new // record to be created. // // The new record we're processing is an active // Item, as data_add() won't be called on a killed // Item. // // if ( is_my_call(origin,1) // If new Item is owned by me (including SSID) if (new_origin_is_mine && !(p_station->flag & ST_ACTIVE) && (p_station->flag & ST_ITEM) ) // Old record was a killed Item { station_del_ptr(p_station); // Remove old killed Item // *completely* redo_list = (int)TRUE; return( data_add(type, call_sign, path, data, from, port, origin, third_party, 0, 1) ); } if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } p_station->flag |= ST_ITEM; // Set "Item" flag if (ok) { // If item was owned by me but another station // is transmitting it now, write entries into // the object.log file showing that we don't own // this item anymore. // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) && !new_origin_is_mine) // But isn't now { disown_object_item(call_sign,origin); } // If station is owned by me (including SSID) // but it's a new object/item // if ( (is_my_call(p_station->origin,1)) if (is_my_object_item(p_station) && (p_station->transmit_time_increment == 0) ) { // This will get us transmitting this object // on the decaying algorithm schedule. // We've transmitted it once if we've just // gotten to this code. p_station->transmit_time_increment = OBJECT_CHECK_RATE; //fprintf(stderr,"data_add(): Setting transmit_time_increment to %d\n", OBJECT_CHECK_RATE); } // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // define it as item (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for wx info process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 0); } add_comment(p_station,data); // the last char always was missing... //p_station->comments[ strlen(p_station->comments) - 1 ] = '\0'; // Wipe out '\n' // moved that to decode_ax25_line // and don't added a '\n' in interface.c p_station->record_type = NORMAL_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_WX1): // weather in '@' or '/' packet ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } if (ok) { (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); p_station->record_type = (char)APRS_WX1; process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_WX2): // '_' ok = extract_time(p_station, data, type); // we need a time if (ok) { (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,0); // look for weather data first p_station->record_type = (char)APRS_WX2; found_pos = 0; process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } } break; case (APRS_WX4): // '#' Peet Bros U-II (km/h) case (APRS_WX6): // '*' Peet Bros U-II (mph) case (APRS_WX3): // '!' Peet Bros Ultimeter 2000 (data logging mode) case (APRS_WX5): // '$ULTW' Peet Bros Ultimeter 2000 (packet mode) if (get_weather_record(p_station)) // get existing or create new weather record { weather = p_station->weather_data; if (type == APRS_WX3) // Peet Bros Ultimeter 2000 data logging mode { decode_U2000_L(1,(unsigned char *)data,weather); } else if (type == APRS_WX5) // Peet Bros Ultimeter 2000 packet mode { decode_U2000_P(1,(unsigned char *)data,weather); } else // Peet Bros Ultimeter-II { decode_Peet_Bros(1,(unsigned char *)data,weather,type); } p_station->record_type = (char)type; // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(temp_data)); weather->wx_sec_time = sec_now(); found_pos = 0; } break; // GPRMC, digits after decimal point // --------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse // 4+ = 6.0 meter error ellipse case (GPS_RMC): // $GPRMC // WE7U // Change this function to return HDOP and the number of characters // after the decimal point. ok = extract_RMC(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius (25.5m). // Best (smallest) circle should be 600 as we have no augmentation // flag to check here for anything better. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; // GPGGA, digits after decimal point, w/o augmentation // --------------------------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse unless HDOP>4, then 10.0 meters // 4+ = 6.0 meter error ellipse unless HDOP>4, then 10.0 meters // // // GPGGA, digits after decimal point, w/augmentation // -------------------------------------------------- // 2 = 25.5 meter error ellipse // 3 = 2.5 meter error ellipse unless HDOP>4, then 10.0 meters // 4+ = 0.6 meter error ellipse unless HDOP>4, then 10.0 meters case (GPS_GGA): // $GPGGA // WE7U // Change this function to return HDOP and the number of characters // after the decimal point. ok = extract_GGA(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius (25.5m). // 3 digits: 6m w/o augmentation unless HDOP >4 = 10m, 2.5m w/augmentation. // 4+ digits: 6m w/o augmentation unless HDOP >4 = 10m, 0.6m w/augmentation. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; // GPGLL, digits after decimal point // --------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse // 4+ = 6.0 meter error ellipse case (GPS_GLL): // $GPGLL ok = extract_GLL(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius, otherwise // give it 600. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; default: fprintf(stderr,"ERROR: UNKNOWN TYPE in data_add\n"); ok = 0; break; } // Left this one in, just in case. Perhaps somebody might // attach a multipoint string onto the end of a packet we // might not expect. For this case we need to check whether // we have multipoints first, as we don't want to erase the // work we might have done with a previous call to // extract_multipoints(). if (ok && (p_station->coord_lat > 0) && (p_station->coord_lon > 0) && (p_station->num_multipoints == 0) ) // No multipoints found yet { extract_multipoints(p_station, data, type, 0); } } if (!ok) // non-APRS beacon, treat it as Other Packet [APRS Reference, chapter 19] { if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", data-1); makePrintable(filtered_data); fprintf(stderr,"store non-APRS data as status: %s: |%s|\n",call,filtered_data); } // GPRMC etc. without a position is here too, but it should not be stored as status! // store it as status report until we get a real one if ((p_station->flag & (~ST_STATUS)) == 0) // only store it if no status yet { add_status(p_station,data-1); p_station->record_type = NORMAL_APRS; // ??? } ok = 1; found_pos = 0; } curr_sec = sec_now(); if (ok) { // data packet is valid // announce own echo, we soon discard that packet... // if (!new_station && is_my_call(p_station->call_sign,1) // Check SSID as well if (!new_station && is_my_station(p_station) // Check SSID as well && strchr(path,'*') != NULL) { upd_echo(path); // store digi that echoes my signal... statusline(langcode("BBARSTA033"),0); // Echo from digipeater } // check if data is just a secondary echo from another digi if ((last_flag & ST_VIATNC) == 0 || (curr_sec - last_stn_sec) > 15 || p_station->coord_lon != last_lon || p_station->coord_lat != last_lat) { store = 1; // don't store secondary echos } } if (!ok && new_station) { delete_station_memory(p_station); // remove unused record } if (store) { // we now have valid data to store into database // make time index unique by adding a serial number if (station_is_mine) { // This station is me. Set the // flag which shows that we own/control this // station. We use this flag later in lieu // of the is_my_call() function in order to speed things // up. // p_station->flag |= ST_MYSTATION; } // Check whether it's a locally-owned object/item if ( object_is_mine || ( new_origin_is_mine && (p_station->flag & ST_ACTIVE) && (p_station->flag & ST_OBJECT) ) ) { p_station->flag |= ST_MYOBJITEM; // Do nothing else. We don't want to update the // last-heard time so that it'll expire from the queue // normally, unless it is a new object/item. // if (new_station) { p_station->sec_heard = curr_sec; } // We need an exception later in this function for the // case where we've moved an object/item (by how much?). // We need to update the time in this case so that it'll // expire later (in fact it could already be expired // when we move it). We should be able to move expired // objects/items to make them active again. Perhaps // some other method as well?. } else { // Reset the "my object" flag p_station->flag &= ~ST_MYOBJITEM; p_station->sec_heard = curr_sec; // Give it a new timestamp } if (curr_sec != last_sec) // todo: if old time calculate time_sn from database { last_sec = curr_sec; next_time_sn = 0; // restart time serial number } p_station->time_sn = next_time_sn++; // todo: warning if serial number too high if (from == DATA_VIA_TNC) // heard via TNC { if (!third_party) // Not a third-party packet { p_station->flag |= ST_VIATNC; // set "via TNC" flag p_station->heard_via_tnc_last_time = curr_sec; p_station->heard_via_tnc_port = port; } else // Third-party packet { // Leave the previous setting of "flag" alone. // Specifically do NOT set the ST_VIATNC flag if it // was a third-party packet. } } else // heard other than TNC { if (new_station) // new station { p_station->flag &= (~ST_VIATNC); // clear "via TNC" flag //fprintf(stderr,"New_station: Cleared ST_VIATNC flag: %s\n", p_station->call_sign); p_station->heard_via_tnc_last_time = 0l; } } p_station->last_port_heard = port; p_station->data_via = from; // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // get_time returns value in temp_data p_station->flag |= ST_ACTIVE; if (third_party) { p_station->flag |= ST_3RD_PT; // set "third party" flag } else { p_station->flag &= (~ST_3RD_PT); // clear "third party" flag } if (origin != NULL && strcmp(origin,"INET") == 0) // special treatment for inet names xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin != NULL && strcmp(origin,"INET-NWS") == 0) // special treatment for NWS xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin != NULL && strcmp(origin,"INET-BOM") == 0) // special treatment for BOM (AU) xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin == NULL || origin[0] == '\0') // normal call { p_station->origin[0] = '\0'; // undefine possible former object with same name } //-------------------------------------------------------------------- // KC2ELS // Okay, here are the standards for ST_DIRECT: // 1. The packet must have been received via TNC. // 2. The packet must not have any * flags. // 3. If present, the first WIDEn-N (or TRACEn-N) must have n=N. // A station retains the ST_DIRECT setting. If // "st_direct_timeout" seconds have passed since we set // that bit then APRSD queries and displays based on the // ST_DIRECT bit will skip that station. // In order to make this scheme work for stations that straddle both // RF and INET, we need to make sure that node_path_ptr doesn't get // overwritten with an INET path if there's an RF path already in // there and it has been less than st_direct_timeout seconds since // the station was last heard on RF. if ((from == DATA_VIA_TNC) // Heard via TNC && !third_party // Not a 3RD-Party packet && path != NULL // Path is not NULL && strchr(path,'*') == NULL) // No asterisk found { // Look for WIDE or TRACE if ((((p = strstr(path,"WIDE")) != NULL) && (p+=4)) || (((p = strstr(path,"TRACE")) != NULL) && (p+=5))) { // Look for n=N on WIDEn-N/TRACEn-N digi field if ((*p != '\0') && isdigit((int)*p)) { if ((*(p+1) != '\0') && (*(p+1) == '-')) { if ((*(p+2) != '\0') && isdigit((int)*(p+2))) { if (*(p) == *(p+2)) { direct = 1; } else { direct = 0; } } else { direct = 0; } } else { direct = 0; } } else { direct = 1; } } else { direct = 1; } } else { direct = 0; } if (direct == 1) { // This packet was heard direct. Set the ST_DIRECT bit // and save the timestamp away. if (debug_level & 1) { fprintf(stderr,"Setting ST_DIRECT for station %s\n", p_station->call_sign); } p_station->direct_heard = curr_sec; p_station->flag |= (ST_DIRECT); } else { // This packet was NOT heard direct. Check whether we // need to expire the ST_DIRECT bit. A lot of fixed // stations transmit every 30 minutes. One hour gives // us time to receive a direct packet from them among // all the digipeated packets. if ((p_station->flag & ST_DIRECT) != 0 && curr_sec > (p_station->direct_heard + st_direct_timeout)) { if (debug_level & 1) fprintf(stderr,"Clearing ST_DIRECT for station %s\n", p_station->call_sign); p_station->flag &= (~ST_DIRECT); } } // If heard on TNC, overwrite node_path_ptr if any of these // conditions are met: // *) direct == 1 (packet was heard direct) // *) ST_DIRECT flag == 0 (packet hasn't been heard // direct recently) // *) ST_DIRECT is set, st_direct_timeout has expired // (packet hasn't been heard direct recently) // // These rules will allow us to keep directly heard paths // saved for at least an hour (st_direct_timeout), and not // get overwritten with digipeated paths during that time. // if ((from == DATA_VIA_TNC) // Heard via TNC && !third_party // Not a 3RD-Party packet && path != NULL) // Path is not NULL { // Heard on TNC interface and not third party. Check // the other conditions listed in the comments above to // decide whether we should overwrite the node_path_ptr // variable. // if ( direct // This packet was heard direct || (p_station->flag & ST_DIRECT) == 0 // Not heard direct lately || ( (p_station->flag & ST_DIRECT) != 0 // Not heard direct lately && (curr_sec > (p_station->direct_heard+st_direct_timeout) ) ) ) { // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); } } // If a 3rd-party packet heard on TNC, overwrite // node_path_ptr only if heard_via_tnc_last_time is older // than one hour (zero counts as well!), plus clear the // ST_DIRECT and ST_VIATNC bits in this case. This makes us // keep the RF path around for at least one hour after the // station is heard. // else if ((from == DATA_VIA_TNC) // Heard via TNC && third_party // It's a 3RD-Party packet && path != NULL) // Path is not NULL { // 3rd-party packet heard on TNC interface. Check if // heard_via_tnc_last_time is older than an hour. If // so, overwrite the path and clear a few bits to show // that it has timed out on RF and we're now receiving // that station from an igate. // if (curr_sec > (p_station->heard_via_tnc_last_time + 60*60)) { // Yep, more than one hour old or is a zero, // overwrite the node_path_ptr variable with the new // one. We're only hearing this station on INET // now. // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); // Clear the ST_VIATNC bit p_station->flag &= ~ST_VIATNC; } // If direct_heard is over an hour old, clear the // ST_DIRECT flag. We're only hearing this station on // INET now. // if (curr_sec > (p_station->direct_heard + st_direct_timeout)) { // Yep, more than one hour old or is a zero, clear // the ST_DIRECT flag. p_station->flag &= ~ST_DIRECT; } } // If heard on INET then overwrite node_path_ptr only if // heard_via_tnc_last_time is older than one hour (zero // counts as well!), plus clear the ST_DIRECT and ST_VIATNC // bits in this case. This makes us keep the RF path around // for at least one hour after the station is heard. // else if (from != DATA_VIA_TNC // From an INET interface && !third_party // Not a 3RD-Party packet && path != NULL) // Path is not NULL { // Heard on INET interface. Check if // heard_via_tnc_last_time is older than an hour. If // so, overwrite the path and clear a few bits to show // that it has timed out on RF and we're now receiving // that station from the INET feeds. // if (curr_sec > (p_station->heard_via_tnc_last_time + 60*60)) { // Yep, more than one hour old or is a zero, // overwrite the node_path_ptr variable with the new // one. We're only hearing this station on INET // now. // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); // Clear the ST_VIATNC bit p_station->flag &= ~ST_VIATNC; /* fprintf(stderr, "\ntype:%d call:%s path:%s data:%s from:%c port:%d origin:%s 3rd:%d\n", type, call_sign, path, data, from, port, origin, third_party); fprintf(stderr,"Cleared ST_VIATNC flag (2): %s\n", p_station->call_sign); */ } // If direct_heard is over an hour old, clear the // ST_DIRECT flag. We're only hearing this station on // INET now. // if (curr_sec > (p_station->direct_heard + st_direct_timeout)) { // Yep, more than one hour old or is a zero, clear // the ST_DIRECT flag. p_station->flag &= ~ST_DIRECT; } } //--------------------------------------------------------------------- p_station->num_packets += 1; redo_list = (int)TRUE; // we may need to update the lists if (found_pos) // if station has a position with the data { if (position_on_extd_screen(p_station->coord_lat,p_station->coord_lon)) { p_station->flag |= (ST_INVIEW); // set "In View" flag if (debug_level & 256) { fprintf(stderr,"Setting ST_INVIEW flag\n"); } } else { p_station->flag &= (~ST_INVIEW); // clear "In View" flag if (debug_level & 256) { fprintf(stderr,"Clearing ST_INVIEW flag\n"); } } } screen_update = 0; if (new_station) { if (debug_level & 256) { fprintf(stderr,"New Station %s\n", p_station->call_sign); } if (strlen(p_station->speed) > 0 && atof(p_station->speed) > 0) { p_station->flag |= (ST_MOVING); // it has a speed, so it's moving moving = 1; } if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { if (p_station->coord_lat != 0 && p_station->coord_lon != 0) // discard undef positions from screen { if (!altnet || is_altnet(p_station) ) { display_station(da,p_station,1); screen_update = 1; // ??? } } } } else // we had seen this station before... { if (debug_level & 256) { fprintf(stderr,"New Data for %s %ld %ld\n", p_station->call_sign, p_station->coord_lat, p_station->coord_lon); } if (found_pos && position_defined(p_station->coord_lat,p_station->coord_lon,1)) // ignore undefined and 0N/0E { if (debug_level & 256) { fprintf(stderr," Valid position for %s\n", p_station->call_sign); } if (p_station->newest_trackpoint != NULL) { if (debug_level & 256) { fprintf(stderr,"Station has a trail: %s\n", p_station->call_sign); } moving = 1; // it's moving if it has a trail } else { if (strlen(p_station->speed) > 0 && atof(p_station->speed) > 0) { if (debug_level & 256) { fprintf(stderr,"Speed detected on %s\n", p_station->call_sign); } moving = 1; // declare it moving, if it has a speed } else { if (debug_level & 256) { fprintf(stderr,"Position defined: %d, Changed: %s\n", position_defined(last_lat, last_lon, 1), (p_station->coord_lat != last_lat || p_station->coord_lon != last_lon) ? "Yes" : "No"); } // Here's where we detect movement if (position_defined(last_lat,last_lon,1) && (p_station->coord_lat != last_lat || p_station->coord_lon != last_lon)) { if (debug_level & 256) { fprintf(stderr,"Position Change detected on %s\n", p_station->call_sign); } moving = 1; // it's moving if it has changed the position } else { if (debug_level & 256) { fprintf(stderr,"Station %s still appears stationary.\n", p_station->call_sign); fprintf(stderr," %s stationary at %ld %ld (%ld %ld)\n", p_station->call_sign, p_station->coord_lat, p_station->coord_lon, last_lat, last_lon); } moving = 0; } } } changed_pos = 0; if (moving == 1) { p_station->flag |= (ST_MOVING); // we have a moving station, process trails if (atoi(p_station->speed) < TRAIL_MAX_SPEED) // reject high speed data (undef gives 0) { // we now may already have the 2nd position, so store the old one first if (debug_level & 256) { fprintf(stderr,"Station %s valid speed %s\n", p_station->call_sign, p_station->speed); } if (p_station->newest_trackpoint == NULL) { if (debug_level & 256) { fprintf(stderr,"Station %s no trail history.\n", p_station->call_sign); } if (position_defined(last_lat,last_lon,1)) // ignore undefined and 0N/0E { if (debug_level & 256) { fprintf(stderr,"Storing old position for %s\n", p_station->call_sign); } (void)store_trail_point(p_station, last_lon, last_lat, last_stn_sec, last_alt, last_speed, last_course, last_flag); } } //if ( p_station->coord_lon != last_lon // || p_station->coord_lat != last_lat ) { // we don't store redundant points (may change this // later ?) // // There are often echoes delayed 15 minutes // or so it looks ugly on the trail, so I // want to discard them This also discards // immediate echoes. Duplicates back in time // up to TRAIL_ECHO_TIME minutes are // discarded. // if (!is_trailpoint_echo(p_station)) { (void)store_trail_point(p_station, p_station->coord_lon, p_station->coord_lat, p_station->sec_heard, p_station->altitude, p_station->speed, p_station->course, p_station->flag); changed_pos = 1; // Check whether it's a locally-owned object/item if (object_is_mine) { // Update time, change position in // time-sorted list to change // expiration time. move_station_time(p_station,p_time); // Give it a new timestamp p_station->sec_heard = curr_sec; //fprintf(stderr,"Updating last heard time\n"); } } else if (debug_level & 256) { fprintf(stderr,"Trailpoint echo detected for %s\n", p_station->call_sign); } } else { if (debug_level & 256 || debug_level & 1) { fprintf(stderr,"Speed over %d mph\n",TRAIL_MAX_SPEED); } } if (track_station_on == 1) // maybe we are tracking a station { track_station(da,tracking_station_call,p_station); } } // moving... // now do the drawing to the screen ok_to_display = !altnet || is_altnet(p_station); // Optimization step, needed twice below. screen_update = 0; if (changed_pos == 1 && Display_.trail && ((p_station->flag & ST_INVIEW) != 0)) { if (ok_to_display) { if (debug_level & 256) { fprintf(stderr,"Adding Solid Trail for %s\n", p_station->call_sign); } draw_trail(da,p_station,1); // update trail screen_update = 1; } else if (debug_level & 256) { fprintf(stderr,"Skipped trail for %s (altnet)\n", p_station->call_sign); } } if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { if (changed_pos == 1 || !position_defined(last_lat,last_lon,0)) { if (ok_to_display) { display_station(da,p_station,1);// update symbol screen_update = 1; } } } } // defined position } if (screen_update) { if (p_station->data_via == 'T') // Data from local TNC { //WE7U // or data_via == 'I' and last_port_heard == AGWPE interface redraw_on_new_data = 2; // Update all symbols NOW! } else if (p_station->data_via == 'F') // If data from file { redraw_on_new_data = 1; // Update each 2 secs } // else if (scale_y > 2048) { // Wider area of world else { redraw_on_new_data = 0; // Update each 60 secs } } // announce stations in the status line // if (!is_my_call(p_station->call_sign,1) // Check SSID as well // && !is_my_call(p_station->origin,1) // Check SSID as well if (!is_my_station(p_station) && !is_my_object_item(p_station) // Check SSID as well && !wait_to_redraw) { if (new_station) { if (p_station->origin[0] == '\0') // new station { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA001"),p_station->call_sign); } else // new object { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA000"),p_station->call_sign); } } else // updated data { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA002"),p_station->call_sign); } statusline(station_id,0); } // announce new station with sound file or speech synthesis if (new_station && !wait_to_redraw) // && !is_my_call(p_station->call_sign,1) // ??? { if (sound_play_new_station) { play_sound(sound_command,sound_new_station); } #ifdef HAVE_FESTIVAL if (festival_speak_new_station) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); xastir_snprintf(station_id, sizeof(station_id), "%s, %s", langcode("SPCHSTR010"), speech_callsign); SayText(station_id); } #endif // HAVE_FESTIVAL } // check for range and DX // if (found_pos && !is_my_call(p_station->call_sign,1)) { // Check SSID also if (found_pos && !is_my_station(p_station)) // Check SSID also { // if station has a position with the data /* Check Audio Alarms based on incoming packet */ /* FG don't care if this is on screen or off get position */ l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,temp_data,sizeof(temp_data)); // Convert to whatever measurement value we're currently using distance = value * cvt_kn2len; /* check ranges */ if ((distance > atof(prox_min)) && (distance < atof(prox_max))) { //fprintf(stderr,"Station within proximity circle, creating waypoint\n"); create_garmin_waypoint(p_station->coord_lat, p_station->coord_lon, p_station->call_sign); if (sound_play_prox_message) { xastir_snprintf(station_id, sizeof(station_id), "%s < %.3f %s",p_station->call_sign, distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005")); statusline(station_id,0); play_sound(sound_command,sound_prox_message); /*fprintf(stderr,"%s> PROX distance %f\n",p_station->call_sign, distance);*/ } } #ifdef HAVE_FESTIVAL if ((distance > atof(prox_min)) && (distance < atof(prox_max)) && festival_speak_proximity_alert) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); if (english_units) { if (distance < 1.0) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance * 1760), langcode("SPCHSTR004")); // say it in yards else if ((int)((distance * 10) + 0.5) % 10) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR006"), speech_callsign, distance, langcode("SPCHSTR003")); // say it in miles with one decimal else xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance + 0.5), langcode("SPCHSTR003")); // say it in miles with no decimal } else { if (distance < 1.0) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance * 1000), langcode("SPCHSTR002")); // say it in meters else if ((int)((distance * 10) + 0.5) % 10) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR006"), speech_callsign, distance, langcode("SPCHSTR001")); // say it in kilometers with one decimal else xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance + 0.5), langcode("SPCHSTR001")); // say it in kilometers with no decimal } SayText(station_id); } #endif // HAVE_FESTIVAL /* FG really should check the path before we do this and add setup for these ranges */ if (sound_play_band_open_message && from == DATA_VIA_TNC && !(p_station->flag & ST_3RD_PT) && (distance > atof(bando_min)) && (distance < atof(bando_max))) { xastir_snprintf(station_id, sizeof(station_id), "%s %s %.1f %s",p_station->call_sign, langcode("UMBNDO0001"), distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005")); statusline(station_id,0); play_sound(sound_command,sound_band_open_message); /*fprintf(stderr,"%s> BO distance %f\n",p_station->call_sign, distance);*/ } #ifdef HAVE_FESTIVAL if (festival_speak_band_opening && from == DATA_VIA_TNC && !(p_station->flag & ST_3RD_PT) && (distance > atof(bando_min)) && (distance < atof(bando_max))) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR011"), speech_callsign, distance, english_units?langcode("SPCHSTR003"):langcode("SPCHSTR001")); SayText(station_id); } #endif // HAVE_FESTIVAL } // end found_pos #ifdef HAVE_DB // Clumsy way of doing things - needs a more elegant approach // iterate through interfaces if (p_station->data_via != DATA_VIA_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"Trying to store station %s to database interfaces.\n",p_station->call_sign); } for (ii=0; ii 0 && connections[ii].type < 4) { if (debug_level & 4096) { fprintf(stderr,"type=[%d]\n",connections[ii].type); } if (port_data[ii].status == DEVICE_UP) { if (connections[ii].descriptor->device_type==DEVICE_SQL_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"Trying interface %d\n",ii); } // if interface is a sql server interface // write station data to sql database ok = storeStationSimpleToGisDb(&connections[ii], p_station); if (ok==1) { if (debug_level & 4096) { fprintf(stderr,"Stored station %s to database interface %d.\n",p_station->call_sign,ii); } } else { pingConnection(&connections[ii]); } } } } } } } #endif /* HAVE_DB */ } // valid data into database return(ok); } // End of data_add() function // Code to compute SmartBeaconing(tm) rates. // // SmartBeaconing(tm) was invented by Steve Bragg (KA9MVA) and Tony Arnerich // (KD7TA). Its main goal is to change the beacon rate based on speed // and cornering. It does speed-variant corner pegging and // speed-variant posit rate. // Some tweaks have been added to the generic SmartBeaconing(tm) algorithm, // but are current labeled as experimental and commented out: 1) We do // a posit as soon as we first cross below the sb_low_speed_limit, and // 2) We do a posit as soon as we cross above the sb_low_speed_limit if // we haven't done a posit for sb_turn_time seconds. These tweaks are // intended to help show that the mobile station has stopped (so that // dead-reckoning doesn't keep it moving across the map on other // people's displays) and to more quickly show that the station is // moving again (for the case where they're in stop-and-go traffic // perhaps). // // It's possible that these new tweaks won't work well for the case // where a station is traveling near the speed of sb_low_speed_limit. // In this case they'll generate a posit each time they go below it and // every time they go above it if they haven't done a posit in // sb_turn_time seconds. This could result in a lot of posits very // quickly. We may need to add yet another limit just above the // sb_low_speed_limit for hysteresis, and not posit until we cross above // that new limit. // // Several special SmartBeaconing(tm) parameters come into play here: // // sb_turn_min Minimum degrees at which corner pegging will // occur. The next parameter affects this for // lower speeds. // // sb_turn_slope Fudget factor for making turns less sensitive at // lower speeds. No real units on this one. // It ends up being non-linear over the speed // range the way the original SmartBeaconing(tm) // algorithm works. // // sb_turn_time Dead-time before/after a corner peg beacon. // Units are in seconds. // // sb_posit_fast Fast posit rate, used if >= sb_high_speed_limit. // Units are in seconds. // // sb_posit_slow Slow posit rate, used if <= sb_low_speed_limit. // Units are in minutes. // // sb_low_speed_limit Low speed limit, units are in Mph. // // sb_high_speed_limit High speed limit, units are in Mph. // // // Input: Course in degrees // Speed in knots // // Output: May force beacons by setting posit_next_time to various // values. // // Modify: sb_POSIT_rate // sb_current_heading // sb_last_heading // posit_next_time // // // With the defaults compiled into the code, here are the // turn_thresholds for a few speeds: // // Example: sb_turn_min = 20 // sb_turn_slope = 25 // sb_high_speed_limit = 60 // // > 60mph 20 degrees // 50mph 25 degrees // 40mph 26 degrees // 30mph 28 degrees // 20mph 33 degrees // 10mph 45 degrees // 3mph 103 degrees (we limit it to 80 now) // 2mph 145 degrees (we limit it to 80 now) // // I added a max threshold of 80 degrees into the code. 145 degrees // is unreasonable to expect except for perhaps switchback or 'U' // turns. // // It'd probably be better to do a linear interpolation of // turn_threshold based on min/max speed and min/max turns. That's // not how the SmartBeaconing(tm) algorithm coders implemented it in // the HamHud though. // void compute_smart_beacon(char *current_course, char *current_speed) { int course; int speed; int turn_threshold; time_t secs_since_beacon; int heading_change_since_beacon; int beacon_now = 0; int curr_sec = sec_now(); // Don't compute SmartBeaconing(tm) parameters or force any beacons // if we're not in that mode! if (!smart_beaconing) { return; } // Convert from knots to mph/kph (whichever is selected) speed = (int)(atof(current_speed) * cvt_kn2len + 0.5); // Poor man's rounding course = atoi(current_course); secs_since_beacon = curr_sec - posit_last_time; // Check for the low speed threshold, set to slow posit rate if // we're going slow. if (speed <= sb_low_speed_limit) { //fprintf(stderr,"Slow speed\n"); // EXPERIMENTAL!!! //////////////////////////////////////////////////////////////////// // Check to see if we're just crossing the threshold, if so, // beacon. This keeps dead-reckoning working properly on // other people's displays. Be careful for speeds near this // threshold though. We really need a slow-speed rate and a // stop rate, with some distance between them, in order to // have some hysteresis for these posits. // if (sb_POSIT_rate != (sb_posit_slow * 60) ) { // Previous rate was _not_ the slow rate // beacon_now++; // Force a posit right away // //fprintf(stderr,"Stopping, POSIT!\n"); // } //////////////////////////////////////////////////////////////////// // Set to slow posit rate sb_POSIT_rate = sb_posit_slow * 60; // Convert to seconds } else // We're moving faster than the low speed limit { // EXPERIMENTAL!!! //////////////////////////////////////////////////////////////////// // Check to see if we're just starting to move. Again, we // probably need yet-another-speed-limit here to provide // some hysteresis. // if ( (secs_since_beacon > sb_turn_time) // Haven't beaconed for a bit // && (sb_POSIT_rate == (sb_posit_slow * 60) ) ) { // Last rate was the slow rate // beacon_now++; // Force a posit right away // //fprintf(stderr,"Starting to move, POSIT!\n"); // } //////////////////////////////////////////////////////////////////// // Start with turn_min degrees as the threshold turn_threshold = sb_turn_min; // Adjust rate according to speed if (speed > sb_high_speed_limit) // We're above the high limit { sb_POSIT_rate = sb_posit_fast; //fprintf(stderr,"Setting fast rate\n"); } else // We're between the high/low limits. Set a between rate { sb_POSIT_rate = (sb_posit_fast * sb_high_speed_limit) / speed; //fprintf(stderr,"Setting medium rate\n"); // Adjust turn threshold according to speed turn_threshold += (int)( (sb_turn_slope * 10) / speed); } // Force a maximum turn threshold of 80 degrees (still too // high?) if (turn_threshold > 80) { turn_threshold = 80; } // Check to see if we've written anything into // sb_last_heading variable yet. If not, write the current // course into it. if (sb_last_heading == -1) { sb_last_heading = course; } // Corner-pegging. Note that we don't corner-peg if we're // below the low-speed threshold. heading_change_since_beacon = abs(course - sb_last_heading); if (heading_change_since_beacon > 180) { heading_change_since_beacon = 360 - heading_change_since_beacon; } //fprintf(stderr,"course change:%d\n",heading_change_since_beacon); if ( (heading_change_since_beacon > turn_threshold) && (secs_since_beacon > sb_turn_time) ) { beacon_now++; // Force a posit right away //fprintf(stderr,"Corner, POSIT!\tOld:%d\tNew:%d\tDifference:%d\tSpeed: %d\tTurn Threshold:%d\n", // sb_last_heading, // course, // heading_change_since_beacon, // speed, // turn_threshold); } // EXPERIMENTAL //////////////////////////////////////////////////////////////////// // If we haven't beaconed for a bit (3 * sb_turn_time?), and // just completed a turn, check to see if our heading has // stabilized yet. If so, beacon the latest heading. We'll // have to save another variable which says whether the last // beacon was caused by corner-pegging. The net effect is // that we'll get an extra posit coming out of a turn that // specifies our correct course and probably a more accurate // speed until the next posit. This should make // dead-reckoning work even better. if (0) { } //////////////////////////////////////////////////////////////////// } // Check to see whether we've sped up sufficiently for the // posit_next_time variable to be too far out. If so, shorten // that interval to match the current speed. if ( (posit_next_time - curr_sec) > sb_POSIT_rate) { posit_next_time = curr_sec + sb_POSIT_rate; } if (beacon_now) { posit_next_time = 0; // Force a posit right away } // Should we also check for a rate too fast for the current // speed? Probably not. It'll get modified at the next beacon // time, which will happen quickly. // Save course for use later. It gets put into sb_last_heading // in UpdateTime() if a beacon occurs. We then use it above to // determine the course deviation since the last time we // beaconed. sb_current_heading = course; } // Speed is in knots void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char UNUSED(speedu), char *alt, char *sats) { long pos_long_temp, pos_lat_temp; char temp_data[40]; // short term string storage char temp_lat[12]; char temp_long[12]; DataRow *p_station; DataRow *p_time; // Note that speed will be in knots 'cuz it was derived from a // GPRMC string without modification. // Recompute the SmartBeaconing(tm) parameters based on current/past // course & speed. Sending the speed in knots. //fprintf(stderr,"Speed: %s\n",speed); compute_smart_beacon(course, speed); p_station = NULL; if (!search_station_name(&p_station,my_callsign,1)) // find my data in the database { p_time = NULL; // add to end of time sorted list //fprintf(stderr,"my_station_gps_change()\n"); p_station = add_new_station(p_station,p_time,my_callsign); } p_station->flag |= ST_ACTIVE; p_station->data_via = 'L'; p_station->flag &= (~ST_3RD_PT); // clear "third party" flag p_station->record_type = NORMAL_APRS; // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen("local") + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,"local",strlen("local")); // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag |= ST_MSGCAP; // set "message capable" flag /* convert to long and weed out any odd data */ pos_long_temp = convert_lon_s2l(pos_long); pos_lat_temp = convert_lat_s2l(pos_lat); /* convert back to clean string for config data */ convert_lon_l2s(pos_long_temp, temp_data, sizeof(temp_data), CONVERT_HP_NORMAL); xastir_snprintf(temp_long, sizeof(temp_long), "%c%c%c%c%c.%c%c%c%c",temp_data[0],temp_data[1],temp_data[2], temp_data[4],temp_data[5], temp_data[7],temp_data[8], temp_data[9], temp_data[10]); convert_lat_l2s(pos_lat_temp, temp_data, sizeof(temp_data), CONVERT_HP_NORMAL); xastir_snprintf(temp_lat, sizeof(temp_lat), "%c%c%c%c.%c%c%c%c",temp_data[0],temp_data[1],temp_data[3],temp_data[4], temp_data[6], temp_data[7], temp_data[8],temp_data[9]); /* fill the data in */ // ??????????????? memcpy(my_lat, temp_lat, sizeof(my_lat)); my_lat[sizeof(my_lat)-1] = '\0'; // Terminate string memcpy(my_long, temp_long, sizeof(my_long)); my_long[sizeof(my_long)-1] = '\0'; // Terminate string p_station->coord_lat = convert_lat_s2l(my_lat); p_station->coord_lon = convert_lon_s2l(my_long); if ((p_station->coord_lon != pos_long_temp) || (p_station->coord_lat != pos_lat_temp)) { /* check to see if enough to change pos on screen */ if ((pos_long_temp>NW_corner_longitude) && (pos_long_tempNW_corner_latitude) && (pos_lat_tempcoord_lon+(scale_x/2))-pos_long_temp)/scale_x)>0 || (labs((p_station->coord_lat+(scale_y/2))-pos_lat_temp)/scale_y)>0) { //redraw_on_new_data = 1; // redraw next chance //redraw_on_new_data = 2; // better response? if (debug_level & 256) { fprintf(stderr,"Redraw on new gps data \n"); } statusline(langcode("BBARSTA038"),0); } else if (debug_level & 256) { fprintf(stderr,"New Position same pixel as old.\n"); } } else if (debug_level & 256) { fprintf(stderr,"New Position is off edge of screen.\n"); } } else if (debug_level & 256) { fprintf(stderr,"New position is off side of screen.\n"); } } p_station->coord_lat = pos_lat_temp; // DK7IN: we have it already !?? p_station->coord_lon = pos_long_temp; curr_sec = sec_now(); my_last_altitude_time = curr_sec; xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%s", speed); // is speed always in knots, otherwise we need a conversion! xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", course); xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%s", alt); // altu; unit should always be meters ???? if(debug_level & 256) fprintf(stderr,"GPS MY_LAT <%s> MY_LONG <%s> MY_ALT <%s>\n", my_lat, my_long, alt); /* get my last altitude meters to feet */ my_last_altitude=(long)(atof(alt)*3.28084); /* get my last course in deg */ my_last_course=atoi(course); /* get my last speed in knots */ my_last_speed = atoi(speed); xastir_snprintf(p_station->sats_visible, sizeof(p_station->sats_visible), "%s", sats); // Update "heard" time for our new position p_station->sec_heard = curr_sec; //if ( p_station->coord_lon != last_lon // || p_station->coord_lat != last_lat ) { // we don't store redundant points (may change this later ?) // There are often echoes delayed 15 minutes or so it looks ugly // on the trail, so I want to discard them This also discards // immediate echoes. Duplicates back in time up to // TRAIL_ECHO_TIME minutes are discarded. // if (!is_trailpoint_echo(p_station)) { (void)store_trail_point(p_station, p_station->coord_lon, p_station->coord_lat, curr_sec, p_station->altitude, p_station->speed, p_station->course, p_station->flag); } if (debug_level & 256) { fprintf(stderr,"Adding Solid Trail for %s\n", p_station->call_sign); } draw_trail(da,p_station,1); // update trail display_station(da,p_station,1); // update symbol if (track_station_on == 1) // maybe we are tracking ourselves? { track_station(da,tracking_station_call,p_station); } // We parsed a good GPS string, so allow beaconing to proceed // normally for a while. my_position_valid = 3; //fprintf(stderr,"Valid GPS input: my_position_valid = 3\n"); //redraw_on_new_data = 1; // redraw next chance redraw_on_new_data = 2; // Immediate update of symbols/tracks } void my_station_add(char *my_callsign, char my_group, char my_symbol, char *my_long, char *my_lat, char *my_phg, char *my_comment, char my_amb) { DataRow *p_station; DataRow *p_time; char temp_data[40]; // short term string storage char *strp; p_station = NULL; if (!search_station_name(&p_station,my_callsign,1)) // find call { p_time = NULL; // add to end of time sorted list //fprintf(stderr,"my_station_add()\n"); p_station = add_new_station(p_station,p_time,my_callsign); } p_station->flag |= ST_ACTIVE; p_station->flag |= ST_MYSTATION; p_station->data_via = 'L'; p_station->flag &= (~ST_3RD_PT); // clear "third party" flag p_station->record_type = NORMAL_APRS; if (transmit_compressed_posit) { // Compressed posit p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } else { // Standard APRS posit p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen("local") + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,"local",strlen("local")); // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag |= ST_MSGCAP; // set "message capable" flag /* Symbol overlay */ if(my_group != '/' && my_group != '\\') { // Found an overlay character. Check it. if ( (my_group >= '0' && my_group <= '9') || (my_group >= 'A' && my_group <= 'Z') ) { // Overlay character is good p_station->aprs_symbol.aprs_type = '\\'; p_station->aprs_symbol.special_overlay = my_group; } else { // Found a bad overlay character p_station->aprs_symbol.aprs_type = my_group; p_station->aprs_symbol.special_overlay = '\0'; } } else // Normal symbol, no overlay { p_station->aprs_symbol.aprs_type = my_group; p_station->aprs_symbol.special_overlay = '\0'; } p_station->aprs_symbol.aprs_symbol = my_symbol; p_station->pos_amb = my_amb; xastir_snprintf(temp_data, sizeof(temp_data), "%s", my_lat); //fprintf(stderr," my_lat:%s\n",temp_data); temp_data[9] = '\0'; strp = &temp_data[20]; xastir_snprintf(strp, // sizeof(strp), // No good, as strp is a pointer (int)(sizeof(temp_data) / 2), "%s", my_long); strp[10] = '\0'; //fprintf(stderr,"my_long:%s\n",my_long); //fprintf(stderr,"my_long:%s\n",strp); switch (my_amb) { case 1: // 1/10th minute temp_data[6] = strp[7] = '5'; break; case 2: // 1 minute temp_data[5] = strp[6] = '5'; temp_data[6] = '0'; strp[7] = '0'; break; case 3: // 10 minutes temp_data[3] = strp[4] = '5'; temp_data[5] = temp_data[6] = '0'; strp[6] = strp[7] = '0'; break; case 4: // 1 degree temp_data[2] = strp[3] = '3'; temp_data[3] = temp_data[5] = temp_data[6] = '0'; strp[4] = strp[6] = strp[7] = '0'; break; case 0: default: break; } p_station->coord_lat = convert_lat_s2l(temp_data); p_station->coord_lon = convert_lon_s2l(strp); if (position_on_extd_screen(p_station->coord_lat,p_station->coord_lon)) { p_station->flag |= (ST_INVIEW); // set "In View" flag } else { p_station->flag &= (~ST_INVIEW); // clear "In View" flag } substr(p_station->power_gain,my_phg,7); add_comment(p_station,my_comment); my_last_course = 0; // set my last course in deg to zero redo_list = (int)TRUE; // update active station lists } // Write the text from the packet_data_string out to the dialog if // the dialog exists. The user can contract/expand the dialog and // always have it filled with the most current data out of the // string. // void display_packet_data(void) { if( (Display_data_dialog != NULL) && (redraw_on_new_packet_data !=0)) { int pos; int last_char; int i; // Find out the last character position in the dialog text // area. last_char = XmTextGetLastPosition(Display_data_text); //fprintf(stderr,"In display_packet_data: first_line=%d,next_line=%d,ncharsdel=%d,nlinesadd=%d\n",first_line,next_line,ncharsdel,nlinesadd); if (first_line != -1) // there is data in the array { if (last_char == 0 || ncharsdel>=last_char) { //fprintf(stderr," Starting from clean slate...\n"); // but there is no text in the dialog or more chars to delete than // there actually are in the dialog // Clear the dialog just in case: XmTextReplace(Display_data_text,0,last_char,""); // display all the data in the ring for (i=first_line; i != next_line; i=(i+1)%MAX_PACKET_DATA_DISPLAY) { XmTextReplace(Display_data_text,last_char,last_char, packet_data_string[i]); last_char=XmTextGetLastPosition(Display_data_text); pos=last_char; XtVaSetValues(Display_data_text,XmNcursorPosition, pos,NULL); } // Now clear counters so they're always the number of lines to // add or characters to delete *since last display* nlinesadd=0; ncharsdel=0; } else // there is stuff left over after we delete old stuff { if (ncharsdel) // we have something to delete off the top { //fprintf(stderr," Must delete %d characters\n",ncharsdel); XmTextReplace(Display_data_text,0,ncharsdel,""); ncharsdel=0; } if (nlinesadd) // and there's new stuff to add at end { //fprintf(stderr," Must add %d lines\n",nlinesadd); last_char=XmTextGetLastPosition(Display_data_text); for (i=(next_line+MAX_PACKET_DATA_DISPLAY -nlinesadd)%MAX_PACKET_DATA_DISPLAY; i != next_line; i=(i+1)%MAX_PACKET_DATA_DISPLAY) { //fprintf(stderr," Adding data from line %d\n",i); XmTextReplace(Display_data_text,last_char,last_char, packet_data_string[i]); last_char=XmTextGetLastPosition(Display_data_text); pos=last_char; XtVaSetValues(Display_data_text,XmNcursorPosition, pos,NULL); } nlinesadd=0; } } } } redraw_on_new_packet_data=0; } // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // data_port == -1 for x_spider port, normal interface number // otherwise. -99 should give a "**" display, meaning all ports. // void packet_data_add(char *from, char *line, int data_port) { int offset; char prefix[3] = ""; int local_tnc_interface = 0; int network_interface = 0; if (data_port == -1) // x_spider port (server port) { xastir_snprintf(prefix,sizeof(prefix),"sp"); } else if (data_port == -99) // All ports, used for transmitting { xastir_snprintf(prefix,sizeof(prefix),"**"); } else { xastir_snprintf(prefix,sizeof(prefix),"%2d",data_port); } offset=0; if (line[0]==(char)3) { offset=1; } // Check whether local or network interface if (is_local_interface(data_port) || data_port == -99) { local_tnc_interface++; } if (is_network_interface(data_port) || data_port == -1 || data_port == -99) { network_interface++; } // Compare Display_packet_data_type against the port type // associated with data_port to determine whether or not to // display it. // switch (Display_packet_data_type) { case 2: // Display NET data only if (!network_interface) { return; // Don't display it } break; case 1: // Display TNC data only if (!local_tnc_interface) { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // fprintf(stderr,"display:%d, port:%d\n", // Display_packet_data_type, // data_port); // Check the Capabilities toggle to see if we only want to show // Station Capability packets if (show_only_station_capabilities) { if (!strstr(line, ":<") // Not a capabilities response && !( strstr(line, my_callsign) && strstr(line, "?IGATE?") ) ) { // Not a capabilities response and not my ?IGATE? // request, don't display the packet. return; } } // Check the "Mine Only" toggle to see if we only want to show // our own packets if (Display_packet_data_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(line, short_call)) { return; } } redraw_on_new_packet_data++; // Now save the packet in the history: xastir_snprintf(packet_data_string[next_line],MAX_LINE_SIZE,"%s:%s-> %s\n", prefix,from,line+offset); next_line = (next_line+1)%MAX_PACKET_DATA_DISPLAY; nlinesadd++; if (first_line == -1) { first_line = 0; } else if (first_line == next_line) { ncharsdel += strlen(packet_data_string[first_line]); first_line = (first_line + 1) %MAX_PACKET_DATA_DISPLAY; } } /* * Decode Mic-E encoded data */ int decode_Mic_E(char *call_sign,char *path,char *info,char from,int port,int third_party) { int ii; int offset; unsigned char s_b1; unsigned char s_b2; unsigned char s_b3; unsigned char s_b4; unsigned char s_b5; unsigned char s_b6; // unsigned char s_b7; int north,west,long_offset; int d,m,h; char temp[MAX_LINE_SIZE+1]; // Note: Must be big in case we get long concatenated packets char new_info[MAX_LINE_SIZE+1]; // Note: Must be big in case we get long concatenated packets int course; int speed; int msg1,msg2,msg3,msg; int info_size; long alt; int msgtyp; char rig_type[10]; int ok; // MIC-E Data Format [APRS Reference, chapter 10] // todo: error check // drop wrong positions from receive errors... // drop 0N/0E position (p.25) /* First 7 bytes of info[] contains the APRS data type ID, */ /* longitude, speed, course. */ /* The 6-byte destination field of path[] contains latitude, */ /* N/S bit, E/W bit, longitude offset, message code. */ /* MIC-E Destination Field Format: ------------------------------- Ar1DDDD0 Br1DDDD0 Cr1MMMM0 Nr1MMMM0 Lr1HHHH0 Wr1HHHH0 CrrSSID0 D = Latitude Degrees. M = Latitude Minutes. H = Latitude Hundredths of Minutes. ABC = Message bits, complemented. N = N/S latitude bit (N=1). W = E/W longitude bit (W=1). L = 100's of longitude degrees (L=1 means add 100 degrees to longitude in the Info field). C = Command/Response flag (see AX.25 specification). r = reserved for future use (currently 0). */ /**************************************************************************** * I still don't handle: * * Custom message bits * * SSID special routing * * Beta versions of the MIC-E (which use a slightly different format). * * * * DK7IN : lat/long with custom msg works, altitude/course/speed works * *****************************************************************************/ if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: FOUND MIC-E\n"); } // Note that the first MIC-E character was not passed to us, so we're // starting just past it. // Check for valid symbol table character. Should be '/' or '\' // or 0-9, A-Z. // if ( info[7] == '/' // Primary table || info[7] == '\\' // Alternate table || (info[7] >= '0' && info[7] <= '9') // Overlay char || (info[7] >= 'A' && info[7] <= 'Z') ) // Overlay char { // We're good, keep going } else // Symbol table or overlay char incorrect { if (info[6] == '/' || info[6] == '\\') // Found it back one char in string { // Don't print out the full info string here because it // can contain unprintable characters. In fact, we // should check the chars we do print out to make sure // they're printable, else print a space char. if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: Symbol table (%c), symbol (%c) swapped or corrupted packet? Call=%s, Path=%s\n", ((info[7] > 0x1f) && (info[7] < 0x7f)) ? info[7] : ' ', ((info[6] > 0x1f) && (info[6] < 0x7f)) ? info[6] : ' ', call_sign, path); fprintf(stderr,"Returned from data_add, invalid symbol table character: %c\n",info[7]); } } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for valid symbol. Should be between '!' and '~' only. if (info[6] < '!' || info[6] > '~') { if (debug_level & 1) { fprintf(stderr,"Returned from data_add, invalid symbol\n"); } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for minimum MIC-E size. if (strlen(info) < 8) { if (debug_level & 1) { fprintf(stderr,"Returned from data_add, packet too short\n"); } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for 8-bit characters in the first eight slots. Not // allowed per Mic-E chapter of the spec. for (ii = 0; ii < 8; ii++) { if ((unsigned char)info[ii] > 0x7f) { // 8-bit data was found in the lat/long/course/speed // portion. Bad packet. Drop it. //fprintf(stderr, "%s: 8-bits found in Mic-E packet initial portion. Dropping it.\n", call_sign); return(1); } } // Check whether we have more data. If flag character is 0x1d // (8-bit telemetry flag) then don't do the 8-bit check below. if (strlen(info) > 8) { // Check for the 8-bit telemetry flag if ((unsigned char)info[8] == 0x1d) { // 8-bit telemetry found, skip the check loop below } else // 8-bit telemetry flag was not found. Check that { // we only have 7-bit characters through the rest of // the packet. for (ii = 8; ii < (int)strlen(info); ii++) { if ((unsigned char)info[ii] > 0x7f) { // 8-bit data was found. Bad packet. Drop it. //fprintf(stderr, "%s: 8-bits found in Mic-E packet final portion (not 8-bit telemetry). Dropping it.\n", call_sign); return(1); } } } } //fprintf(stderr,"Path1:%s\n",path); msg1 = (int)( ((unsigned char)path[0] & 0x40) >>4 ); msg2 = (int)( ((unsigned char)path[1] & 0x40) >>5 ); msg3 = (int)( ((unsigned char)path[2] & 0x40) >>6 ); msg = msg1 | msg2 | msg3; // We now have the complemented message number in one variable msg = msg ^ 0x07; // And this is now the normal message number msgtyp = 0; // DK7IN: Std message, I have to add custom msg decoding //fprintf(stderr,"Msg: %d\n",msg); /* Snag the latitude from the destination field, Assume TAPR-2 */ /* DK7IN: latitude now works with custom message */ s_b1 = (unsigned char)( (path[0] & 0x0f) + (char)0x2f ); //fprintf(stderr,"path0:%c\ts_b1:%c\n",path[0],s_b1); if (path[0] & 0x10) // A-J { s_b1 += (unsigned char)1; } if (s_b1 > (unsigned char)0x39) // K,L,Z { s_b1 = (unsigned char)0x20; } //fprintf(stderr,"s_b1:%c\n",s_b1); s_b2 = (unsigned char)( (path[1] & 0x0f) + (char)0x2f ); //fprintf(stderr,"path1:%c\ts_b2:%c\n",path[1],s_b2); if (path[1] & 0x10) // A-J { s_b2 += (unsigned char)1; } if (s_b2 > (unsigned char)0x39) // K,L,Z { s_b2 = (unsigned char)0x20; } //fprintf(stderr,"s_b2:%c\n",s_b2); s_b3 = (unsigned char)( (path[2] & (char)0x0f) + (char)0x2f ); //fprintf(stderr,"path2:%c\ts_b3:%c\n",path[2],s_b3); if (path[2] & 0x10) // A-J { s_b3 += (unsigned char)1; } if (s_b3 > (unsigned char)0x39) // K,L,Z { s_b3 = (unsigned char)0x20; } //fprintf(stderr,"s_b3:%c\n",s_b3); s_b4 = (unsigned char)( (path[3] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path3:%c\ts_b4:%c\n",path[3],s_b4); if (s_b4 > (unsigned char)0x39) // L,Z { s_b4 = (unsigned char)0x20; } //fprintf(stderr,"s_b4:%c\n",s_b4); s_b5 = (unsigned char)( (path[4] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path4:%c\ts_b5:%c\n",path[4],s_b5); if (s_b5 > (unsigned char)0x39) // L,Z { s_b5 = (unsigned char)0x20; } //fprintf(stderr,"s_b5:%c\n",s_b5); s_b6 = (unsigned char)( (path[5] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path5:%c\ts_b6:%c\n",path[5],s_b6); if (s_b6 > (unsigned char)0x39) // L,Z { s_b6 = (unsigned char)0x20; } //fprintf(stderr,"s_b6:%c\n",s_b6); // s_b7 = (unsigned char)path[6]; // SSID, not used here //fprintf(stderr,"path6:%c\ts_b7:%c\n",path[6],s_b7); //fprintf(stderr,"\n"); // Special tests for 'L' due to position ambiguity deviances in // the APRS spec table. 'L' has the 0x40 bit set, but they // chose in the spec to have that represent position ambiguity // _without_ the North/West/Long Offset bit being set. Yuk! // Please also note that the tapr.org Mic-E document (not the // APRS spec) has the state of the bit wrong in columns 2 and 3 // of their table. Reverse them. if (path[3] == 'L') { north = 0; } else { north = (int)((path[3] & 0x40) == (char)0x40); // N/S Lat Indicator } if (path[4] == 'L') { long_offset = 0; } else { long_offset = (int)((path[4] & 0x40) == (char)0x40); // Longitude Offset } if (path[5] == 'L') { west = 0; } else { west = (int)((path[5] & 0x40) == (char)0x40); // W/E Long Indicator } //fprintf(stderr,"north:%c->%d\tlat:%c->%d\twest:%c->%d\n",path[3],north,path[4],long_offset,path[5],west); /* Put the latitude string into the temp variable */ xastir_snprintf(temp, sizeof(temp), "%c%c%c%c.%c%c%c%c",s_b1,s_b2,s_b3,s_b4,s_b5,s_b6, (north ? 'N': 'S'), info[7]); // info[7] = symbol table /* Compute degrees longitude */ xastir_snprintf(new_info, sizeof(new_info), "%s", temp); d = (int) info[0]-28; if (long_offset) { d += 100; } if ((180<=d)&&(d<=189)) // ?? { d -= 80; } if ((190<=d)&&(d<=199)) // ?? { d -= 190; } /* Compute minutes longitude */ m = (int) info[1]-28; if (m>=60) { m -= 60; } /* Compute hundredths of minutes longitude */ h = (int) info[2]-28; /* Add the longitude string into the temp variable */ xastir_snprintf(temp, sizeof(temp), "%03d%02d.%02d%c%c",d,m,h,(west ? 'W': 'E'), info[6]); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); /* Compute speed in knots */ speed = (int)( ( info[3] - (char)28 ) * (char)10 ); speed += ( (int)( (info[4] - (char)28) / (char)10) ); if (speed >= 800) { speed -= 800; // in knots } /* Compute course */ course = (int)( ( ( (info[4] - (char)28) % 10) * (char)100) + (info[5] - (char)28) ); if (course >= 400) { course -= 400; } /* ??? fprintf(stderr,"info[4]-28 mod 10 - 4 = %d\n",( ( (int)info[4]) - 28) % 10 - 4); fprintf(stderr,"info[5]-28 = %d\n", ( (int)info[5]) - 28 ); */ xastir_snprintf(temp, sizeof(temp), "%03d/%03d",course,speed); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); offset = 8; // start of rest of info /* search for rig type in Mic-E data */ rig_type[0] = '\0'; if (info[offset] != '\0' && (info[offset] == '>' || info[offset] == ']')) { /* detected type code: > TH-D7 ] TM-D700 */ if (info[offset] == '>') xastir_snprintf(rig_type, sizeof(rig_type), " TH-D7"); else xastir_snprintf(rig_type, sizeof(rig_type), " TM-D700"); offset++; } info_size = (int)strlen(info); /* search for compressed altitude in Mic-E data */ // { if (info_size >= offset+4 && info[offset+3] == '}') // { { /* detected altitude ___} */ alt = ((((long)info[offset] - (long)33) * (long)91 +(long)info[offset+1] - (long)33) * (long)91 + (long)info[offset+2] - (long)33) - 10000; // altitude in meters alt /= 0.3048; // altitude in feet, as in normal APRS //32808 is -10000 meters, or 10 km (deepest ocean), which is as low as a MIC-E //packet may go. Upper limit is mostly a guess. if ( (alt > 500000) || (alt < -32809) ) // Altitude is whacko. Skip it. { if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: Altitude is whacko: %ld feet, skipping altitude...\n", alt); } offset += 4; } else // Altitude is ok { xastir_snprintf(temp, sizeof(temp), " /A=%06ld",alt); offset += 4; strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } } /* start of comment */ if (strlen(rig_type) > 0) { xastir_snprintf(temp, sizeof(temp), "%s",rig_type); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } strncat(new_info, " Mic-E ", sizeof(new_info) - 1 - strlen(new_info)); if (msgtyp == 0) { switch (msg) { case 1: strncat(new_info, "Enroute", sizeof(new_info) - 1 - strlen(new_info)); break; case 2: strncat(new_info, "In Service", sizeof(new_info) - 1 - strlen(new_info)); break; case 3: strncat(new_info, "Returning", sizeof(new_info) - 1 - strlen(new_info)); break; case 4: strncat(new_info, "Committed", sizeof(new_info) - 1 - strlen(new_info)); break; case 5: strncat(new_info, "Special", sizeof(new_info) - 1 - strlen(new_info)); break; case 6: strncat(new_info, "Priority", sizeof(new_info) - 1 - strlen(new_info)); break; case 7: strncat(new_info, "Emergency", sizeof(new_info) - 1 - strlen(new_info)); // Do a popup to alert the operator to this // condition. Make sure we haven't popped up an // emergency message for this station within the // last 30 minutes. If we pop these up constantly // it gets quite annoying. // EMERGENCY if (emergency_distance_check) { double distance; char course_deg[5]; distance = distance_from_my_station(call_sign, course_deg); // Because of the distance check we have to receive a valid position // from the station BEFORE we process the EMERGENCY portion and // check distance, doing the popups. We need to figure out a way to // throw the packet back into the queue if it was an emergency // packet so that we process these packets twice each. That way // only one packet from the emergency station is required to // generate the popups. if (distance == 0.0) { process_emergency_packet_again++; } // Check whether the station is near enough to // us to require that we alert on the packet. // // This may be slightly controversial, but if we // don't know WHERE a station is, we can't help // much in an emergency, can we? The // zero-distance check helps in the case where // we haven't yet or never get a position packet // for a station. As soon as we have a position // and it is within a reasonable range, we do // our emergency popups. // if ( distance != 0.0 && (float)distance <= emergency_range ) { if ( (strncmp(call_sign, last_emergency_callsign, strlen(call_sign)) != 0) || ((last_emergency_time + 60*30) < sec_now()) ) { char temp[50]; char temp2[150]; char temp3[300]; char timestring[101]; // Callsign is different or enough time has // passed last_emergency_time = sec_now(); xastir_snprintf(last_emergency_callsign, sizeof(last_emergency_callsign), "%s", call_sign); // Bring up the Find Station dialog so that the // operator can go to the location quickly xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", call_sign); Locate_station( (Widget)NULL, (XtPointer)NULL, (XtPointer)1 ); // Bring up another dialog with the // callsign plus distance/bearing to the // station. xastir_snprintf(temp, sizeof(temp), "%0.1f", distance); xastir_snprintf(temp2, sizeof(temp2), langcode("WPUPSTI022"), temp, course_deg); get_timestamp(timestring); xastir_snprintf(temp3, sizeof(temp3), "%s %s", timestring, temp2); popup_message_always(call_sign, temp3); } } } break; default: strncat(new_info, "Off Duty", sizeof(new_info) - 1 - strlen(new_info)); } } else { xastir_snprintf(temp, sizeof(temp), "Custom%d",msg); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } if (info[offset] != '\0') { /* Append the rest of the message to the expanded MIC-E message */ for (ii=offset; ii278/007 /A=-05685 TM-D700 Mic-E Off Duty N0EST , // from: 70, // port: -1, // NULL, // third_party: 0 } // We don't transmit Mic-E protocol from Xastir, so we know it's // not our station's packets or our object/item packets, // therefore the last two parameters here are both zero. // ok = data_add(APRS_MICE,call_sign,path,new_info,from,port,NULL,third_party, 0, 0); if (debug_level & 1) { fprintf(stderr,"Returned from data_add, end of function\n"); } return(ok); } // End of decode_Mic_E() /* * Directed Station Query (query to my station) [APRS Reference, chapter 15] */ int process_directed_query(char *call,char *path,char *message,char from) { DataRow *p_station; char from_call[MAX_CALLSIGN+1]; char temp[100]; int ok = 0; if (debug_level & 1) { fprintf(stderr,"process_directed_query: %s\n",message); } // Check for proper usage of the APRSD query if (!ok && strncmp(message,"APRSD",5) == 0 && from != 'F') // stations heard direct { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:Directs=",from_call); p_station = n_first; while (p_station != NULL) { if ((p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { if ( ((p_station->flag & ST_VIATNC) != 0) // test "via TNC" flag && ((p_station->flag & ST_DIRECT) != 0) // And "direct" flag && sec_now() < (p_station->direct_heard + st_direct_timeout) // Within the last hour // && !is_my_call(p_station->call_sign,1) ) { // and not me (checks SSID too) && !(is_my_station(p_station)) ) // and not me (checks SSID too) { if (strlen(temp)+strlen(p_station->call_sign) < 65) { strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); strncat(temp, p_station->call_sign, sizeof(temp) - 1 - strlen(temp)); } else { // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); xastir_snprintf(temp, sizeof(temp), ":%s:Directs=",from_call); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); strncat(temp, p_station->call_sign, sizeof(temp) - 1 - strlen(temp)); } } } p_station = p_station->n_next; } // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); ok = 1; } // Check for illegal case for the APRSD query if (!ok && strncasecmp(message,"APRSD",5) == 0 && from != 'F') // stations heard direct { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSH query if (!ok && strncmp(message,"APRSH",5)==0) { ok = 1; } // Check for illegal case for the APRSH query if (!ok && strncasecmp(message,"APRSH",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSM query if (!ok && strncmp(message,"APRSM",5)==0) { ok = 1; } // Check for illegal case for the APRSM query if (!ok && strncasecmp(message,"APRSM",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSO query if (!ok && strncmp(message,"APRSO",5)==0) { ok = 1; } // Check for illegal case for the APRSO query if (!ok && strncasecmp(message,"APRSO",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the APRSP query if (!ok && strncmp(message,"APRSP",5) == 0 && from != 'F') { transmit_now = 1; //send position ok = 1; } // Check for illegal case for the APRSP query if (!ok && strncasecmp(message,"APRSP",5) == 0 && from != 'F') { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSS query if (!ok && strncmp(message,"APRSS",5)==0) { ok = 1; } // Check for illegal case for the APRSS query if (!ok && strncasecmp(message,"APRSS",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the APRST/PING? queries if (!ok && (strncmp(message,"APRST",5)==0 || strncmp(message,"PING?",5)==0) && from != 'F') { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:PATH= %s>%s",from_call,call,path); // correct format ????? // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); ok = 1; } // Check for illegal case for the APRST/PING? queries if (!ok && (strncasecmp(message,"APRST",5)==0 || strncasecmp(message,"PING?",5)==0) && from != 'F') { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the VER query (either case?) if (!ok && strncasecmp("VER",message,3) == 0 && from != 'F') // not in Reference !??? { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:%s",from_call,VERSIONLABEL); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); if (debug_level & 1) { fprintf(stderr,"Sent to %s:%s\n",call,temp); } ok = 1; } return(ok); } /* * Station Capabilities, Queries and Responses [APRS Reference, chapter 15] */ // // According to Bob Bruninga we should wait a random time between 0 // and 120 seconds before responding to a general query. We use the // delayed-ack mechanism to add this randomness. // // NOTE: We may end up sending these to RF when the query came in // over the internet. We should check that. // int process_query( char *call_sign, char * UNUSED(path), char *message,char from,int port, int UNUSED(third_party) ) { char temp[100]; int ok = 0; float randomize; // Generate a random number between 0.0 and 1.0 randomize = rand() / (float)RAND_MAX; // Convert to between 0 and 120 seconds randomize = randomize * 120.0; //fprintf(stderr,"Randomize:%f\n", randomize); // Check for proper usage of the ?APRS? query // // NOTE: We need to add support in here for the radius circle as // listed in the spec for general queries. Right now we respond to // all queries, whether we're inside the circle or not. Spec says // this: // // ?Query?Lat,Long,Radius // 1 n 1 n 1 n 1 4 Bytes // // i.e. ?APRS? 34.02,-117.15,0200 // // Note leading space in latitude as its value is positive. // Lat/long are floating point degrees. N/E are positive, indicated // by a leading space. S/W are negative. Radius is in miles // expressed as a fixed 4-digit number in whole miles. All stations // inside the specified circle should respond with a position report // and a status report. // if (!ok && strncmp(message,"APRS?",5)==0) { // // Initiate a delayed transmit of our own posit. // UpdateTime() uses posit_next_time to decide when to // transmit, so we'll just muck with that. // if ( posit_next_time - sec_now() < randomize ) { // Skip setting it, as we'll transmit soon anyway } else { posit_next_time = (size_t)(sec_now() + randomize); } ok = 1; } // Check for illegal case for the ?APRS? query if (!ok && strncasecmp(message,"APRS?",5)==0) { ok = 1; // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call_sign, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); } // Check for proper usage of the ?IGATE? query if (!ok && strncmp(message,"IGATE?",6)==0 && port != -1) // Not from a log file { if (operate_as_an_igate && from != 'F') { xastir_snprintf(temp, sizeof(temp), "= 1) ) { xastir_snprintf(short_path, short_path_size, "%s", path); // Terminate the path at the end of the last used digipeater // This is trickier than it seems due to WIDEn-N and TRACEn-N // digipeaters. // Take a run through the entire path string looking for unused // TRACE/WIDE paths. for ( i = (strlen(path)-1); i >= 0; i-- ) // Count backwards { // If we find ",WIDE3-3" or ",TRACE7-7" (numbers match), // jam '\0' in at the comma. These are unused digipeaters. if ( (strstr(&short_path[i],",WIDE7-7") != NULL) || (strstr(&short_path[i],",WIDE6-6") != NULL) || (strstr(&short_path[i],",WIDE5-5") != NULL) || (strstr(&short_path[i],",WIDE4-4") != NULL) || (strstr(&short_path[i],",WIDE3-3") != NULL) || (strstr(&short_path[i],",WIDE2-2") != NULL) || (strstr(&short_path[i],",WIDE1-1") != NULL) || (strstr(&short_path[i],",TRACE7-7") != NULL) || (strstr(&short_path[i],",TRACE6-6") != NULL) || (strstr(&short_path[i],",TRACE5-5") != NULL) || (strstr(&short_path[i],",TRACE4-4") != NULL) || (strstr(&short_path[i],",TRACE3-3") != NULL) || (strstr(&short_path[i],",TRACE2-2") != NULL) || (strstr(&short_path[i],",TRACE1-1") != NULL) ) { short_path[i] = '\0'; } } // Take another run through short_string looking for used // TRACE/WIDE paths. Also look for '*' characters and flag // if we see any. If no '*' found, but a used TRACE/WIDE // path found, chop the path after the used TRACE/WIDE. This // is to modify paths like this: // APRS,PY1AYH-15*,RELAY,WIDE3-2,PY1EU-1 // to this: // APRS,PY1AYH-15*,RELAY,WIDE3-2 j = 0; found_trace_wide = 0; found_asterisk = 0; for ( i = (strlen(short_path)-1); i >= 0; i-- ) // Count backwards { if (short_path[i] == '*') { found_asterisk++; } // Search for TRACEn/WIDEn. If found (N!=n is guaranteed // by the previous loop) set the lower increment for the next // loop just past the last TRACEn/WIDEn found. The used part // of the TRACEn/WIDEn will still remain in our shorter path. if ( (strstr(&short_path[i],"WIDE7") != NULL) || (strstr(&short_path[i],"WIDE6") != NULL) || (strstr(&short_path[i],"WIDE5") != NULL) || (strstr(&short_path[i],"WIDE4") != NULL) || (strstr(&short_path[i],"WIDE3") != NULL) || (strstr(&short_path[i],"WIDE2") != NULL) || (strstr(&short_path[i],"WIDE1") != NULL) || (strstr(&short_path[i],"TRACE7") != NULL) || (strstr(&short_path[i],"TRACE6") != NULL) || (strstr(&short_path[i],"TRACE5") != NULL) || (strstr(&short_path[i],"TRACE4") != NULL) || (strstr(&short_path[i],"TRACE3") != NULL) || (strstr(&short_path[i],"TRACE2") != NULL) || (strstr(&short_path[i],"TRACE1") != NULL) ) { j = i; found_trace_wide++; break; // We only want to find the right-most one. // We've found a used digipeater! } } // Chop off any unused digi's after a used TRACEn/WIDEn if (!found_asterisk && found_trace_wide) { for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == ',') { short_path[i] = '\0'; // Terminate the string } } } // At this point, if we found a TRACEn or WIDEn, the "j" // variable will be non-zero. If not then it'll be zero and // we'll run completely through the shorter path converting // '*' characters to '\0'. found_asterisk = 0; for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == '*') { short_path[i] = '\0'; // Terminate the string found_asterisk++; } } // Check for TCPIP or TCPXX as the last digipeater. If present, // remove them. TCPXX means that the packet came from an unregistered // user, and those packets will be rejected in igate.c before they're // sent to RF anyway. igate.c will check for its presence in path, // not in short_path, so we're ok here to get rid of it in short_path. if (strlen(short_path) >= 5) // Get rid of "TCPIP" & "TCPXX" { ptr = &short_path[strlen(short_path) - 5]; if ( (strcasecmp(ptr,"TCPIP") == 0) || (strcasecmp(ptr,"TCPXX") == 0) ) { *ptr = '\0'; } if ( (strlen(short_path) >= 1) // Get rid of possible ending comma && (short_path[strlen(short_path) - 1] == ',') ) { short_path[strlen(short_path) - 1] = '\0'; } } // We might have a string with zero used digipeaters. In this case // we will have no '*' characters and no WIDEn-N/TRACEn-N digis. // Get rid of everything except the destination call. These packets // must have been heard directly by an igate station. if (!found_trace_wide && !found_asterisk) { for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == ',') { short_path[i] = '\0'; // Terminate the string } } } // The final step: Remove any asterisks in the path. // We'll insert our own on the way out to RF again. for ( i = 0; i < (int)(strlen(short_path) - 1); i++ ) { if (short_path[i] == '*') { for (j = i; j <= (int)(strlen(short_path) - 1); j++ ) { short_path[j] = short_path[j+1]; // Shift left by one char } } } } else { short_path[0] = '\0'; // We were passed an empty string or a NULL. } if (debug_level & 1) { fprintf(stderr,"%s\n",path); fprintf(stderr,"%s\n\n",short_path); } } // TODO: // *) Use the valid_call(call) function here? // *) Add a "Tactical Call Disable" togglebutton. Default = // disabled. // *) Send out TAC assignments as they are created via an APRS // message? // *) Add "Send All Tactical Calls" menu entry. Another entry to // send them out repetitively? // *) Create a public/private distinction for TAC calls? // *) Add public/private toggle to the Tactical Callsign box, and // have it send an APRS Message if public when changed? // *) Add a method to list the public/private TAC calls we currently // have assigned. // *) Create an easier method to remove one or more TAC calls? // Currently we have to send a blank assignment ("we7u-12="). // *) Log TAC calls and date/time for each assignment, including // NULL assignments. // // From Bob: // *) Range filter - won't accept tactical assignments without a // position within X miles of source. // *) Change filter - won't accept changes from others for locally // created tac assignment. Kind of implies two tables - local // and remote Button/menu item to send local, or send all - each // a manual operation, as we discussed. // *) Perhaps repeat messages fewer times if sent to TACTICAL than // for a normal message? This is so that more than one // controller can manipulate them without having to wait for the // timeout of the first message. // // int fill_in_tactical_callsign(char *call, char *tactical_call) { DataRow *p_station; // Convert callsign to upper-case (void)to_upper(call); // Get rid of white space on either end (void)remove_leading_spaces(call); (void)remove_trailing_spaces(call); (void)remove_leading_spaces(tactical_call); (void)remove_trailing_spaces(tactical_call); // Find the station record. if (!search_station_name(&p_station, call, 1)) { // Station not found. // Add the TAC call to the tactical hash for future // application to a callsign via the log_tactical_call() // function call below... } else // Found it! Assign the new tactical call. Some code { // here borrowed from db.c:Change_tactical_change_data() // Check for blank incoming tactical call. if (tactical_call[0] == '\0') { // Blank tactical call string. Free space and null // pointer. free(p_station->tactical_call_sign); p_station->tactical_call_sign = NULL; } else // Non-blank incoming tactical call string { if (p_station->tactical_call_sign == NULL) { // Malloc some memory to hold it. p_station->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); } if (p_station->tactical_call_sign == NULL) { fprintf(stderr, "Couldn't malloc space for tactical callsign\n"); return -1; } xastir_snprintf(p_station->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", tactical_call); } redraw_on_new_data = 2; // redraw now } // Log the change in the tactical_calls.log file. Also adds it // to the tactical callsign hash. log_tactical_call(call, tactical_call); return(0); } // // Assign tactical callsigns based on messages sent to "TACTICAL" // // *) To set your own tactical callsign and send it to others, // send an APRS message to "TACTICAL" with your callsign in // the message text. // // *) To send multiple tactical calls to others, send an APRS // message to "TACTICAL" and enter: // "CALL1=TAC1;CALL2=TAC2;CALL3=TAC3" in the message text. // // '=' or ';' characters can not be in the TAC callsign. // int tactical_data_add(char *call, char *message, char UNUSED(from) ) { char *temp_ptr; if (strlen(message) <= 1) { return -1; } // Check whether we're dealing with one or multiple tactical // callsign assignments. Look for a '=' character. temp_ptr = strrchr(message,'='); if (temp_ptr == NULL) { // No '=' character was found. We're dealing with a single // tactical assignment for the "call" callsign. Extract the // tactical call and assign it to the station data record // for the station. if (debug_level & 2) { fprintf(stderr, "One tactical assignment.\n"); } fill_in_tactical_callsign(call, message); } else // We're dealing with multiple tactical assignments. { int ii; const int max = 50; char *Substring[max]; char *Call_Tac[2]; if (debug_level & 2) { fprintf(stderr, "Possibly multiple tactical assignments.\n"); } // Split the message first on ';' characters to get the // callsign=tactical pairs separated from each other. split_string( message, Substring, max, ';' ); // Check whether we found more than one pair. if (Substring[0] == NULL) // No ';' chars were found. { // We might still have a single tactical definition in // the message. Assign "message" to Substring[0] for // further processing below. if (debug_level & 2) { fprintf(stderr, "No semicolons found.\n"); } Substring[0] = message; } ii = 0; while (Substring[ii] != NULL) { // Split each string and process. The results of each // split will be in: // Call_Tac[0] (Callsign) // Call_Tac[1] (Tactical Callsign) // split_string( Substring[ii], Call_Tac, 2, '=' ); if (Call_Tac[0] != NULL) // Found '=' char. { if (debug_level & 2) { fprintf(stderr, "Found a tactical pair: %s->%s\n", Call_Tac[0], Call_Tac[1]); } fill_in_tactical_callsign(Call_Tac[0], Call_Tac[1]); } ii++; } } return 0; } // // Messages, Bulletins and Announcements [APRS Reference, chapter 14] // // // Returns 1 if successful // 0 if not successful // int decode_message(char *call,char *path,char *message,char from,int port,int third_party) { char *temp_ptr; char ipacket_message[300]; char message_plus_acks[MAX_MESSAGE_LENGTH + 10]; char from_call[MAX_CALLSIGN+1]; char ack[20]; int ok, len; char addr[9+1]; char addr9[9+1]; char msg_id[5+1]; char orig_msg_id[5+1]; char ack_string[6]; int done; int reply_ack = 0; int to_my_call = 0; int to_my_base_call = 0; int from_my_call = 0; // :xxxxxxxxx:____0-67____ message printable, except '|', '~', '{' // :TACTICAL :text Tactical definition for sending station // :TACTICAL :CALL1=TAC1;CALL2=TAC2 Tactical definitions for multiple stations // :BLNn :____0-67____ general bulletin printable, except '|', '~' // :BLNnxxxxx:____0-67____ + Group Bulletin // :BLNX :____0-67____ Announcement // :NWS-xxxxx:____0-67____ NWS Service Bulletin // :NWS_xxxxx:____0-67____ NWS Service Bulletin // :BOM-xxxxx:____0-67____ BOM Service Bulletin (AU Wx) // :BOM_xxxxx:____0-67____ BOM Service Bulletin (AU Wx) // :xxxxxxxxx:ackn1-5n + ack // :xxxxxxxxx:rejn1-5n + rej // :xxxxxxxxx:____0-67____{n1-5n + message // :NTS.... // 01234567890123456 // 01234567890123456 old // we get message with already extracted data ID if (debug_level & 1) { fprintf(stderr,"decode_message: start\n"); } if (debug_level & 1) { if ( (message != NULL) && (strlen(message) > (MAX_MESSAGE_LENGTH + 10) ) ) { // // Overly long message. Throw it away. We're done. // fprintf(stderr,"decode_message: LONG message. Dumping it.\n"); return(0); } } if (is_my_call(call, 1) ) // Check SSID also { from_my_call++; } ack_string[0] = '\0'; // Clear out the Reply/Ack result string len = (int)strlen(message); ok = (int)(len > 9 && message[9] == ':'); if (ok) { substr(addr9,message,9); // extract addressee xastir_snprintf(addr, sizeof(addr), "%s", addr9); (void)remove_trailing_spaces(addr); if (is_my_call(addr,1)) // Check includes SSID { to_my_call++; } if (is_my_call(addr,0)) // Check ignores SSID. We use { // this to catch messages to some // of our other SSID's to_my_base_call++; } message = message + 10; // pointer to message text // Save the message text and the acks/reply-acks before we // extract the acks below. xastir_snprintf(message_plus_acks, sizeof(message_plus_acks), "%s", message); temp_ptr = strrchr(message,'{'); // look for message ID after //*last* { in message. msg_id[0] = '\0'; if (temp_ptr != NULL) { substr(msg_id,temp_ptr+1,5); // extract message ID, could be non-digit temp_ptr[0] = '\0'; // adjust message end (chops off message ID) } // Save the original msg_id away. xastir_snprintf(orig_msg_id, sizeof(orig_msg_id), "%s", msg_id); // Check for Reply/Ack protocol in msg_id, which looks like // this: "{XX}BB", where XX is the sequence number for the // message, and BB is the ack for the previous message from // my station. I've also seen this from APRS+: "{XX}B", so // perhaps this is also possible "{X}B" or "{X}BB}". We can // also get auto-reply responses from APRS+ that just have // "}X" or "}XX" at the end. We decode those as well. // temp_ptr = strstr(msg_id,"}"); // look for Reply Ack in msg_id if (temp_ptr != NULL) // Found Reply/Ack protocol! { reply_ack++; // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"1Found Reply/Ack:%s\n",message); fprintf(stderr,"Orig_msg_id:%s\t",msg_id); } // Put this code into the UI message area as well (if applicable). // Separate out the extra ack so that we can deal with // it properly. xastir_snprintf(ack_string, sizeof(ack_string), "%s", temp_ptr+1); // After the '}' character! // Terminate it here so that rest of decode works // properly. We can get duplicate messages // otherwise. // // Note that we modify msg_id here. Use orig_msg_id if we need the // unmodified version (full REPLY-ACK version) later. // temp_ptr[0] = '\0'; // adjust msg_id end // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"New_msg_id:%s\tReply_ack:%s\n\n", msg_id,ack_string); } } else // Look for Reply Ack in message without sequence { // number temp_ptr = strstr(message,"}"); if (temp_ptr != NULL) { int yy = 0; reply_ack++; // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"2Found Reply/Ack:%s\n",message); } // Put this code into the UI message area as well (if applicable). xastir_snprintf(ack_string, sizeof(ack_string), "%s", temp_ptr+1); // After the '}' character! ack_string[yy] = '\0'; // Terminate the string // Terminate it here so that rest of decode works // properly. We can get duplicate messages // otherwise. temp_ptr[0] = '\0'; // adjust message end // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"Reply_ack:%s\n\n",ack_string); } } } done = 0; } else { done = 1; // fall through... } if (debug_level & 1) { fprintf(stderr,"1\n"); } len = (int)strlen(message); //-------------------------------------------------------------------------- if (!done && len > 3 && strncmp(message,"ack",3) == 0) // ACK { // Received an ACK packet. Note that these can carry the // REPLY-ACK protocol or a single ACK sequence number plus // perhaps an extra '}' on the end. They should have one of // these formats: // ack1 Normal ACK // ackY Normal ACK // ack23 Normal ACK // ackfH Normal ACK // ack23{ REPLY-ACK Protocol // ack2Q}3d REPLY-ACK Protocol substr(msg_id,message+3,5); // fprintf(stderr,"ACK: %s: |%s| |%s|\n",call,addr,msg_id); // if (is_my_call(addr,1)) { // Check SSID also if (to_my_call) // Check SSID also { // Note: This function handles REPLY-ACK protocol just // fine, stripping off the 2nd ack if present. It uses // only the first sequence number. clear_acked_message(call,addr,msg_id); // got an ACK for me // This one also handles REPLY-ACK protocol just fine. msg_record_ack(call,addr,msg_id,0,0); // Record the ack for this message } else // ACK is for another station { // Now if I have Igate on and I allow to retransmit station data // check if this message is to a person I have heard on my TNC within an X // time frame. If if is a station I heard and all the conditions are ok // spit the ACK out on the TNC -FG if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); // Only send '}' and the ack_string if it's not // empty, else just end the packet with the message // string. This keeps us from appending a '}' when // it's not called for. xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s%s%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, // message, message_plus_acks); // (ack_string[0] == '\0') ? "" : "}", // ack_string); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send ACK to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } } done = 1; } if (debug_level & 1) { fprintf(stderr,"2\n"); } //-------------------------------------------------------------------------- if (!done && len > 3 && strncmp(message,"rej",3) == 0) // REJ { substr(msg_id,message+3,5); // if ( is_my_call(addr,1) ) { // Check SSID also if (to_my_call) // Check SSID also { // REJ is for me! // fprintf(stderr,"Received a REJ packet from %s: |%s| |%s|\n",call,addr,msg_id); // Note: This function handles REPLY-ACK protocol just // fine, stripping off the 2nd ack if present. It uses // only the first sequence number. clear_acked_message(call,addr,msg_id); // got an REJ for me // This one also handles REPLY-ACK protocol just fine. msg_record_rej(call,addr,msg_id); // Record the REJ for this message } else // REJ is for another station { /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the REJ out on the TNC */ if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); // Only send '}' and the rej_string if it's not // empty, else just end the packet with the message // string. This keeps us from appending a '}' when // it's not called for. xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s%s%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, // message, message_plus_acks); // (ack_string[0] == '\0') ? "" : "}", // ack_string); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send REJ to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } } done = 1; } if (debug_level & 1) { fprintf(stderr,"3\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"TACTICAL",8) == 0) // Tactical definition { if (debug_level & 2) { fprintf(stderr,"found TACTICAL: |%s| |%s|\n",call,message); } tactical_data_add(call,message,from); done = 1; } if (debug_level & 1) { fprintf(stderr,"TAC\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"BLN",3) == 0) // Bulletin { // fprintf(stderr,"found BLN: |%s| |%s|\n",addr,message); bulletin_data_add(addr,call,message,"",MESSAGE_BULLETIN,from); done = 1; } if (debug_level & 1) { fprintf(stderr,"4\n"); } //-------------------------------------------------------------------------- // if (!done && strlen(msg_id) > 0 && is_my_call(addr,1)) { // Message for me (including SSID check) if (!done && strlen(msg_id) > 0 && to_my_call) // Message for me (including SSID check) { // with msg_id (sequence number) time_t last_ack_sent; long record; // Remember to put this code into the UI message area as well (if // applicable). // Check for Reply/Ack if (reply_ack && strlen(ack_string) != 0) // Have a free-ride ack to deal with { //fprintf(stderr, "reply-ack: clear_acked_message()\n"); clear_acked_message(call,addr,ack_string); // got an ACK for me //fprintf(stderr, "reply-ack: msg_record_ack()\n"); msg_record_ack(call,addr,ack_string,0,0); // Record the ack for this message } // Save the ack 'cuz we might need it while talking to this // station. We need it to implement Reply/Ack protocol. // Note that msg_id has already been truncated by this point. // orig_msg_id contains the full REPLY-ACK text. //fprintf(stderr, "store_most_recent_ack()\n"); store_most_recent_ack(call,msg_id); // fprintf(stderr,"found Msg w line to me: |%s| |%s|\n",message,msg_id); last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); // id_fixed // Here we need to know if it is a new message or an old. // If we've already received it, we don't want to kick off // the alerts or pop up the Send Message dialog again. If // last_ack_sent == (time_t)0, then it is a new message. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist // for this QSO. Only call it for the first message // line or the first ack, not for any repeats. // //fprintf(stderr,"***check_popup_window 1\n"); (void)check_popup_window(call, 2); // Calls update_messages() //update_messages(1); // Force an update if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } #ifdef HAVE_FESTIVAL /* I re-use ipacket_message as my string buffer */ if (festival_speak_new_message_alert) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "You have a new message from %s.", call); SayText(ipacket_message); } if (festival_speak_new_message_body) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), " %s", message); SayText(ipacket_message); } #endif // HAVE_FESTIVAL } // Try to only send an ack out once per 30 seconds at the // fastest. //WE7U // Does this 30-second check work? // if ( from != 'F' // Not from a log file && (last_ack_sent != (time_t)-1l) // Not an error && (last_ack_sent + 30 ) < sec_now() && !satellite_ack_mode // Disable separate ack's for satellite work && port != -1 ) // Not from a log file { char path[MAX_LINE_SIZE+1]; //fprintf(stderr,"Sending ack: %ld %ld %ld\n",last_ack_sent,sec_now(),record); // Update the last_ack_sent field for the message msg_update_ack_stamp(record); pad_callsign(from_call,call); /* ack the message */ // Attempt to snag a custom path out of the Send Message // dialog, if set. If not set, path will contain '\0'; get_send_message_path(call, path, MAX_LINE_SIZE+1); //fprintf(stderr,"Path: %s\n", path); // In this case we want to send orig_msg_id back, not // the (possibly) truncated msg_id. This is per Bob B's // Reply/Ack spec, sent to xastir-dev on Nov 14, 2001. xastir_snprintf(ack, sizeof(ack), ":%s:ack%s",from_call,orig_msg_id); //WE7U // Need to figure out the reverse path for this one instead of // passing a NULL for the path? Probably not, as auto-calculation // of paths isn't a good idea. // // What we need to do here is check whether we have a custom path // set for this QSO. If so, pass that path along as the transmit // path. messages.h:Message_Window struct has the send_message_path // variable in it. If a Message_Window still exists for this QSO // then we can snag the user-entered path from there. If the struct // has already been destroyed then we have nowhere to snag the // custom path from and have to rely on the default paths in each // interface properties dialog instead. Then again, we _could_ snag // the path out of the last received message in the message database // for that case. Might be better to disable the Close button, or // warn the user that the custom path will be lost if they close the // Send Message dialog. // Send out the immediate ACK if (path[0] == '\0') { transmit_message_data(call,ack,NULL); } else { transmit_message_data(call,ack,path); } if (record != -1l) // Msg we've received before { // It's a message that we've received before, // consider sending an extra ACK in about 30 seconds // to try to get it to the remote station. Perhaps // another one in 60 seconds as well. // fprintf(stderr, // "We've received this message before.\n"); // fprintf(stderr, // "Sending a couple of delayed ack's.\n"); if (path[0] == '\0') { transmit_message_data_delayed(call,ack,NULL,sec_now()+30); transmit_message_data_delayed(call,ack,NULL,sec_now()+60); transmit_message_data_delayed(call,ack,NULL,sec_now()+120); } else { transmit_message_data_delayed(call,ack,path,sec_now()+30); transmit_message_data_delayed(call,ack,path,sec_now()+60); transmit_message_data_delayed(call,ack,path,sec_now()+120); } } if (auto_reply == 1) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "AA:%s", auto_reply_message); if (debug_level & 2) fprintf(stderr,"Send autoreply to <%s> from <%s> :%s\n", call, my_callsign, ipacket_message); // if (!is_my_call(call,1)) // Check SSID also if (!from_my_call) // Check SSID also { output_message(my_callsign, call, ipacket_message, ""); } } } else { //fprintf(stderr,"Skipping ack: %ld %ld\n",last_ack_sent,sec_now()); } done = 1; } if (debug_level & 1) { fprintf(stderr,"5a\n"); } //-------------------------------------------------------------------------- if (!done && strlen(msg_id) == 0 && to_my_call) // Message for me (including SSID check) { // but without message-ID. // These should appear in a Send Message dialog and should // NOT get ack'ed. Kenwood radios send this message type as // an auto-answer or a buffer-full message. They look // something like: // // :WE7U-13 :Not at keyboard. // time_t last_ack_sent; long record; if (len > 2 && message[0] == '?' && port != -1 // Not from a log file && to_my_call) // directed query (check SSID also) { // Smallest query known is "?WX". if (debug_level & 1) { fprintf(stderr,"Received a directed query\n"); } done = process_directed_query(call,path,message+1,from); } // fprintf(stderr,"found Msg w line to me: |%s| |%s|\n",message,msg_id); last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); // id_fixed // Here we need to know if it is a new message or an old. // If we've already received it, we don't want to kick off // the alerts or pop up the Send Message dialog again. If // last_ack_sent == (time_t)0, then it is a new message. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist // for this QSO. Only call it for the first message // line or the first ack, not for any repeats. // //fprintf(stderr,"***check_popup_window 1\n"); (void)check_popup_window(call, 2); // Calls update_messages() //update_messages(1); // Force an update if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } #ifdef HAVE_FESTIVAL /* I re-use ipacket_message as my string buffer */ if (festival_speak_new_message_alert) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "You have a new message from %s.", call); SayText(ipacket_message); } if (festival_speak_new_message_body) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), " %s", message); SayText(ipacket_message); } #endif // HAVE_FESTIVAL } // Update the last_ack_sent field for the message, even // though we won't be sending an ack in response. msg_update_ack_stamp(record); //fprintf(stderr,"Received msg for me w/o ack\n"); done = 1; } if (debug_level & 1) { fprintf(stderr,"5b\n"); } //-------------------------------------------------------------------------- if (!done && ( (strncmp(addr,"NWS-",4) == 0) // NWS weather alert || (strncmp(addr,"NWS_",4) == 0) // NWS weather alert compressed || (strncmp(addr,"BOM-",4) == 0) // BOM (AU) weather alert || (strncmp(addr,"BOM_",4) == 0) ) ) // BOM (AU) weather alert compressed { // could have sort of line number //fprintf(stderr,"found NWS: |%s| |%s| |%s|\n",addr,message,msg_id); (void)alert_data_add(addr, call, message, msg_id, MESSAGE_NWS, from); done = 1; if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message); output_nws_igate_rf(call, path, ipacket_message, port, third_party); } } if (debug_level & 1) { fprintf(stderr,"6a\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"SKY",3) == 0) // NWS weather alert additional info { // could have sort of line number //fprintf(stderr,"found SKY: |%s| |%s| |%s|\n",addr,message,msg_id); /* (void)alert_data_add(addr, call, message, msg_id, MESSAGE_NWS, from); */ // We don't wish to record these in memory. They cause an infinite // loop in the current code and a massive memory leak. return(1); // Tell the calling program that the packet was ok so // that it doesn't add it with data_add() itself! done = 1; if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message); output_nws_igate_rf(call, path, ipacket_message, port, third_party); } } if (debug_level & 1) { fprintf(stderr,"6b\n"); } //-------------------------------------------------------------------------- if (!done && strlen(msg_id) > 0) // Other message with linenumber. This { // is either a message for someone else // or a message for another one of my // SSID's. long record_out; time_t last_ack_sent; char message_plus_note[MAX_MESSAGE_LENGTH + 30]; if (debug_level & 2) fprintf(stderr,"found Msg w/line: |%s| |%s| |%s|\n", addr, message, orig_msg_id); if (to_my_base_call && !from_my_call) { // Special case: We saw a message w/msg_id that was to // one of our other SSID's, but it was not from // ourselves. That last bit (!from_my_call) is // important in the case where we're working an event // with several stations using the same callsign. // // Store as if it came to my callsign, with a zeroed-out // msg_id so we can't try to ack it. We also need some // other indication in the "Send Message" dialog as to // what's happening. Perhaps add the original callsign // to the message itself in a note at the start? // xastir_snprintf(message_plus_note, sizeof(message_plus_note), "(Sent to:%s) %s", addr, message); last_ack_sent = msg_data_add(my_callsign, call, message_plus_note, "", MESSAGE_MESSAGE, from, &record_out); } else // Normal case, messaging between other people { last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record_out); } new_message_data += look_for_open_group_data(addr); // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record_out == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 2\n"); // Callsign check here also checks SSID for exact match // if ((is_my_call(call,1) && check_popup_window(addr, 2) != -1) // if ((from_my_call && check_popup_window(addr, 2) != -1) // We need to do an SSID-non-specific check here so that we can pick // up messages intended for other stations of ours. // if ((to_my_base_call && check_popup_window(addr, 2) != -1) if ((to_my_base_call && check_popup_window(call, 2) != -1) || check_popup_window(call, 0) != -1 || check_popup_window(addr, 1) != -1) { //fprintf(stderr,"Matches my base call\n"); update_messages(1); // Force an update } } /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the message out on the TNC -FG */ if (operate_as_an_igate>1 && last_ack_sent != (time_t)-1l && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also // && !is_my_call(addr,1) // Check SSID also && !to_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s{%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message_plus_acks); // message, // orig_msg_id); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send message to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } done = 1; } if (debug_level & 1) { fprintf(stderr,"7\n"); } //-------------------------------------------------------------------------- if (!done) // message without line number { long record_out; time_t last_ack_sent; if (debug_level & 4) { fprintf(stderr,"found Msg: |%s| |%s|\n",addr,message); } //found Msg: |WE7U-13| |?APRSD| //found Msg: |WE7U-14| |Directs=| last_ack_sent = msg_data_add(addr, call, message, "", MESSAGE_MESSAGE, from, &record_out); new_message_data++; // ?????? // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record_out == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 3\n"); if (check_popup_window(addr, 1) != -1) { //update_messages(1); // Force an update } } // Could be response to a query. Popup a message. // Check addr for my_call and !third_party, then check later in the // packet for my_call if it is a third_party message? Depends on // what the packet looks like by this point. if ( last_ack_sent != (time_t)-1l && (message[0] != '?') // && is_my_call(addr,1) ) { // Check SSID also && to_my_call ) // Check SSID also { // We no longer wish to have both popups and the Send // Group Message dialogs come up for every query // response, so we use popup_message() here instead of // popup_message_always() so that by default we'll see // the below message in STDERR. If --with-errorpopups // has been configured in, we'll get a popup as well. // Send Group Message dialogs work well for multi-line // query responses, so we'll leave it that way. // popup_message(langcode("POPEM00018"),message); // Check for Reply/Ack. APRS+ sends an AA: response back // for auto-reply, with an embedded free-ride Ack. if (strlen(ack_string) != 0) // Have an extra ack to deal with { clear_acked_message(call,addr,ack_string); // got an ACK for me msg_record_ack(call,addr,ack_string,0,0); // Record the ack for this message } } // done = 1; } if (debug_level & 1) { fprintf(stderr,"9\n"); } //-------------------------------------------------------------------------- if (ok) (void)data_add(STATION_CALL_DATA, call, path, message, from, port, NULL, third_party, 0, // Not a packet from my station 0); // Not my object/item if (debug_level & 1) { fprintf(stderr,"decode_message: finish\n"); } return(ok); } /* * UI-View format messages, not relevant for APRS, format is not specified in APRS Reference * * This function is not currently called anywhere in the code. */ int decode_UI_message(char *call,char *path,char *message,char from,int port,int third_party) { char *temp_ptr; char from_call[MAX_CALLSIGN+1]; char ack[20]; char addr[9+1]; int ok, len; char msg_id[5+1]; int done; int from_my_call = 0; int to_my_call = 0; if (is_my_call(call, 1) ) // Check SSID also { from_my_call++; } // I'm not sure, but I think they use 2 digit line numbers only // extract addr from path substr(addr,path,9); ok = (int)(strlen(addr) > 0); if (ok) { temp_ptr = strstr(addr,","); // look for end of first call if (temp_ptr != NULL) { temp_ptr[0] = '\0'; // adjust addr end } ok = (int)(strlen(addr) > 0); } if (is_my_call(addr, 1) ) // Check SSID also { to_my_call++; } len = (int)strlen(message); ok = (int)(len >= 2); if (ok) { temp_ptr = strstr(message,"~"); // look for message ID msg_id[0] = '\0'; if (temp_ptr != NULL) { substr(msg_id,temp_ptr+1,2); // extract message ID, could be non-digit temp_ptr[0] = '\0'; // adjust message end } done = 0; } else { done = 1; // fall through... } len = (int)strlen(message); //-------------------------------------------------------------------------- // Callsign check here checks SSID as well // if (!done && msg_id[0] != '\0' && is_my_call(addr,1)) { // message for me if (!done && msg_id[0] != '\0' && to_my_call) // message for me { time_t last_ack_sent; long record; last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 4\n"); (void)check_popup_window(call, 2); //update_messages(1); // Force an update } if (last_ack_sent != (time_t)-1l) { if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } // Only send an ack or autoresponse once per 30 seconds if ( (from != 'F') && ( (last_ack_sent + 30) < sec_now()) ) { //fprintf(stderr,"Sending ack: %ld %ld %ld\n",last_ack_sent,sec_now(),record); // Record the fact that we're sending an ack now msg_update_ack_stamp(record); pad_callsign(from_call,call); /* ack the message */ xastir_snprintf(ack, sizeof(ack), ":%s:ack%s",from_call,msg_id); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,ack,NULL); if (auto_reply == 1) { char temp[300]; xastir_snprintf(temp, sizeof(temp), "AA:%s", auto_reply_message); if (debug_level & 2) fprintf(stderr,"Send autoreply to <%s> from <%s> :%s\n", call, my_callsign, temp); // if (!is_my_call(call,1)) // Check SSID also if (!from_my_call) // Check SSID also { output_message(my_callsign, call, temp, ""); } } } } done = 1; } //-------------------------------------------------------------------------- if (!done && len == 2 && msg_id[0] == '\0') // ACK { substr(msg_id,message,5); // if (is_my_call(addr,1)) { // Check SSID also if (to_my_call) // Check SSID also { clear_acked_message(call,addr,msg_id); // got an ACK for me msg_record_ack(call,addr,msg_id,0,0); // Record the ack for this message } // else { // ACK for other station /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the ACK out on the TNC -FG */ //// if (operate_as_an_igate>1 && from==DATA_VIA_NET && !is_my_call(call,1)) { // if (operate_as_an_igate>1 && from==DATA_VIA_NET && !from_my_call) { // char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n",operate_as_an_igate,from,my_callsign,call,addr); { // shorten_path(path,short_path,sizeof(short_path)); //sprintf(ipacket_message,"}%s>%s:%s:%s",call,path,addr9,message); // sprintf(ipacket_message,"}%s>%s,TCPIP,%s*::%s:%s",call,short_path,my_callsign,addr9,message); // output_igate_rf(call,addr,path,ipacket_message,port,third_party,NULL); // igate_msgs_tx++; // } // } done = 1; } //-------------------------------------------------------------------------- if (ok) { (void)data_add(STATION_CALL_DATA, call, path, message, from, port, NULL, third_party, 0, // Not a packet from my station 0); // Not my object/item } return(ok); } /* * Decode APRS Information Field and dispatch it depending on the Data Type ID * * call = Callsign or object/item name string * path = Path string * message = Info field (corrupted already if object/item packet) * origin = Originating callsign if object/item, otherwise NULL * from = DATA_VIA_LOCAL/DATA_VIA_TNC/DATA_VIA_NET/DATA_VIA_FILE * port = Port number * third_party = Set to one if third-party packet * orig_message = Unmodified info field * */ void decode_info_field(char *call, char *path, char *message, char *origin, char from, int port, int third_party, char *orig_message) { char line[MAX_LINE_SIZE+1]; int ok_igate_net; int ok_igate_rf; int done, ignore; char data_id; int station_is_mine = 0; int object_is_mine = 0; char user_base_dir[MAX_VALUE]; /* remember fixed format starts with ! and can be up to 24 chars in the message */ // ??? if (debug_level & 1) { fprintf(stderr,"decode_info_field: c:%s p:%s m:%s f:%c o:%s\n",call,path,message,from,origin); } if (debug_level & 1) { fprintf(stderr,"decode_info_field: Past check\n"); } done = 0; // if 1, packet was decoded ignore = 0; // if 1, don't treat undecoded packets as status text ok_igate_net = 0; // if 1, send packet to internet ok_igate_rf = 0; // if 1, igate packet to RF if "from" is in nws-stations.txt if ( is_my_call(call, 1) ) { station_is_mine++; // Station is controlled by me } if ( (message != NULL) && (strlen(message) > MAX_LINE_SIZE) ) // Overly long message, throw it away. { if (debug_level & 1) { fprintf(stderr,"decode_info_field: Overly long message. Throwing it away.\n"); } done = 1; } else if (message == NULL || strlen(message) == 0) // we could have an empty message { (void)data_add(STATION_CALL_DATA,call,path,NULL,from,port,origin,third_party, station_is_mine, 0); done = 1; // don't report it to internet } // special treatment for objects/items. if (!done && origin[0] != '\0') { // If station/object/item is owned by me (including SSID) if ( is_my_call(origin, 1) ) { object_is_mine++; } if (message[0] == '*') // set object { (void)data_add(APRS_OBJECT,call,path,message+1,from,port,origin,third_party, station_is_mine, object_is_mine); if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } else if (message[0] == '!') // set item { (void)data_add(APRS_ITEM,call,path,message+1,from,port,origin,third_party, station_is_mine, object_is_mine); if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } else if (message[0] == '_') // delete object/item { DataRow *p_station; delete_object(call); // ?? does not vanish from map immediately !!??? // If object was owned by me but another station is // transmitting it now, write entries into the // object.log file showing that we don't own this object // anymore. p_station = NULL; if (search_station_name(&p_station,call,1)) { // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) // If station was owned by me (including SSID) && (!object_is_mine) ) // But isn't now { disown_object_item(call,origin); } } if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } } if (!done) { data_id = message[0]; // look at the APRS Data Type ID (first char in information field) message += 1; // extract data ID from information field ok_igate_net = 1; // as default report packet to internet if (debug_level & 1) { if (ok_igate_net) { fprintf(stderr,"decode_info_field: ok_igate_net can be read\n"); } } switch (data_id) { case '=': // Position without timestamp (with APRS messaging) if (debug_level & 1) { fprintf(stderr,"decode_info_field: = (position w/o timestamp)\n"); } //WE7U // Need to check for weather info in this packet type as well? done = data_add(APRS_MSGCAP,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '!': // Position without timestamp (no APRS messaging) or Ultimeter 2000 WX if (debug_level & 1) { fprintf(stderr,"decode_info_field: ! (position w/o timestamp or Ultimeter 2000 WX)\n"); } if (message[0] == '!' && is_xnum_or_dash(message+1,40)) // Ultimeter 2000 WX { done = data_add(APRS_WX3,call,path,message+1,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_FIXED,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '/': // Position with timestamp (no APRS messaging) if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (position w/timestamp)\n"); } //WE7U // Need weather decode in this section similar to the '@' section // below. if ((toupper(message[14]) == 'N' || toupper(message[14]) == 'S') && (toupper(message[24]) == 'W' || toupper(message[24]) == 'E')) // uncompressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (uncompressed position w/timestamp no messaging)\n"); } if (message[29] == '/') { if (message[33] == 'g' && message[37] == 't') { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else // compressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (compressed position w/timestamp no messaging)\n"); } if (message[16] >= '!' && message[16] <= 'z') // csT is speed/course { if (message[20] == 'g' && message[24] == 't') // Wx data { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } // done = data_add(APRS_DOWN,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '@': // Position with timestamp (with APRS messaging) // DK7IN: could we need to test the message length first? if ((toupper(message[14]) == 'N' || toupper(message[14]) == 'S') && (toupper(message[24]) == 'W' || toupper(message[24]) == 'E')) // uncompressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: @ (uncompressed position w/timestamp)\n"); } if (message[29] == '/') { if (message[33] == 'g' && message[37] == 't') { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else // compressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: @ (compressed position w/timestamp)\n"); } if (message[16] >= '!' && message[16] <= 'z') // csT is speed/course { if (message[20] == 'g' && message[24] == 't') // Wx data { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } ok_igate_rf = done; break; case '[': // Maidenhead grid locator beacon (obsolete- but used for meteor scatter) done = data_add(APRS_GRID,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case 0x27: // Mic-E Old GPS data (or current GPS data in Kenwood TM-D700) case 0x60: // Mic-E Current GPS data (but not used in Kennwood TM-D700) //case 0x1c:// Mic-E Current GPS data (Rev. 0 beta units only) //case 0x1d:// Mic-E Old GPS data (Rev. 0 beta units only) if (debug_level & 1) { fprintf(stderr,"decode_info_field: 0x27 or 0x60 (Mic-E)\n"); } done = decode_Mic_E(call,path,message,from,port,third_party); ok_igate_rf = done; break; case '_': // Positionless weather data [APRS Reference, chapter 12] if (debug_level & 1) { fprintf(stderr,"decode_info_field: _ (positionless wx data)\n"); } done = data_add(APRS_WX2,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '#': // Peet Bros U-II Weather Station (km/h) [APRS Reference, chapter 12] if (debug_level & 1) { fprintf(stderr,"decode_info_field: # (peet bros u-II wx station)\n"); } if (is_xnum_or_dash(message,13)) { done = data_add(APRS_WX4,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '*': // Peet Bros U-II Weather Station (mph) if (debug_level & 1) { fprintf(stderr,"decode_info_field: * (peet bros u-II wx station)\n"); } if (is_xnum_or_dash(message,13)) { done = data_add(APRS_WX6,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '$': // Raw GPS data or Ultimeter 2000 if (debug_level & 1) { fprintf(stderr,"decode_info_field: $ (raw gps or ultimeter 2000)\n"); } if (strncmp("ULTW",message,4) == 0 && is_xnum_or_dash(message+4,44)) { done = data_add(APRS_WX5,call,path,message+4,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPGGA",message,5) == 0) { done = data_add(GPS_GGA,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPRMC",message,5) == 0) { done = data_add(GPS_RMC,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPGLL",message,5) == 0) { done = data_add(GPS_GLL,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { // handle VTG and WPT too (APRS Ref p.25) } ok_igate_rf = done; break; case ':': // Message if (debug_level & 1) { fprintf(stderr,"decode_info_field: : (message)\n"); } // Do message logging if that feature is enabled. if (log_message_data && from != DATA_VIA_FILE) { char temp_msg[MAX_MESSAGE_LENGTH+1]; xastir_snprintf(temp_msg, sizeof(temp_msg), "%s>%s:%s", call, path, orig_message); log_data( get_user_base_dir(LOGFILE_MESSAGE, user_base_dir, sizeof(user_base_dir)), temp_msg ); } //fprintf(stderr,"Calling decode_message\n"); done = decode_message(call,path,message,from,port,third_party); //fprintf(stderr,"Back from decode_message\n"); // there could be messages I should not retransmit to internet... ??? Queries to me... break; case '>': // Status [APRS Reference, chapter 16] if (debug_level & 1) { fprintf(stderr,"decode_info_field: > (status)\n"); } done = data_add(APRS_STATUS,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '?': // Query if (debug_level & 1) { fprintf(stderr,"decode_info_field: ? (query)\n"); } done = process_query(call,path,message,from,port,third_party); ignore = 1; // don't treat undecoded packets as status text break; case 'T': // Telemetry data [APRS Reference, chapter 13] // We treat these as status packets currently. ok_igate_rf = 1; if (debug_level & 1) { fprintf(stderr,"decode_info_field: T (telem)\n"); } done = data_add(APRS_STATUS,call,path,message,from,port,origin,third_party, station_is_mine, 0); break; case '{': // User-defined APRS packet format //} // We treat these as status packets currently. ok_igate_rf = 1; break; case '<': // Station capabilities [APRS Reference, chapter 15] if (debug_level & 1) { fprintf(stderr,"decode_info_field: ~,<\n"); } // // We could tweak the Incoming Data dialog to add // filter togglebuttons. One such toggle could be // "Station Capabilities". We'd then have a usable // dialog for displaying things like ?IGATE? // responses. In this case we wouldn't have to do // anything special with the packet for decoding, // just let it hit the default block below for // putting them into the status field of the record. // One downside is that we'd only be able to catch // new station capability records in that dialog. // The only way to look at past capability records // would be the Station Info dialog for each // station. // //fprintf(stderr,"%10s: %s\n", call, message); // Don't set "done" as we want these to appear in // the status text for the record. break; case '%': // Agrelo DFJr / MicroFinder Radio Direction Finding if (debug_level & 1) { fprintf(stderr,"decode_info_field: %%\n"); } // Here is where we'd add a call to an RDF decode // function so that we could display vectors on the // map for each RDF position. // // Agrelo format: "%XXX/Q" // // "XXX" is relative bearing to the signal (000-359). Careful here: // At least one unit reports in magnetic instead of relative // degrees. "000" means no direction info available, 360 means true // north. // // "Q" is bearing quality (0-9). 0 = unsuitable. 9 = manually // entered. 1-8 = varying quality with 8 being the best. // // I've also seen these formats, which may not be Agrelo compatible: // // "%136.0/9" // "%136.0/8/158.0" (That last number is magnetic bearing) // // These sentences may be sent MULTIPLE times per second, like 20 or // more! If we decide to average readings, we'll need to dump our // averages and start over if our course changes. // // Check for Agrelo format: if ( strlen(message) >= 5 && is_num_chr(message[0]) // "%136/9" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '/' && is_num_chr(message[4]) ) { fprintf(stderr, "Type 1 RDF packet from call: %s\tBearing: %c%c%c\tQuality: %c\n", call, message[0], message[1], message[2], message[4]); } // Check for extended formats (not // Agrelo-compatible): else if (strlen(message) >= 13 && is_num_chr(message[0]) // "%136.0/8/158.0" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '.' && is_num_chr(message[4]) && message[5] == '/' && is_num_chr(message[6]) && message[7] == '/' && is_num_chr(message[8]) && is_num_chr(message[9]) && is_num_chr(message[10]) && message[11] == '.' && is_num_chr(message[12]) ) { fprintf(stderr, "Type 3 RDF packet from call: %s\tBearing: %c%c%c%c%c\tQuality: %c\tMag Bearing: %c%c%c%c%c\n", call, message[0], message[1], message[2], message[3], message[4], message[6], message[8], message[9], message[10], message[11], message[12]); } // Check for extended formats (not // Agrelo-compatible): else if (strlen(message) >= 7 && is_num_chr(message[0]) // "%136.0/9" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '.' && is_num_chr(message[4]) && message[5] == '/' && is_num_chr(message[6]) ) { fprintf(stderr, "Type 2 RDF packet from call: %s\tBearing: %c%c%c%c%c\tQuality: %c\n", call, message[0], message[1], message[2], message[3], message[4], message[6]); } // Don't set "done" as we want these to appear in // the status text for the record until we get the // full decoding for this type of packet coded up. break; case '~': // UI-format messages, not relevant for APRS ("Do not use" in Reference) case ',': // Invalid data or test packets [APRS Reference, chapter 19] case '&': // Reserved -- Map Feature if (debug_level & 1) { fprintf(stderr,"decode_info_field: ~,&\n"); } ignore = 1; // Don't treat undecoded packets as status text break; } if (debug_level & 1) { if (done) { fprintf(stderr,"decode_info_field: done = 1\n"); } else { fprintf(stderr,"decode_info_field: done = 0\n"); } if (ok_igate_net) { fprintf(stderr,"decode_info_field: ok_igate_net can be read 2\n"); } } if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with big switch\n"); } // Add most remaining data to the station record as status // info // if (!done && !ignore) // Other Packets [APRS Reference, chapter 19] { done = data_add(OTHER_DATA,call,path,message-1,from,port,origin,third_party, station_is_mine, 0); if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with data_add(OTHER_DATA)\n"); } } if (!done) // data that we do ignore... { //fprintf(stderr,"decode_info_field: not decoding info: Call:%s ID:%c Msg:|%s|\n",call,data_id,message); ok_igate_net = 0; // don't put data on internet if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with ignored data\n"); } } } if (third_party) { ok_igate_net = 0; // don't put third party traffic on internet } // if (is_my_call(call,1)) // Check SSID as well if (station_is_mine) { ok_igate_net = 0; // don't put my data on internet ??? } if (ok_igate_net) { if (debug_level & 1) { fprintf(stderr,"decode_info_field: ok_igate_net start\n"); } if ( (from == DATA_VIA_TNC) // Came in via a TNC && (strlen(orig_message) > 0) ) // Not empty { // Here's where we inject our own callsign like this: // "WE7U-15,I" in order to provide injection ID for our // igate. xastir_snprintf(line, sizeof(line), "%s>%s,%s,I:%s", (strlen(origin)) ? origin : call, path, my_callsign, orig_message); //fprintf(stderr,"decode_info_field: IGATE>NET %s\n",line); output_igate_net(line, port, third_party); } } // Attempt to gate to RF only if the following conditions are // met: // // *) ok_igate_rf flag is set. // *) Not my exact callsign. // *) Packet was from the INET, not local RF // *) The "from" call matches a line in data/nws-stations.txt, // verified by igate.c:check_NWS_stations(). // // The output_igate_rf() function will also do some checks on // the packet before allowing it to be igated, including a // dupe-check. // // Callsign check here checks SSID as well // if (ok_igate_rf && !is_my_call(call,1) && from == DATA_VIA_NET) { if (ok_igate_rf && !station_is_mine && from == DATA_VIA_NET) { char ipacket_message[300]; char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*:%s", (strlen(origin)) ? origin : call, short_path, my_callsign, orig_message); // If origin, pass "call" to output_igate_rf() as the last // parameter. This would be the object/item name. output_igate_rf((strlen(origin)) ? origin : call, (strlen(origin)) ? origin : call, path, ipacket_message, port, third_party, (strlen(origin)) ? call : NULL); //fprintf(stderr,"decode_info_field: IGATE>RF %s\n",ipacket_message); } if (debug_level & 1) { fprintf(stderr,"decode_info_field: done\n"); } } /* * Extract object or item data from information field before processing * * Returns 1 if valid object found, else returns 0. * */ int extract_object(char *call, char **info, char *origin) { int ok, i; // Object and Item Reports [APRS Reference, chapter 11] ok = 0; // todo: add station originator to database if ((*info)[0] == ';') // object { // fixed 9 character object name with any printable ASCII character if (strlen((*info)) > 1+9) { substr(call,(*info)+1,9); // extract object name (*info) = (*info) + 10; // Remove leading spaces ? They look bad, but are allowed by the APRS Reference ??? (void)remove_trailing_spaces(call); if (valid_object(call)) { // info length is at least 1 ok = 1; } } } else if ((*info)[0] == ')') // item { // 3 - 9 character item name with any printable ASCII character if (strlen((*info)) > 1+3) { for (i = 1; i <= 9; i++) { if ((*info)[i] == '!' || (*info)[i] == '_') { call[i-1] = '\0'; break; } call[i-1] = (*info)[i]; } call[9] = '\0'; // In case we never saw '!' || '_' (*info) = &(*info)[i]; // Remove leading spaces ? They look bad, but are allowed by the APRS Reference ??? //(void)remove_trailing_spaces(call); // This statement messed up our searching!!! Don't use it! if (valid_object(call)) { // info length is at least 1 ok = 1; } } } else { fprintf(stderr,"Not an object, nor an item!!! call=%s, info=%s, origin=%s.\n", call, *info, origin); } return(ok); } /* * Extract third-party traffic from information field before processing */ int extract_third_party(char *call, char *path, int path_size, char **info, char *origin, int origin_size) { int ok; char *p_call; char *p_path; p_call = NULL; // to make the compiler happy... p_path = NULL; // to make the compiler happy... ok = 0; if (!is_my_call(call,1)) // Check SSID also { // todo: add reporting station call to database ?? // but only if not identical to reported call (*info) = (*info) +1; // strip '}' character p_call = strtok((*info),">"); // extract call if (p_call != NULL) { p_path = strtok(NULL,":"); // extract path if (p_path != NULL) { (*info) = strtok(NULL,""); // rest is information field if ((*info) != NULL) // the above looks dangerous, but works on same string if (strlen(p_path) < 100) { ok = 1; // we have found all three components } } } } if ((debug_level & 1) && !ok) { fprintf(stderr,"extract_third_party: invalid format from %s\n",call); } if (ok) { xastir_snprintf(path, path_size, "%s", p_path); ok = valid_path(path); // check the path and convert it to TAPR format // Note that valid_path() also removes igate injection identifiers if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", path); makePrintable(filtered_data); fprintf(stderr,"extract_third_party: invalid path: %s\n",filtered_data); } } if (ok) // check callsign { (void)remove_trailing_asterisk(p_call); // is an asterisk valid here ??? if (valid_inet_name(p_call,(*info),origin,origin_size)) // accept some of the names used in internet { // Treat it as object with special origin xastir_snprintf(call, MAX_CALLSIGN+1, "%s", p_call); } else if (valid_call(p_call)) // accept real AX.25 calls { xastir_snprintf(call, MAX_CALLSIGN+1, "%s", p_call); } else { ok = 0; if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", p_call); makePrintable(filtered_data); fprintf(stderr,"extract_third_party: invalid call: %s\n",filtered_data); } } } return(ok); } /* * Extract text inserted by TNC X-1J4 from start of info line */ void extract_TNC_text(char *info) { int i,j,len; if (strncasecmp(info,"thenet ",7) == 0) // 1st match { len = strlen(info)-1; for (i=7; i7 && info[i] == ')' && info[i+1] == ' ') // found { i += 2; for (j=0; i<=len; i++,j++) { info[j] = info[i]; } } } } //WE7U2 // We feed a raw 7-byte string into this routine. It decodes the // callsign-SSID and tells us whether there are more callsigns after // this. If the "asterisk" input parameter is nonzero it'll add an // asterisk to the callsign if it has been digipeated. This // function is called by the decode_ax25_header() function. // // Inputs: string Raw input string // asterisk 1 = add "digipeated" asterisk // // Outputs: callsign Processed string // returned int 1=more callsigns follow, 0=end of address field // int decode_ax25_address(char *string, char *callsign, int asterisk) { int i,j; char ssid; char t; int more = 0; int digipeated = 0; // Shift each of the six callsign characters right one bit to // convert to ASCII. We also get rid of the extra spaces here. j = 0; for (i = 0; i < 6; i++) { t = ((unsigned char)string[i] >> 1) & 0x7f; if (t != ' ') { callsign[j++] = t; } } // Snag out the SSID byte to play with. We need more than just // the 4 SSID bits out of it. ssid = (unsigned char)string[6]; // Check the digipeat bit if ( (ssid & 0x80) && asterisk) { digipeated++; // Has been digipeated } // Check whether it is the end of the address field if ( !(ssid & 0x01) ) { more++; // More callsigns to come after this one } // Snag the four SSID bits ssid = (ssid >> 1) & 0x0f; // Construct the SSID number and add it to the end of the // callsign if non-zero. If it's zero we don't add it. if (ssid) { callsign[j++] = '-'; if (ssid > 9) { callsign[j++] = '1'; } ssid = ssid % 10; callsign[j++] = '0' + ssid; } // Add an asterisk if the packet has been digipeated through // this callsign if (digipeated) { callsign[j++] = '*'; } // Terminate the string callsign[j] = '\0'; return(more); } // Function which receives raw AX.25 packets from a KISS interface and // converts them to a printable TAPR-2 (more or less) style string. // We receive the packet with a KISS Frame End character at the // beginning and a "\0" character at the end. We can end up with // multiple asterisks, one for each callsign that the packet was // digipeated through. A few other TNC's put out this same sort of // format. // // Note about KISS & CRC's: The TNC checks the CRC. If bad, it // drops the packet. If good, it sends it to the computer WITHOUT // the CRC bytes. There's no way at the computer end to check // whether the packet was corrupted over the serial channel between // the TNC and the computer. Upon sending a KISS packet to the TNC, // the TNC itself adds the CRC bytes back on before sending it over // the air. In Xastir we can just assume that we're getting // error-free packets from the TNC, ignoring possible corruption // over the serial line. // // Some versions of KISS can encode the radio channel (for // multi-port TNC's) in the command byte. How do we know we're // running those versions of KISS though? Here are the KISS // variants that I've been able to discover to date: // // KISS No CRC, one radio port // // SMACK 16-bit CRC, multiport TNC's // // KISS-CRC // // 6-PACK // // KISS Multi-drop (Kantronics) 8-bit XOR Checksum, multiport TNC's (AGWPE compatible) // BPQKISS (Multi-drop) 8-bit XOR Checksum, multiport TNC's // XKISS (Kantronics) 8-bit XOR Checksum, multiport TNC's // // JKISS (AGWPE and BPQ32 compatible) // // MKISS Linux driver which supports KISS/BPQ and // hardware handshaking? Also Paccomm command to // immediately enter KISS mode. // // FlexKISS -, // FlexCRC -|-- These are all the same! // RMNC-KISS -| // CRC-RMNC -' // // // It appears that none of the above protocols implement any form of // hardware flow control. // // // Compare this function with interface.c:process_ax25_packet() to // see if we're missing anything important. // // // Inputs: data_string Raw string (must be MAX_LINE_SIZE or bigger) // length Length of raw string (may get changed here) // // Outputs: int 0 if it is a bad packet, // 1 if it is good // data_string Processed string // int decode_ax25_header(unsigned char *data_string, int *length) { char temp[20]; char result[MAX_LINE_SIZE+100]; char dest[15]; int i, ptr; char callsign[15]; char more; char num_digis = 0; // Do we have a string at all? if (data_string == NULL) { return(0); } // Drop the packet if it is too long. Note that for KISS packets // we can't use strlen() as there can be 0x00 bytes in the // data itself. if (*length > 1024) { data_string[0] = '\0'; *length = 0; return(0); } // Start with an empty string for the result result[0] = '\0'; ptr = 0; // Process the destination address for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 0); // No asterisk xastir_snprintf(dest,sizeof(dest),"%s",callsign); // Process the source address for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 0); // No asterisk // Store the two callsigns we have into "result" in the correct // order xastir_snprintf(result,sizeof(result),"%s>%s",callsign,dest); // Process the digipeater addresses (if any) num_digis = 0; while (more && num_digis < 8) { for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 1); // Add asterisk strncat(result, ",", sizeof(result) - 1 - strlen(result)); strncat(result, callsign, sizeof(result) - 1 - strlen(result)); num_digis++; } strncat(result, ":", sizeof(result) - 1 - strlen(result)); // Check the Control and PID bytes and toss packets that are // AX.25 connect/disconnect or information packets. We only // want to process UI packets in Xastir. // Control byte should be 0x03 (UI Frame). Strip the poll-bit // from the PID byte before doing the comparison. if ( (data_string[ptr++] & (~0x10)) != 0x03) { return(0); } // PID byte should be 0xf0 (normal AX.25 text) if (data_string[ptr++] != 0xf0) { return(0); } // WE7U: We get multiple concatenated KISS packets sometimes. Look // for that here and flag when it happens (so we know about it and // can fix it someplace earlier in the process). Correct the // current packet so we don't get the extra garbage tacked onto the // end. for (i = ptr; i < *length; i++) { if (data_string[i] == KISS_FEND) { fprintf(stderr,"***Found concatenated KISS packets:***\n"); data_string[i] = '\0'; // Truncate the string break; } } // Add the Info field to the decoded header info strncat(result, (char *)(&data_string[ptr]), sizeof(result) - 1 - strlen(result)); // Copy the result onto the top of the input data. Note that // the length can sometimes be longer than the input string, so // we can't just use the "length" variable here or we'll // truncate our string. Make sure the data_string variable is // MAX_LINE_SIZE or bigger. // memcpy(data_string, result, MAX_LINE_SIZE); data_string[MAX_LINE_SIZE-1] = '\0'; // Terminate string // Write out the new length *length = strlen(result); //fprintf(stderr,"%s\n",data_string); return(1); } // RELAY the packet back out onto RF if received on a port with // digipeat enabled and the packet header has a non-digipeated RELAY // or my_callsign entry. This is for AX.25 kernel networking ports // or Serial KISS TNC ports only: Regular serial TNC's have these // features enabled/disabled through the startup/shutdown files. // // Adding asterisks: // Keep whatever digipeated fields have already been set. If // there's a "RELAY", "WIDE1-1", or "my_callsign" entry that hasn't // been digipeated yet, change it to "my_callsign*". // // This might be much easier to code into the routine that first // receives the packet (for Serial KISS TNC's). There we'd have // access to every digipeated bit directly instead of parsing // asterisks out of a string. // // NOTE: We don't handle this case properly: Multiple // RELAY's/WIDE1-1's or my_callsign's in the path, where one of the // earlier matching callsigns has been digipeated, but a later one // has not. We'll find the first matching callsign and the last // digi, and we won't relay the packet. This probably won't happen // much in the real world. // // We could also do preemptive digipeating here and skip over // callsigns that haven't been digipeated yet. Should we set the // digipeated bits on everything before it? Probably. Either that // or remove the callsigns ahead of it in the list that weren't // digipeated. // void relay_digipeat(char *call, char *path, char *info, int port) { char new_path[110+1]; char new_digi[MAX_CALLSIGN+2]; // Need extra for '*' storage int ii, jj; int done; char destination[MAX_CALLSIGN+1]; #define MAX_RELAY_SUBSTRINGS 10 char *Substring[MAX_RELAY_SUBSTRINGS]; // Pointers to substrings parsed by split_string() // Pointers to all of the possible calls we with to digipeat by char *Relay_Calls[MAX_RELAY_DIGIPEATER_CALLS]; char temp_string[MAX_LINE_SIZE+1]; // Check whether transmits are disabled globally if (transmit_disable) { return; } // Check whether relay_digipeat has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].relay_digipeat != 1) { return; } // Check whether transmit has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].transmit_data != 1) { return; } // Check for the only four types of interfaces where we might // want to do RELAY digipeating. If not one of these, go // bye-bye. if ( (devices[port].device_type != DEVICE_SERIAL_KISS_TNC) && (devices[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (devices[port].device_type != DEVICE_AX25_TNC) && (devices[port].device_type != DEVICE_NET_AGWPE) ) { return; } // Check to see if this is my own transmitted packet (in some // cases you get your own packets back from interfaces) if (!strcasecmp(call, my_callsign)) { //fprintf(stderr,"relay_digipeat: packet was mine, don't digipeat it!\n"); return; } // Make a copy of the incoming path. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", path); split_string(temp_string, Substring, MAX_RELAY_SUBSTRINGS, ','); // Each element in the path is now pointed to by a char ptr in // the Substring array. If a NULL is found in the array, that's // the end of the path. if (Substring[0] == NULL) { // Something's wrong! Couldn't find anything in the path // string, not even a destination callsign? //fprintf(stderr, "\t\tNo path: %s\n", path); return; } else // Save the destination callsign away { xastir_snprintf(destination, sizeof(destination), "%s", Substring[0]); //fprintf(stderr,"Destination: %s\n",destination); } // We'll skip the first call in the path (pointed to by // Substring[0]) in the loops below. That's the destination // call and we don't want to look for RELAY or my_callsign // there. // Check to see if we just ran out of path if (Substring[1] == NULL) // No digipeaters listed { //fprintf(stderr,"relay_digipeat: ran out of path, don't digipeat it!\n"); //fprintf(stderr, "\t\tNo digi's listed: %s\n", path); return; } //fprintf(stderr," Path: %s\n",path); // We could also loop through the array and dump them out until // we hit a NULL if necessary. // Find the first digipeater callsign _after_ any digis that // have asterisks. Run through the array in reverse, looking // for the digi callsign with an asterisk after it that's // closest to the end of the path. ii = MAX_RELAY_SUBSTRINGS - 1; done = 0; while (!done && ii > 0) { if (Substring[ii] != NULL) { if (strstr(Substring[ii],"*")) { ii++; // Found an asterisk: Used digi. Point to // the digi _after_ this one. done++; // We found what we're looking for! } else // No asterisk found yet. { ii--; } } else // No filled-in digipeater field found yet. { ii--; } } if (ii == 0) // No asterisks found. Entire path unused? { // Set ii to first actual digi field instead of the // destination callsign. ii = 1; } else // ii points to first unused digi field. { } if (Substring[ii] == NULL) // No unused digi's found. { // We're done here. //fprintf(stderr, "\t\tPath used up: %s\n", path); return; } //fprintf(stderr,"\t\tUnused digi: %s\tPath: %s\n", Substring[ii], path); // Split the relay digipeater calls into separate substrings. // Split on comma delimiters. We get rid of extra spaces at the // point where we read the string in from the config file // (xa_config.c), so spaces between the calls are ok (but not // tabs). split_string(relay_digipeater_calls, Relay_Calls, MAX_RELAY_DIGIPEATER_CALLS, ','); // Check for match against my_callsign in this digipeater slot done = 0; if (strcmp(Substring[ii], my_callsign) == 0) { // It's our callsign. Digipeat using this call slot. done++; } else // Not my_callsign. Check every non-empty string in { // Relay_Calls[] for a match. jj = 0; while (!done && jj < MAX_RELAY_DIGIPEATER_CALLS) { // Check for ending conditions if (Relay_Calls[jj] == NULL || Relay_Calls[jj][0] == '\0') { // We hit the end of the array of possible // digipeater calls and had no match. Exit from // this routine as we're not going to digipeat on // this callsign slot. // Later we could add the option of "preemptive digipeating", where // we look further down the path for a possible match. We're not // doing that now. // fprintf(stderr,"End of Relay_Calls array: %d\n",jj); return; } // If we made it to here, we should have a valid // digipeater callsign in the Relay_Calls[jj] slot to // compare against. if (debug_level & 1) { fprintf(stderr,"\tComparing %s to %s\n", Substring[ii], Relay_Calls[jj]); } if (strcmp(Substring[ii], Relay_Calls[jj]) == 0) { done++; // fprintf(stderr,"match, done++\n"); } else { jj++; // fprintf(stderr,"incrementing jj: %d\n", jj); } } } if (!done) { // No valid digipeating callsign found in this slot, exit // this routine as we're not going to digipeat this packet. return; } /* OLD CODE: // Check for RELAY, WIDE1-1 (the new relay) or my_callsign in // this digipeater slot. If none of these found then exit this // routine. if ( (strcmp(Substring[ii], "RELAY") != 0) && (strcmp(Substring[ii], "WIDE1-1") != 0) && (strcmp(Substring[ii], my_callsign) != 0) ) { // Some other callsign found in this digi field. Don't // relay the packet. //fprintf(stderr,"Not relay, wide1-1, or %s, skipping\n", my_callsign); return; } */ // Ok, we made it! We have RELAY, WIDE1-1, or my_callsign that // hasn't been digipeated through, and we wish to change that // fact. Put in our callsign for all three cases and add an // asterisk to the end of the call. Also had to fix up the KISS // transmit routine so that it'll set the digipeated bit for // each callsign that has an asterisk. // Construct the new digi call, with the trailing asterisk xastir_snprintf(new_digi, sizeof(new_digi), "%s*", my_callsign); Substring[ii] = new_digi; // Point to new digi string instead of old //fprintf(stderr,"*** new_digi: %s\tSubstring: %s\n", // new_digi, // Substring[ii]); // Construct the new path, substituting the correct portion. // Start with the first digi and a comma: xastir_snprintf(new_path, sizeof(new_path), "%s,", Substring[1]); ii = 2; while ( (Substring[ii] != NULL) && (ii < MAX_RELAY_SUBSTRINGS) ) { strncat(new_path, Substring[ii], sizeof(new_path) - 1 - strlen(new_path)); ii++; if (Substring[ii] != NULL) // Add a comma if more to come strncat(new_path, ",", sizeof(new_path) - 1 - strlen(new_path)); } //fprintf(stderr,"*** New Path: %s,%s\n", destination, new_path); if ( (devices[port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { #ifdef SERIAL_KISS_RELAY_DIGI // fprintf(stderr,"KISS RELAY short_path: %s\n", short_path); // fprintf(stderr,"KISS RELAY new_path: %s\n", new_path); send_ax25_frame(port, call, destination, new_path, info); #endif } else if (devices[port].device_type == DEVICE_AX25_TNC) { char header_txt[MAX_LINE_SIZE+5]; //fprintf(stderr,"AX25 RELAY new_path: %s\n", new_path); // set from call xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s\r", '\3', "MYCALL", call); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // set path xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", destination, new_path); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // set converse mode xastir_snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', "CONV"); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // send packet if (port_data[port].status == DEVICE_UP) { port_write_string(port, info); } } else if (devices[port].device_type == DEVICE_NET_AGWPE) { send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string), // AGWPE RadioPort '\0', // Type of frame (data) (unsigned char *)call, // source (unsigned char *)destination, // destination (unsigned char *)new_path, // Path, (unsigned char *)info, strlen(info)); } } /* * Decode AX.25 line * \r and \n should already be stripped from end of line * line should not be NULL * * If dbadd is set, add to database. Otherwise, just return true/false * to indicate whether input is valid AX25 line. */ // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // int decode_ax25_line(char *line, char from, int port, int dbadd) { char *call_sign; char *path0; char path[100+1]; // new one, we may add an '*' char *info; char info_copy[MAX_LINE_SIZE+1]; char call[MAX_CALLSIGN+1]; char origin[MAX_CALLSIGN+1]; int ok; int third_party; char backup[MAX_LINE_SIZE+1]; char tmp_line[MAX_LINE_SIZE+1]; char tmp_line2[630]; char tmp_path[100+1]; char *ViaCalls[10]; // Check guard band around pointers. Make sure it's pristine. if ( check_guard_band() ) { fprintf(stderr, "WARNING: Guard band around global pointers was corrupted!\n"); } xastir_snprintf(backup, sizeof(backup), "%s", line); // This is a good one to enable for debugging without getting too // many other types of messages to the xterm. It will enable the // block below. //#define WE7U_DEBUG #ifndef WE7U_DEBUG if (debug_level & 1) #endif { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", line); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: start parsing %s\n", filtered_data); } if (line == NULL) { fprintf(stderr,"decode_ax25_line: line == NULL.\n"); return(FALSE); } if ( (line != NULL) && (strlen(line) > MAX_LINE_SIZE) ) // Overly long message, throw it away. We're done. { if (debug_level & 1) { fprintf(stderr,"\ndecode_ax25_line: LONG packet. Dumping it:\n%s\n",line); } return(FALSE); } if (line[strlen(line)-1] == '\n') // better: look at other places, // so that we don't get it here... { line[strlen(line)-1] = '\0'; // Wipe out '\n', to be sure } if (line[strlen(line)-1] == '\r') { line[strlen(line)-1] = '\0'; // Wipe out '\r' } call_sign = NULL; path0 = NULL; info = NULL; origin[0] = '\0'; call[0] = '\0'; path[0] = '\0'; third_party = 0; // CALL>PATH:APRS-INFO-FIELD // split line into components // ^ ^ ok = 0; call_sign = strtok(line,">"); // extract call from AX.25 line if (call_sign != NULL) { path0 = strtok(NULL,":"); // extract path from AX.25 line if (path0 != NULL) { info = strtok(NULL,""); // rest is info_field if (info != NULL) { if ((info - path0) < 100) // check if path could be copied { ok = 1; // we have found all three components } } } } if (ok) { xastir_snprintf(path, sizeof(path), "%s", path0); memset(info_copy, '\0', sizeof(info_copy)); xastir_snprintf(info_copy, sizeof(info_copy), "%s", info); ok = valid_path(path); // check the path and convert it to TAPR format // Note that valid_path() also removes igate injection identifiers if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", path); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: invalid path: %s\n",filtered_data); } } if (ok) { // If it's not me transmitting it: if (strcmp(my_callsign,call_sign) != 0) { // Check for "EMERGENCY" anywhere in the line. // APRS+SA also supports any of these in the TO: field: // // EMERGENCY // ALARM // ALERT // WARNING // WXALARM // EM // // Snag just the TO: field from the path, used for most of the // comparisons below. It will be pointed to by ViaCalls[0]; xastir_snprintf(tmp_path, // Make a temporary backup sizeof(tmp_path), "%s", path); split_string(tmp_path, ViaCalls, 10, ','); if ( (strstr(backup, "EMERGENCY")) // Checks entire line || (strcmp(ViaCalls[0], "ALARM") == 0) // Checks to_field || (strcmp(ViaCalls[0], "ALERT") == 0) // Checks to_field || (strcmp(ViaCalls[0], "WARNING") == 0) // Checks to_field || (strcmp(ViaCalls[0], "WXALARM") == 0) // Checks to_field || (strcmp(ViaCalls[0], "EM") == 0) ) // Checks to_field { double distance; // miles or km char course_deg[5]; // EMERGENCY if (emergency_distance_check) { distance = distance_from_my_station(call_sign, course_deg); // Because of the distance check we have to receive a valid position // from the station BEFORE we process the EMERGENCY portion and // check distance, doing the popups. We need to figure out a way to // throw the packet back into the queue if it was an emergency // packet so that we process these packets twice each. That way // only one packet from the emergency station is required to // generate the popups. if (distance == 0.0) { process_emergency_packet_again++; } // Check whether the station is near enough to // us to require that we alert on the packet. // // This may be slightly controversial, but if we // don't know WHERE a station is, we can't help // much in an emergency, can we? The // zero-distance check helps in the case where // we haven't yet or never get a position packet // for a station. As soon as we have a position // and it is within a reasonable range, we do // our emergency popups. // if ( distance != 0.0 && (float)distance <= emergency_range ) { // Do the conversion for emergency_range to mi or km as needed. // if (english_units) { // } // else { // } // Do a popup to alert the operator to this // condition. Make sure we haven't popped // up an emergency message for this station // within the last 30 minutes. If we pop // these up constantly it gets quite // annoying. if ( (strncmp(call_sign, last_emergency_callsign, strlen(call_sign)) != 0) || ((last_emergency_time + 60*30) < sec_now()) ) { char temp[50]; char temp2[150]; char temp3[300]; char timestring[101]; // Callsign is different or enough time // has passed last_emergency_time = sec_now(); xastir_snprintf(last_emergency_callsign, sizeof(last_emergency_callsign), "%s", call_sign); // Bring up the Find Station dialog so // that the operator can go to the // location quickly. xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", call_sign); Locate_station( (Widget)NULL, (XtPointer)NULL, (XtPointer)1 ); // Bring up an additional popup dialog // that shows the entire packet, so the // user can make a determination as to // whether the packet is or is not a // real emergency. // popup_message_always(langcode("POPEM00036"), backup); // Bring up another dialog with the // callsign plus distance/bearing to the // station. xastir_snprintf(temp, sizeof(temp), "%0.1f", distance); xastir_snprintf(temp2, sizeof(temp2), langcode("WPUPSTI022"), temp, course_deg); get_timestamp(timestring); xastir_snprintf(temp3, sizeof(temp3), "%s %s", timestring, temp2); popup_message_always(call_sign, temp3); } } } } } } if (ok) { // Attempt to digipeat this packet if we should. If port=-2, // we received this packet from the x_spider server and we // should not attempt to digipeat it. If port=-1, it's from // a log file. Again, don't digipeat it. if (port >= 0) { relay_digipeat(call_sign, path, info, port); } extract_TNC_text(info); // extract leading text from TNC X-1J4 if (strlen(info) > 256) // first check if information field conforms to APRS specs { ok = 0; // drop packets too long } if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", info); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: info field too long: %s\n",filtered_data); } } if (ok) // check callsign { (void)remove_trailing_asterisk(call_sign); // is an asterisk valid here ??? if (valid_inet_name(call_sign,info,origin,sizeof(origin))) // accept some of the names used in internet { xastir_snprintf(call, sizeof(call), "%s", call_sign); } else if (valid_call(call_sign)) // accept real AX.25 calls { xastir_snprintf(call, sizeof(call), "%s", call_sign); } else { ok = 0; if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call_sign); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: invalid call: %s\n",filtered_data); } } } if (!dbadd) { if (debug_level & 1) { fprintf(stderr,"decode_ax25_line: exiting\n"); } return(ok); } if (ok && info[0] == '}') // look for third-party traffic { ok = extract_third_party(call,path,sizeof(path),&info,origin,sizeof(origin)); // extract third-party data third_party = 1; // Add it to the HEARD queue for this interface. We use this // for igating purposes. If some other igate beat us to this // packet, we don't want to duplicate it over the air. If // port=-2, we received it from the x_spider server and we // should not save it in the queue. If port=-1, the packet // came from a log file and again we shouldn't save it to // the queue. if (port >= 0) { insert_into_heard_queue(port, backup); } } if (ok && (info[0] == ';' || info[0] == ')')) // look for objects or items { xastir_snprintf(origin, sizeof(origin), "%s", call); ok = extract_object(call,&info,origin); // extract object data } if (ok) { // decode APRS information field, always called with valid call and path // info is a string with 0 - 256 bytes // fprintf(stderr,"dec: %s (%s) %s\n",call,origin,info); if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+80]; sprintf(filtered_data, "Registering data %s %s %s %s %c %d %d", call, path, info, origin, from, port, third_party); makePrintable(filtered_data); fprintf(stderr,"c/p/i/o fr pt tp: %s\n", filtered_data); } decode_info_field(call, path, info, origin, from, port, third_party, info_copy); } if (port == -2) // We received this packet from an x_spider { // server. We need to dump it out all of our // transmit-enabled ports. // If the string starts with "user" or "pass", it's an // authentication string. We need to send those through as // well so that the user gets logged into the internet // server and can send/receive packets/messages. We also // dump it to our console so that we can see who logged in // to us. if (strncasecmp(line,"user",4) == 0 || strncasecmp(line,"pass",4) == 0 || strncasecmp(line,"filter",6) == 0) { fprintf(stderr,"\tLogged on: %s\n", line); // If the line has a "filter" parameter in it, we need to remove it, // else a client may change our filtering parameters. Perhaps we // should skip the authentication stuff as well, as the servers // might get confused if we pass two different authentications on // the same socket? } else if (strlen(line) > 0) // Not empty { // Send the packet unchanged out all of our // transmit-enabled ports. We should send it as // third-party igated packets if we're sending to // servers, send it unchanged if sending through TNC? //fprintf(stderr,"Retransmitting x_spider packet: %s\n", line); // Here's where we inject our own callsign like this: // "WE7U-15,I" in order to provide injection ID for our // igate. xastir_snprintf(tmp_line2, sizeof(tmp_line2), "%s>%s,%s,I:%s", call_sign, path, my_callsign, info_copy); memcpy(tmp_line, tmp_line2, sizeof(tmp_line)); tmp_line[sizeof(tmp_line)-1] = '\0'; // Terminate line //fprintf(stderr,"decode_ax25_line: IGATE>NET %s\n",tmp_line); //fprintf(stderr,"call: %s\tcall_sign: %s\n", call, call_sign); output_igate_net(tmp_line, port, 0); // 0="not third-party" } } // EMERGENCY // For emergency packets we need to process them twice, to try // to get a position before we do the distance check. // // This causes an infinite loop on packets that don't have a // distance! Disabling it for now. if (process_emergency_packet_again) { process_emergency_packet_again = 0; //fprintf(stderr,"Again: %s\n", backup); // decode_ax25_line(backup, from, port, dbadd); } if (debug_level & 1) { fprintf(stderr,"decode_ax25_line: exiting\n"); } return(ok); } /* * Read a line from file. We use this to read in log files and to * read in findu track files. For findu track files we need to get * rid of the
at the end of the lines, else it shows up in our * comment lines in Station_info. */ void read_file_line(FILE *f) { char line[MAX_LINE_SIZE+1]; char cin; int pos; pos = 0; line[0] = '\0'; while (!feof(f)) { if (fread(&cin,1,1,f) == 1) { if (cin != (char)10 && cin != (char)13) // normal characters { if (pos < MAX_LINE_SIZE) { line[pos++] = cin; } } else // CR or LF { if (cin == (char)10) // Found LF as EOL char { char *ptr; line[pos] = '\0'; // Always add a terminating zero after last char pos = 0; // start next line // Get rid of
HTML tag at end of line here. // Findu track files have them. ptr = strstr(line, "
"); if (ptr) // Found one of them { *ptr = '\0'; // Terminate the line at that point } // Save backup copies of this string and the // previous string. Used for debugging // purposes. If we get a segfault, we can print // out the last two messages received. memcpy(incoming_data_copy_previous, incoming_data_copy, MAX_LINE_SIZE); incoming_data_copy_previous[MAX_LINE_SIZE-1] = '\0'; // Terminate string memcpy(incoming_data_copy, line, MAX_LINE_SIZE); incoming_data_copy[MAX_LINE_SIZE-1] = '\0'; // Terminate string if (line[0] != '#') { decode_ax25_line(line,'F',-1, 1); // Decode the packet } return; // only read line by line } } } } if (feof(f)) // Close file if at the end { (void)fclose(f); read_file = 0; statusline(langcode("BBARSTA012"),0); // File done.. redraw_on_new_data = 2; // redraw immediately after finish } } /* * Center map to new position */ void set_map_position(Widget UNUSED(w), long lat, long lon) { // see also map_pos() in location.c // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; set_last_position(); center_latitude = lat; center_longitude = lon; setup_in_view(); // flag all stations in new screen view // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(w)) { // (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } /* * Search for a station to be located (for Tracking and Find Station) */ int locate_station(Widget w, char *call, int follow_case, int get_match, int center_map) { DataRow *p_station; char call_find[MAX_CALLSIGN+1]; char call_find1[MAX_CALLSIGN+1]; int ii; if (!follow_case) { for (ii=0; ii<(int)strlen(call); ii++) { if (isalpha((int)call[ii])) { call_find[ii] = toupper((int)call[ii]); // Problem with lowercase objects/names!! } else { call_find[ii] = call[ii]; } } call_find[ii] = '\0'; xastir_snprintf(call_find1, sizeof(call_find1), "%s", call_find); } else xastir_snprintf(call_find1, sizeof(call_find1), "%s", call); if (search_station_name(&p_station,call_find1,get_match)) { if (position_defined(p_station->coord_lat,p_station->coord_lon,0)) { if (center_map || !position_on_inner_screen(p_station->coord_lat,p_station->coord_lon)) // only change map if really necessary { set_map_position(w, p_station->coord_lat, p_station->coord_lon); } return(1); // we found it } } return(0); } /* * Look for other stations that the tracked one has gotten close to. * and speak a proximity warning. * TODO: * - sort matches by distance * - set upper bound on number of matches so we don't speak forever * - use different proximity distances for different station types? * - look for proximity to embedded map objects */ void search_tracked_station(DataRow **p_tracked) { DataRow *t = (*p_tracked); DataRow *curr = NULL; if (debug_level & 1) { char lat[20],lon[20]; convert_lat_l2s(t->coord_lat, lat, sizeof(lat), CONVERT_HP_NORMAL); convert_lon_l2s(t->coord_lon, lon, sizeof(lat), CONVERT_HP_NORMAL); fprintf(stderr,"Searching for stations close to tracked station %s at %s %s ...\n", t->call_sign,lat,lon); } while (next_station_time(&curr)) { if (curr != t && curr->flag&ST_ACTIVE) { float distance; // Distance in whatever measurement // units we're currently using. char bearing[10]; char station_id[600]; distance = (float)calc_distance_course(t->coord_lat, t->coord_lon, curr->coord_lat, curr->coord_lon, bearing, sizeof(bearing)) * cvt_kn2len; if (debug_level & 1) fprintf(stderr,"Looking at %s: distance %.3f bearing %s (%s)\n", curr->call_sign,distance,bearing,convert_bearing_to_name(bearing,1)); /* check ranges (copied from earlier prox alert code, above) */ if ((distance > atof(prox_min)) && (distance < atof(prox_max))) { if (debug_level & 1) { fprintf(stderr," tracked station is near %s!\n",curr->call_sign); } if (sound_play_prox_message) { sprintf(station_id,"%s < %.3f %s from %s",t->call_sign, distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), curr->call_sign); statusline(station_id,0); play_sound(sound_command,sound_prox_message); } #ifdef HAVE_FESTIVAL if (festival_speak_tracked_proximity_alert) { if (english_units) { if (distance < 1.0) sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance * 1760), langcode("SPCHSTR004"), convert_bearing_to_name(bearing,1), curr->call_sign); else if ((int)((distance * 10) + 0.5) % 10) sprintf(station_id, langcode("SPCHSTR008"), t->call_sign, distance, langcode("SPCHSTR003"), convert_bearing_to_name(bearing,1), curr->call_sign); else sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance + 0.5), langcode("SPCHSTR003"), convert_bearing_to_name(bearing,1), curr->call_sign); } else /* metric */ { if (distance < 1.0) sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance * 1000), langcode("SPCHSTR002"), convert_bearing_to_name(bearing,1), curr->call_sign); else if ((int)((distance * 10) + 0.5) % 10) sprintf(station_id, langcode("SPCHSTR008"), t->call_sign, distance, langcode("SPCHSTR001"), convert_bearing_to_name(bearing,1), curr->call_sign); else sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance + 0.5), langcode("SPCHSTR001"), convert_bearing_to_name(bearing,1), curr->call_sign); } if (debug_level & 1) { fprintf(stderr," %s\n",station_id); } SayText(station_id); } #endif /* HAVE_FESTIVAL */ } } } // end of while } /* * Change map position if necessary while tracking a station * we call it with defined station call and position */ void track_station(Widget w, char * UNUSED(call_tracked), DataRow *p_station) { long x_ofs, y_ofs; long new_lat, new_lon; if ( is_tracked_station(p_station->call_sign) ) // We want to track this station { new_lat = p_station->coord_lat; // center map to station position as default new_lon = p_station->coord_lon; x_ofs = new_lon - center_longitude; // current offset from screen center y_ofs = new_lat - center_latitude; if ((labs(x_ofs) > (screen_width*scale_x/3)) || (labs(y_ofs) > (screen_height*scale_y/3))) { // only redraw map if near border (margin 1/6 of screen at each side) if (labs(y_ofs) < (screen_height*scale_y/2)) { new_lat += y_ofs/2; // give more space in driving direction } if (labs(x_ofs) < (screen_width*scale_x/2)) { new_lon += x_ofs/2; } set_map_position(w, new_lat, new_lon); // center map to new position } search_tracked_station(&p_station); } } // ******************************************************************** // calc aloha_distance() // calculate and return alhoa circle radius in current distance units // The ALOHA radius is computed according to the algorithm described by // Bob Bruninga at http://web.usna.navy.mil/~bruninga/aprs/ALOHAcir.txt // with some clarification provided py private email. // // The gist of it is that we grab a list of all stations heard via TNC // and sort it b distance from our station. We then accumulate a // count of how many theoretical packets would be introduced into the local // area in 30 minutes from these stations, and stop when we hit 1800 // (the supposed limit of the channel capacity). The distance to the last // station we counted is our ALOHA limit. Per Bob B., this should be plotted // on the map as a circle with no user-selectable way of turning it off. // double calc_aloha_distance(void) { DataRow *p_station = n_first; // walk in alphabetical order aloha_entry *aloha_array; aloha_entry *temp_aloha_array; int num_aloha_alloc=1000; int num_aloha_entries=0; int digi_copies=1; char temp[10]; // needed for course_deg argument of // distance_from_my_station int sum; double distance; int ii; // This should be enough, though we'll realloc if necessary aloha_array = (aloha_entry *)malloc (num_aloha_alloc*sizeof(aloha_entry)); CHECKMALLOC(aloha_array); // We need a list of all stations that were heard via tnc: while (p_station != NULL) { if (num_aloha_entries == num_aloha_alloc) { num_aloha_alloc *= 2; temp_aloha_array=realloc(aloha_array,num_aloha_alloc); if (temp_aloha_array) { aloha_array=temp_aloha_array; } else { fprintf(stderr,"***** Realloc failed *****\n"); exit(1); } } if ( (p_station->flag & ST_VIATNC) != 0 && (p_station->flag & ST_ACTIVE) != 0 ) { if (position_defined(p_station->coord_lat,p_station->coord_lon,1)) { xastir_snprintf(aloha_array[num_aloha_entries].call_sign, MAX_CALLSIGN+1, "%s", p_station->call_sign); aloha_array[num_aloha_entries].is_digi = aloha_array[num_aloha_entries].is_mobile = aloha_array[num_aloha_entries].is_other_mobile = aloha_array[num_aloha_entries].is_home = aloha_array[num_aloha_entries].is_wx = (char) FALSE; aloha_array[num_aloha_entries].distance = distance_from_my_station(p_station->call_sign,temp); if ( p_station->newest_trackpoint != NULL && strlen(p_station->speed) > 0) { // If the station has a track and a speed of any value // (even zero), it's a mobile. aloha_array[num_aloha_entries].is_mobile = (char) TRUE; } else if ( (p_station->aprs_symbol.aprs_type=='/' && (strchr("'<=>()*0COPRSUXY[^abefgjkpsuv", p_station->aprs_symbol.aprs_symbol) != NULL)) || (p_station->aprs_symbol.aprs_type=='\\' && (strchr("/0>AKOS^knsuv", p_station->aprs_symbol.aprs_symbol) != NULL))) { // // Per private email exchange with Bob Bruninga: // If the station has one of these symbols, // it's "other mobile" // these are also listed on // web.usna.navy.mil/~bruninga/aprs/aprs11.html // aloha_array[num_aloha_entries].is_other_mobile =(char)TRUE; } else if ( p_station-> record_type == APRS_WX1 || p_station-> record_type == APRS_WX2 || p_station-> record_type == APRS_WX3 || p_station-> record_type == APRS_WX4 || p_station-> record_type == APRS_WX5 || p_station-> record_type == APRS_WX6 || p_station-> aprs_symbol.aprs_symbol=='_') { // Bob B. uses the station symbol "_" to select this, but // agrees that if we do it this way it's probably better // -- this says if we've gotten any WX data, it's a WX // station aloha_array[num_aloha_entries].is_wx = (char) TRUE; } else if (p_station->aprs_symbol.aprs_symbol=='#') { // Per Bob B., if it has "#" as its symbol, it's // assumed to be a digi. aloha_array[num_aloha_entries].is_digi = (char) TRUE; } else { // Anything that hasn't gotten selected yet is just a home aloha_array[num_aloha_entries].is_home = (char) TRUE; } num_aloha_entries++; } } p_station = p_station-> n_next; } if (debug_level & 2048) { fprintf (stderr,"aloha_distance: Found %d local stations\n", num_aloha_entries); } // we now have all the stations heard via TNC. Now sort it by distance qsort((void *) aloha_array,num_aloha_entries,sizeof(aloha_entry), comp_by_dist); // Starting from the closest, working outward, accumulate sum=0; the_aloha_stats.digis=0; the_aloha_stats.wxs = 0; the_aloha_stats.other_mobiles = 0; the_aloha_stats.mobiles_in_motion = 0; the_aloha_stats.homes = 0; the_aloha_stats.total = 0; for (ii=0; (ii0 && ii < num_aloha_entries && sum >= 1800) // we hit the limit { distance = aloha_array[ii-1].distance; } else { distance = -1; // indeterminate, not enough data yet } free (aloha_array); // make sure we don't leak return distance; } // Used by qsort to sort the aloha entries int comp_by_dist(const void *av,const void *bv) { aloha_entry *a = (aloha_entry *) av; aloha_entry *b = (aloha_entry *) bv; if (a->distance < b->distance) { return -1; } if (a->distance > b->distance) { return 1; } return 0; } // Called periodically by UpdateTime, we calculate our aloha radius every // so often. (Bob B. recommends every 30 minutes) void calc_aloha(int secs_now) { char status_text[100]; if (aloha_time == 0) // first call { aloha_time = secs_now+ALOHA_CALC_INTERVAL; aloha_status_time = secs_now+ALOHA_STATUS_INTERVAL; aloha_radius = -1.0; // Debug: Let's us play with/display aloha circles right away: //aloha_radius = 40.0; // Miles the_aloha_stats.digis=0; the_aloha_stats.wxs = 0; the_aloha_stats.other_mobiles = 0; the_aloha_stats.mobiles_in_motion = 0; the_aloha_stats.homes = 0; the_aloha_stats.total = 0; //fprintf(stderr,"Initialized aloha radius time\n"); } else { if (secs_now > aloha_time) { aloha_radius = calc_aloha_distance(); aloha_time = secs_now + ALOHA_CALC_INTERVAL; if (debug_level & 2048) { if (aloha_radius < 0) { fprintf(stderr,"Aloha distance indeterminate\n"); } else { fprintf(stderr,"Aloha distance is %f",aloha_radius); if (english_units) { fprintf(stderr," miles.\n"); } else { fprintf(stderr," km.\n"); } } } } if (secs_now > aloha_status_time) { if ( aloha_radius != -1 ) { xastir_snprintf(status_text, sizeof(status_text), langcode("BBARSTA044"), (english_units) ? (int)aloha_radius : (int)(aloha_radius * cvt_mi2len), (english_units) ? " miles" : " km"); statusline(status_text,1); } aloha_status_time = secs_now + ALOHA_STATUS_INTERVAL; } } } // popup window on menu request void Show_Aloha_Stats(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp[2000]; char format[1000]; unsigned long time_since_aloha_update; int minutes, hours; char Hours[7]; char Minutes[9]; if (aloha_radius != -1) { // we've done at least one interval, and aloha_time is the time // for the *next* one. We want the time since the last one. time_since_aloha_update = sec_now()-(aloha_time-ALOHA_CALC_INTERVAL); hours = time_since_aloha_update/3600; time_since_aloha_update -= hours*3600; minutes = time_since_aloha_update/60; if (hours == 1) xastir_snprintf(Hours,sizeof(Hours),"%s", langcode("TIME003")); // Hour else xastir_snprintf(Hours,sizeof(Hours),"%s", langcode("TIME004")); // Hours if (minutes == 1) xastir_snprintf(Minutes,sizeof(Minutes),"%s", langcode("TIME005")); // Minute else xastir_snprintf(Minutes,sizeof(Minutes),"%s", langcode("TIME006")); // Minutes // Build up the whole format string // "Aloha radius %d" xastir_snprintf(format,sizeof(format),"%s",langcode("WPUPALO001")); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); // "Stations inside...: %d" strncat(format,langcode("WPUPALO002"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Digis: %d" strncat(format,langcode("WPUPALO003"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Mobiles (in motion): %d" strncat(format,langcode("WPUPALO004"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Mobiles (other): %d" strncat(format,langcode("WPUPALO005"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" WX stations: %d" strncat(format,langcode("WPUPALO006"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Home stations: %d" strncat(format,langcode("WPUPALO007"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //"Last calculated %s ago." strncat(format,langcode("WPUPALO008"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); // We now have the whole format string, now print using it: xastir_snprintf(temp,sizeof(temp),format, (english_units) ? (int)aloha_radius : (int)(aloha_radius * cvt_mi2len), (english_units)?" miles":" km", the_aloha_stats.total, the_aloha_stats.digis, the_aloha_stats.mobiles_in_motion, the_aloha_stats.other_mobiles, the_aloha_stats.wxs, the_aloha_stats.homes, hours, Hours, minutes, Minutes); popup_message_always(langcode("PULDNVI016"),temp); } else { // Not calculated yet popup_message_always(langcode("PULDNVI016"),langcode("WPUPALO666")); } } // Debugging tool: // Check to see if time list contains any stations older than remove_time. // If the expire code did its job properly, there should be none. If there // are none, we return NULL. If there are any, we return the pointer to the // last one found (which should be the newest of them by virtue of how we // walk the list). DataRow * sanity_check_time_list(time_t remove_time) { DataRow *p_station, *p_station_t_newer, *retval; retval=NULL; for (p_station = t_oldest; p_station != NULL; p_station = p_station_t_newer) { p_station_t_newer = p_station->t_newer; // Don't count my station in this. if (!is_my_station(p_station) && p_station->sec_heard < remove_time) { retval=p_station; } } return (retval); } // Debugging tool // dump out the entire time-sorted list starting from oldest and proceeding // to newest void dump_time_sorted_list(void) { DataRow *p_station, *p_station_t_newer; struct tm *time; fprintf(stderr,"\tTime-sorted list dump \n"); fprintf(stderr, "\t Call Sign:\tsec_heard\tdate/time\n"); for (p_station = t_oldest; p_station != NULL; p_station = p_station_t_newer) { p_station_t_newer = p_station->t_newer; time = localtime(&p_station->sec_heard); fprintf(stderr,"\t%s\t%ld\t%02d/%02d %02d:%02d:%02d\n", p_station->call_sign, (long int) p_station->sec_heard, time->tm_mon+1,time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } } Xastir-Release-2.2.2/src/db_gis.c000066400000000000000000003361261501463444000165430ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // include postgresql library for postgis support #ifdef HAVE_POSTGIS #include // pg_type.h contains constants for OID values to use in paramTypes arrays // in prepared queries. #include #endif // HAVE_POSTGIS // mysql error library for mysql error code constants #ifdef HAVE_MYSQL #include #include #include #include #include #endif // HAVE_MYSQL #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H // Some systems don't have strtof #ifndef HAVE_STRTOF #define strtof(a,b) atof(a) #endif #include "snprintf.h" #include #include #include #include #include #include #include "database.h" #include "main.h" #include "util.h" #include "xastir.h" #include "db_gis.h" #ifdef HAVE_DB /* db_gis.c * * Functions supporting connections to databases, including GIS enabled * databases that hold OpenGIS objects and can apply spatial indices. * * XASTIR GIS database code is separated into three layers * * 1) Supporting XASTIR logic (ui elements, cad integration, * map drawing, etc). * 2a) Generic db storage/retrieval code - wrappers for layer 3 * 2b) Connection management code * 3a) DBMS specific db storage/retrieval code for spatial databases * 3b) DBMS specific db storage/retrieval code for non-spatial databases * * Data structures in an underlying database can be considered as a fourth * level. * * Code for layers 2 and 3 is in this file. * * Layer 2 functions should be extern and called from elsewhere to * perform spatial database operations. Xastir shouldn't need to care * if an underlying database has spatial support or not for simple data. * Some functionality might require spatial object support and might be * included only if a spatial database is available. Thus 3b code may only * support a subset of the 2a functions, while 3a code should support all * 2a functions. * Layer 2a wrappers should take and return values in xastir coordinates, * and convert them to decimal degrees to pass on to layer 3. Likewise * return values from layer 3 to layer 2a should be in decimal degrees, * limiting the number of different places at which the xastir/decimal * degree conversion code needs to be invoked. This would not be true if * data are fed directly from decimal degree feeds into the database, so * there may also be a need for layer 2 functions that deal only with * latitude and longitude in decimal degrees. * * Layer 3 functions should not be extern and should only be called * by layer 2 functions from within this file. * Layer 3 functions should take and return values in decimal degrees. * Xastir objects should be passed down into layer 3, as doing * so should make code easier to maintain (but harder to extend) than using * generic structures for transport of data between layers 2 and 3. * Passing a station struct from layer 2 to 3 makes layer 2 a very simple * wrapper, but requires new layer 3 code to write station data to a map * layer rather than to a DataRow (to, for example, prepare a layer of * temperature data at points for analysis and generation of a temperature * grid.) [Using generic structures for transport would let the layer 3 * code remain unchanged while layer 2 functions are added or extended, but * requires added maintenance to synchronise xastir structs, the generic * structs, and database structures.] * * A spatially enabled database is expected to support OpenGIS spatial * objects and be able to apply spatial indices to the data. A * non-spatially enabled database is expected to hold coordinates using * separate fields for latitude and longitude. Layer 3 functions that * interact with a spatial database will need to convert decimal degrees * to well known text (WKT, and perhaps also well known binary, WKB) * representations. Layer 3 functions that interact with non-spatially * enabled databases can just pass raw latitudes and longitudes. * * All spatial data are expected to be in WGS84 projection EPSG:4326 * * Support for five sets of underlying database schema elements is envisioned * - a very simple station at point and time table * - schema elements to support CAD objects with arbitrary associated data * tables. * - a schema capable of holding the full range of aprs data using spatial * elements (Points, Polygons, etc). * - full support for APRSWorld tables (using latitude and longitude fields * rather than spatial elements). * - arbitrary tables with schema discovery for arbitrary GIS databases * such as Tiger data. * The first three of these will require schema version awareness and will * produce compatibility/database lifecycle issues. * * Descriptions of how to make connections to databases are stored in * connection descriptors. Connection descriptors describe the DBMS, whether * the database has/lacks spatial support, the schema type (simple, * simple+cad, xastir full, APRSWorld, etc for the database, and connection * parameters (server, user, database). The layer 2/3 separation is intended * to allow functions (layer 2) to be called from within xastir (layer 1) * without the need to test which function to call for which dbms. Some * functions may be schema specific, others may be able to use any of * several different schemas. Connections can be opened from a database * descriptor, and more than one descriptor can point to the same database. * (Thus a single MySQL database may contain simple xastir tables, xastir * CAD object tables, and APRSWorld tables, but two different descriptors * would be used to define connections to talk to the APRSWorld tables and * the simple+cad tables within what MySQL considers one schema. A given * version of xastir will expect a particular version or range of versions * for database schemas - an older version of xastir may expect fields that * no longer exist in a database created for a newer version of xastir and * vice versa. * * Data selected from a spatial database might be brought into xastir as * stations just like an internet feed or findu fetch trail query, as * editable CAD objects, or as map layers. */ /******************* DATABASE SUPPORT IS EXPERIMENTAL ***********************/ /**************** CODE IN THIS FILE MAY CHANGE AT ANY TIME ******************/ // Layer 3 declarations // xastir_dbms_type is used in interface_gui.c to set up cb_items to populate // database picklist. Define and internationalise here. char xastir_dbms_type[4][XASTIR_DB_DESCRIPTOR_MAX_SIZE+1] = {"","MySQL (lat/long)","Postgresql/Postgis","MySQL Spatial"} ; // xastir_schema_type is used in interface_gui.c to set up cb_item to populate // schema type picklist Sql_Database_schema_type_data. Define and internationalize here. char xastir_schema_type[5][XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE+1] = {"","Xastir Simple","Xastir CAD","Xastir Full","APRSWorld"} ; const char *POSTGIS_TIMEFORMAT = "%Y-%m-%d %H:%M:%S%z"; const char *MYSQL_TIMEFORMAT = "%Y-%m-%d %H:%M:%S"; /* // store integer values for picklist items, but use localized strings on picklists char xastir_dbms_type[3][XASTIR_DB_DESCRIPTOR_MAX_SIZE+1]; // array of xastir database type strings xastir_snprintf(&xastir_dbms_type[DB_MYSQL][0], XASTIR_DB_DESCRIPTOR_MAX_SIZE, "%s",langcode("XADBMST001")); xastir_snprintf(&xastir_dbms_type[DB_POSTGIS][0], sizeof(&xastir_dbms_type[DB_POSTGIS][0]), "%s", langcode("XADBMST002")); xastir_snprintf(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], sizeof(&xastir_dbms_type[DB_MYSQL_SPATIAL][0]), "%s",langcode("XADBMST003")); char xastir_schema_type[4][XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE+1]; // array of xastir schema type strings xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_SIMPLE], sizeof(xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0]), "%s",langcode ("XASCHEMA01")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_CAD][0], sizeof(xastir_schema_type[XASTIR_SCHEMA_CAD][0]), "%s", langcode("XASCHEMA02")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_COMPLEX][0], sizeof(xastir_schema_type[XASTIR_SCHEMA_COMPLEX][0]), "%s", langcode("XASCHEMA03")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_APRSWORLD], sizeof(xastir_schema_type[XASTIR_SCHEMA_APRSWORLD][0]), "%s", langcode("XASCHEMA04")); */ #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS int storeStationToGisDbPostgis(Connection *aDbConnection, DataRow *aStation); int storeCadToGisDbPostgis(Connection *aDbConnection, CADRow *aCadObject); int storeStationSimplePointToGisDbPostgis(Connection *aDbConnection, DataRow *aStation); int testXastirVersionPostgis(Connection *aDbConnection); int getAllSimplePositionsPostgis(Connection *aDbConnection); int getAllSimplePositionsPostgisInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat); //PGconn postgres_conn_struct[MAX_DB_CONNECTIONS]; #endif /* HAVE_POSTGIS*/ #ifdef HAVE_MYSQL_SPATIAL int storeStationToGisDbMysql(Connection *aDbConnection, DataRow *aStation); int storeCadToGisDbMysql(Connection *aDbConnection, CADRow *aCadObject); int storeStationSimplePointToGisDbMysql(Connection *aDbConnection, DataRow *aStation); int getAllSimplePositionsMysqlSpatial(Connection *aDbConnection); int getAllCadFromGisDbMysql(Connection *aDbConnection); int getAllSimplePositionsMysqlSpatialInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat); #endif /* HAVE_MYSQL_SPATIAL */ #endif /* HAVE_SPATIAL_DB */ //Connection connection_struc[MAX_DB_CONNECTIONS]; Connection connections[MAX_IFACE_DEVICES]; int connections_initialized = 0; #ifdef HAVE_MYSQL //MYSQL mysql_conn_struct, *mysql_connection = &mysql_conn_struct; //MYSQL mcs[MAX_DB_CONNECTIONS]; Connection dbc_struct, *dbc = &dbc_struct; int testXastirVersionMysql(Connection *aDbConnection); int storeStationSimplePointToDbMysql(Connection *aDbConnection, DataRow *aStation); int getAllSimplePositionsMysql(Connection *aDbConnection); int getAllSimplePositionsMysqlInBoundingBox(Connection *aDbConnection, char *str_e_long, char *str_w_long, char *str_n_lat, char *str_s_lat); int storeStationToDbMysql(Connection *aDbConnection, DataRow *aStation); void mysql_interpret_error(int errorcode, Connection *aDbConnection); #endif /* HAVE_MYSQL*/ // Layer 2a: Generic GIS db storage code. ************************************ // Wrapper functions for actual DBMS specific actions #ifdef HAVE_SPATIAL_DB // ******** Functions that require spatialy enabled database support ********* /* function storeStationToGisDb() * Stores the information about a station and its most recent position * to a spatial database. * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } // This function is dbms agnostic, and hands the call off to a // function for the relevant database type. That function picks the // relevant schema and either handles the query or passes it on to // a function to handle that schema. switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = storeStationToGisDbPostgis(aDbConnection, aStation); break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = storeStationToGisDbMysql(aDbConnection, aStation); break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = storeStationToDbMysql(aDbConnection, aStation); break; #endif /* HAVE_MYSQL*/ } return returnvalue; } /* function storeCadToGisDb() * Stores current data about objects (including CAD objects) and their * most recent positions to a spatial database. Objects are treated as * points */ int storeCadToGisDb(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; if (aDbConnection==NULL || aCadObject==NULL) { return returnvalue; } // check that connection has cad support in schema return returnvalue; } /* function storeStationTrackToGisDb() * Stores information about a station and track of all received positions from * that station (including weather information if present) to a spatial * database. * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationTrackToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } return returnvalue; } #endif /* HAVE_SPATIAL_DB */ // ***** Functions that do not require spatialy enabled database support ****** // Include "Simple" in these function names. They should only deal with point // data, not polygons or complex spatial objects. Station positions and times // demarking implicit tracks should be ok. /* function storeStationSimpleToGisDb() * Stores basic information about a station and its most recent position * to a spatial database. Stores only callsign, most recent position, * and time. Intended for testing and simple logging uses. * Underlying table should have structure: * create table simpleStation ( * simpleStationId int primary key not null auto_increment * station varchar(9) not null, // max_callsign * time date not null default now(), * position POINT // or latitude float, longitude float for simple db. * ); **** or perhaps it should be an APRSWorld table?? **** **** or perhaps it should be an APRSWorld table, but with POINT when supported?? **** * * ********* generalize to lat/lon fields or position POINT. ****** * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationSimpleToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; int triedDatabase = 0; if (debug_level & 4096) { fprintf(stderr,"in storeStationSimpleToGisDb() "); } if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } if (aStation->data_via == DATA_VIA_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"skipping station heard from Database\n"); } returnvalue = 1; return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"with connection->type: %d\n",aDbConnection->type); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = storeStationSimplePointToGisDbPostgis(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = storeStationSimplePointToGisDbMysql(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = storeStationSimplePointToDbMysql(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } /* function getAllSimplePositions() * Given a database connection, return all simple station positions stored in * that database. */ int getAllSimplePositions(Connection *aDbConnection) { int returnvalue = 0; int triedDatabase = 0; if (aDbConnection==NULL) { return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"in getAllSimplePositions "); fprintf(stderr,"with aDbConnection->type %d\n",aDbConnection->type); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : //fprintf(stderr,"connection [%p]\n",aDbConnection); //fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); returnvalue = getAllSimplePositionsPostgis(aDbConnection); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = getAllSimplePositionsMysqlSpatial(aDbConnection); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = getAllSimplePositionsMysql(aDbConnection); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } /* function getAllSimplePositionsInBoundingBox() * Given a database connection and a bounding box, return all simple station * positions stored in that database that fall within the bounds of the box. * Takes eastern, western, northern, and southern bounds of box in xastir * coordinates. */ int getAllSimplePositionsInBoundingBox(Connection *aDbConnection, int east, int west, int north, int south) { int returnvalue = 0; int triedDatabase = 0; char str_e_long[11]; char str_n_lat[10]; char str_w_long[11]; char str_s_lat[10]; if (aDbConnection==NULL) { return returnvalue; } // convert from xastir coordinates to decimal degrees convert_lon_l2s(east, str_e_long, sizeof(str_e_long), CONVERT_DEC_DEG); convert_lat_l2s(north, str_n_lat, sizeof(str_n_lat), CONVERT_DEC_DEG); convert_lon_l2s(west, str_w_long, sizeof(str_w_long), CONVERT_DEC_DEG); convert_lat_l2s(south, str_s_lat, sizeof(str_s_lat), CONVERT_DEC_DEG); switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = getAllSimplePositionsPostgisInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = getAllSimplePositionsMysqlSpatialInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = getAllSimplePositionsMysqlInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } // Layer 2b: Connection management. ******************************************* /* It should be possible to maintain a list of an arbitrary number of defined * data sources of different types, and to have an arbitrary number of * connections to these data sources open at the same time. * * Some issues: How to handle login credentials for databases? Request on * connection? How to perform multiple operations with the same datasource * (e.g. logging to the database from feeds while querying CAD objects). * Probably want to be able to store password, request password on connect, * or use configuration file (e.g. my.ini) for password) - let user tune * choices to environment. * * The existing interface code seems better suited to having a fixed number * of interfaces with zero or one database connection associated with each * interface than handing an arbitrary number of connections per interface. */ // simple testing hardcoded database connection testing function // remove this function and call in main.c when integration with // interfaces is working. // fill in password, uncomment, and uncomment code in main.c for // simple database write test - writes station in n_first to simple mysql db /* ioparam simpleDbTest(void) { ioparam test; Connection conn; int ok; xastir_snprintf(test.device_name, sizeof(test.device_name), "Test Connection"); test.database_type = DB_MYSQL; xastir_snprintf(test.device_host_name, sizeof(test.device_host_name), "localhost"); test.sp = 3306; xastir_snprintf(test.database_username, sizeof(test.database_username), "xastir_test"); // hardcode a test password here for simple test xastir_snprintf(test.device_host_pswd, sizeof(test.device_host_pswd), "hardcoded test password"); xastir_snprintf(test.database_schema, sizeof(test.database_schema), "xastir"); test.database_schema_type = XASTIR_SCHEMA_SIMPLE; xastir_snprintf(test.database_unix_socket, sizeof(test.database_unix_socket), "/var/lib/mysql/mysql.sock"); got_conn=openConnection(&test, conn); ok = storeStationSimpleToGisDb(&conn, n_first); return test; } */ int initConnections() { int x; if (debug_level & 4096) { fprintf(stderr,"initConnections()\n"); } for (x=0; xdescriptor = &devices[x]; connection->type = 0; // assign no type by default connection->interface_number = x; // so we can reference port_data[] from a connection // without knowing the connection's position in // connections[] // malloc for the PGconn will cause segfault on trying to // open the connection #ifdef HAVE_POSTGIS connection->phandle = (PGconn*)malloc(sizeof(PGconn*)); #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL //connection->mhandle = (MYSQL)malloc(sizeof(MYSQL)); mysql_init(&connection->mhandle); #endif /* HAVE_MYSQL */ for(y=0; yerrormessage[y]=' '; } connection->errormessage[MAX_CONNECTION_ERROR_MESSAGE-1]='\0'; if (debug_level & 4096) { fprintf(stderr,"initAConnection() [%d]\n",x); } return 1; } /* Function openConnection() * Opens the specified database connection. * @param anIface a database connection description (host username etc). * @param connection a generic database connection for which the * appropriate MySQL or Postgresql connection handle will be used * for the open connection on success. * @returns 0 on any error, 1 for successful connection * on connection failure, returns 0 and sets error message in * the connection descriptor. */ int openConnection(ioparam *anIface, Connection *connection) { int returnvalue = 0; int connection_made = 0; #ifdef HAVE_POSTGIS char connection_string[900]; int connected; // status of connection polling loop time_t start_time; PGconn *postgres_connection; PostgresPollingStatusType poll; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL unsigned long client_flag = 0; // parameter used for mysql connection, is normally 0. unsigned int port; // port to make connection on #endif /* HAVE_MYSQL */ if (anIface==NULL) { fprintf(stderr,"Null iface\n"); return returnvalue; } if (anIface==NULL || connection==NULL) { fprintf(stderr,"Null connection\n"); return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"opening connection [%p] \n",connection); } // #ifdef HAVE_MYSQL // switch (anIface->database_type) { // #ifdef HAVE_MYSQL_SPATIAL // case DB_MYSQL_SPATIAL : // #endif /* HAVE_MYSQL_SPATIAL */ // #ifdef HAVE_MYSQL // case DB_MYSQL : // #endif /* HAVE_MYSQL */ // // instantiate the MYSQL structure for the connection // //fprintf(stderr,"calling mysql_init\n"); // //connection->mhandle = mysql_init(&connection->mhandle); // //fprintf(stderr,"called mysql_init\n"); // } // #endif /* HAVE_MYSQL */ // clear any existing error message xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); if (debug_level & 4096) { fprintf(stderr,"Entering openConnection with anIface [%p] and conn [%p]\n",anIface,connection); } connection->type = anIface->database_type; //connection->descriptor = anIface; if (connections_initialized == 0) { connections_initialized = initConnections(); connections_initialized = 1; } // TODO: need some sort of connection listener to handle reconnection attempts when a connection fails... // try to open connection if (!(anIface==NULL)) { switch (anIface->database_type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : if (debug_level & 4096) { fprintf(stderr,"Opening Connection to a Postgresql/Postgis database.\n"); } // If type is postgis, connect to postgis database. // build connection string from parameters xastir_snprintf(connection_string, sizeof(connection_string), \ "host=%s user=%s password=%s dbname=%s port=%d", \ anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, anIface->sp); // Use nonblocking connection (connectStart and connectPoll) //connection->phandle = PQconnectStart(connection_string); postgres_connection = PQconnectStart(connection_string); //if (connection->phandle == NULL) { if (postgres_connection == NULL) { xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); } else { connected = 0; // can connect, run PQ_connect_poll loop // Note: xastir needs to decide when to time out start_time = sec_now(); statusline("Connecting to Postgresql database",1); while ((connected==0) & (sec_now()<(start_time+30))) { // need to add a timer to polling loop //poll = PQconnectPoll(connection->phandle); poll = PQconnectPoll(postgres_connection); if (poll == PGRES_POLLING_FAILED || poll == PGRES_POLLING_OK) { connected = 1; } // add connection status feedback here if desired } //if (PQstatus(connection->phandle)==CONNECTION_OK) { if (PQstatus(postgres_connection)==CONNECTION_OK) { if (debug_level & 4096) { fprintf(stderr,"Connected to Postgresql database on %s\n",anIface->device_host_name); } // connection successful connection->phandle = postgres_connection; connection->type=DB_POSTGIS; //connection->descriptor = anIface; xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); connection_made = 1; } else { // connection attempt failed fprintf(stderr,"Failed to connect to Postgresql database on %s\n",anIface->device_host_name); fprintf(stderr,"Postgres Error: %s\n", PQerrorMessage(postgres_connection)); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to make Postgresql connection %s. %s", PQerrorMessage(postgres_connection), connection_string); } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : // if type is mysql (=>4.1), connect to mysql database if (debug_level & 4096) { fprintf(stderr,"Opening connection to a MySQL (spatial) database.\n"); } if (&connection->mhandle == NULL) { // insufficient memory to initialize a new database handle xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); } else { port = anIface->sp; statusline("Connecting to MySQL database",1); if (debug_level & 4096) { fprintf(stderr,"Opening connection to %s.\n",anIface->device_host_name); } mysql_real_connect(&connection->mhandle, anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port, anIface->database_unix_socket, client_flag); //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) if (&connection->mhandle == NULL) { // unable to establish connection xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to establish connection: %s", mysql_error(&connection->mhandle)); fprintf(stderr,"Failed to connect to MySQL database on %s\n",anIface->device_host_name); fprintf(stderr, "MySQL Error: %s", mysql_error(&connection->mhandle)); } else { // mysql_real_connect is coming back with non-null failed connection. // connected to database // make sure error message for making connection is empty. xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); // ping the server if (mysql_ping(&connection->mhandle)==0) { fprintf(stderr,"mysql ping ok [0]\n"); connection_made = 1; // store connection information connection->type = DB_MYSQL_SPATIAL; //connection->descriptor = anIface; if (debug_level & 4096) { fprintf(stderr,"Connected to MySQL database, connection stored\n"); } } else { fprintf(stderr,"mysql ping failed [1]\n"); fprintf(stderr,"Can't connect to MySQL database: Can't ping server.\n"); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to ping MySQL server. Server may be down. Check connection parameters."); } } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : // if type is mysql (<4.1), connect to mysql database if (debug_level & 4096) { fprintf(stderr,"Opening connection to a MySQL database.\n"); } if (&connection->mhandle == NULL) { // insufficient memory to initialize a new database handle xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); fprintf(stderr,"Insufficient memory to open mysql connection [mysql_init(*MYSQL) returned null].\n"); } else { client_flag = CLIENT_COMPRESS; port = anIface->sp; // **** fails if database_unix_socket doesn't exist mysql_real_connect(&connection->mhandle, anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port, anIface->database_unix_socket, client_flag); if (&connection->mhandle == NULL) { fprintf(stderr,"Unable to establish connection to MySQL database\nHost: %s Schema: %s Username: %s\n",anIface->device_host_name, anIface->database_schema, anIface->database_username); // unable to establish connection xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to establish MySQL connection. Host: %s Username: %s Password: %s Schema %s Port: %d", anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port); fprintf(stderr,"Failed to connect to MySQL database on %s\n",anIface->device_host_name); fprintf(stderr, "MySQL Error: %s", mysql_error(&connection->mhandle)); } else { fprintf(stderr,"Connected to MySQL database on %s\n",anIface->device_host_name); // connected to database // make sure error message for making connection is empty. xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); // ping the server if (mysql_ping(&connection->mhandle)==0) { fprintf(stderr,"mysql ping ok [0]\n"); connection_made = 1; // store connection information connection->type = DB_MYSQL; //connection->descriptor = anIface; if (debug_level & 4096) { fprintf(stderr,"Connected to MySQL database, connection stored\n"); } } else { fprintf(stderr,"mysql ping failed [1]\n"); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to ping MySQL server. Server may be down. Check connection parameters."); fprintf(stderr,"Can't connect to MySQL database: Can't ping server.\n"); } } } break; #endif /* HAVE_MYSQL*/ } /* end switch */ } /* end test for null interface */ if (connection_made==1) { if (debug_level & 4096) { fprintf(stderr,"Connection made: "); fprintf(stderr,"connection->type [%d]\n",connection->type); } if (testConnection((Connection*)connection)==True) { returnvalue = 1; statusline("Connected to database",1); } else { statusline("Incompatible database schema",1); fprintf(stderr,"Connection OK, but incompatible schema. [%s]\n",connection->errormessage); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "%s",connection->errormessage); closeConnection(connection,-1); //free(connection); } } else { // Detailed error message should have been returned above, but make sure // there is at least a minimal failure message regardless of the problem. statusline("Failed to connect to database",1); fprintf(stderr,"Failed to make database connection.\n"); //free(connection); // not pointing to the right thing ?? port_data[connection->interface_number].status = DEVICE_ERROR; } return returnvalue; } /* Function closeConnection() * Closes the specified database connection. * @param aDbConnection a generic database connection handle. */ int closeConnection(Connection *aDbConnection, int port_number) { //ioparam db = aDbConnection->descriptor; fprintf(stderr,"Closing connection on port %d\n",port_number); if (aDbConnection==NULL) { return 0; } // free up connection resources switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : fprintf(stderr,"Connection type is postgis.\n"); // if type is postgis, close connection to postgis database if (aDbConnection->phandle!=NULL) { if (port_data[port_number].status==DEVICE_UP) { PQfinish(aDbConnection->phandle); } //free(aDbConnection->phandle); } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : // if type is mysql, close connection to mysql database if (&aDbConnection->mhandle!=NULL) { if (debug_level & 4096) { fprintf(stderr,"Connection type to close is mysql spatial.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } mysql_close(&aDbConnection->mhandle); //free(aDbConnection->mhandle); } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : fprintf(stderr,"Connection type is mysql.\n"); // if type is mysql, close connection to mysql database if (&aDbConnection->mhandle!=NULL) { mysql_close(&aDbConnection->mhandle); //free(aDbConnection->mhandle); } break; #endif /* HAVE_MYSQL*/ } return 1; } /* Tests a database connection to see if the server is responding. * @param aDbConnection pointer to a generic connection handle. * @returns 0 on any error, 1 for successful ping. */ int pingConnection(Connection *aDbConnection) { int returnvalue = True; int dbreturn; #ifdef HAVE_POSTGIS ConnStatusType psql_status; #endif /* HAVE_POSTGIS */ if (aDbConnection==NULL) { return 0; } if (debug_level & 4096) { fprintf(stderr,"Pinging database server type=[%d]\n",aDbConnection->type); //} else { //fprintf(stderr,"Pinging database server.\n"); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS: returnvalue = False; // is the connection open [required] if (aDbConnection->phandle!=NULL) { psql_status = PQstatus(aDbConnection->phandle); if (psql_status!=CONNECTION_OK) { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Postgresql connection failed"); fprintf(stderr, "PQstatus returned CONNECTION_BAD, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "PQstatus returned CONNECTION_OK.\n"); } returnvalue = True; } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL: returnvalue = False; // is the connection open [required] if (&aDbConnection->mhandle!=NULL) { // can we ping the server [required] dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr, "MySQL Ping failed, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "MySQL Ping OK.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } returnvalue = True; } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL: // is the connection open [required] if (&aDbConnection->mhandle != NULL) { dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr, "MySQL Ping failed, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "MySQL Ping OK.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } returnvalue = True; } } break; #endif /* HAVE_MYSQL*/ } if (returnvalue==0) { fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); statusline("Database Ping Failed",1); port_data[aDbConnection->interface_number].status = DEVICE_ERROR; } return returnvalue; } /* Tests a database connection and the underlying schema to see * if the connection is open, the schema version is supported by * this version of the code, and to see what permissions are * available */ int testConnection(Connection *aDbConnection) { int returnvalue = True; int dbreturn; int major_version; int minor_version; char warning[100]; #ifdef HAVE_POSTGIS ConnStatusType psql_status; PGresult *result; const char *postgis_sql = "SELECT COUNT(*) FROM geometry_columns"; // test to see if schema used in connection has postgis support added #endif /* HAVE_POSTGIS */ if (aDbConnection==NULL) { return 0; } xastir_snprintf(warning, 100, " "); // make sure warning is empty switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS: returnvalue = False; // is the connection open [required] if (aDbConnection->phandle!=NULL) { psql_status = PQstatus(aDbConnection->phandle); if (psql_status!=CONNECTION_OK) { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Postgresql connection failed"); fprintf(stderr, "PQstatus returned CONNECTION_BAD, probably unable to connect to server.\n"); } else { fprintf(stderr, "PQstatus returned CONNECTION_OK.\n"); // which version of postgresql are we running dbreturn = PQserverVersion(aDbConnection->phandle); major_version = dbreturn / 10000; minor_version = (dbreturn - (major_version*10000)) / 100; fprintf(stderr,"Postgresql version [%d] %d.%d\n",dbreturn,major_version,minor_version); // is the database spatially enabled [required] result = PQexec(aDbConnection->phandle,postgis_sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(aDbConnection->phandle)); fprintf(stderr, "testConnection() Null result\nPostgresql Error : %s\n",PQerrorMessage(aDbConnection->phandle)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { // PQexec returned a valid result set, meaning that a geometry_types table exists. // are the needed tables present [required] // check schema type (simple, simple+cad, full, aprsworld) // check version of database schema for compatibility if (testXastirVersionPostgis(aDbConnection)==1) { returnvalue = True; } // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have inesrt privileges [optional] // does the user have delete privileges [optional] } else { // schema lacks a geometry_columns table, either schema or database lacks postgis support xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "No geometry_columns table found. Is PostGIS installed and added to this schema?\n"); xastir_snprintf(warning, 100, "No geometry_columns table found. PostGIS may not be installed, or the schema may not have PostGIS support added."); fprintf(stderr, "No geometry_columns table found.\nPostGIS may not be installed, or the schema may not have PostGIS support added.\n"); fprintf(stderr, "Postgresql Error : %s\n",PQerrorMessage(aDbConnection->phandle)); } } } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL: returnvalue = False; // is the connection open [required] if (&aDbConnection->mhandle!=NULL) { // can we ping the server [required] dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr,"Ping of mysql server failed.\n"); xastir_snprintf(warning, 100, "%s",aDbConnection->errormessage); } else { if (debug_level & 4096) { fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } // is the database spatially enabled [required] // determine from db version >= 4.2 // MySQL 4.1 is past end of life, 4.2 at end of life but still in widespread use, e.g. RHEL4 (in early 2008). // mysql_server_version is new to mysql 4.1, prepared queries stabilized in 4.2 dbreturn = mysql_get_server_version(&aDbConnection->mhandle); if (dbreturn>0) { major_version = dbreturn / 10000; minor_version = (dbreturn - (major_version*10000)) / 100; if (major_version>=5 || (major_version==4 && minor_version >=2)) { fprintf(stderr,"MySQL Server version %d.%d OK.\n",major_version,minor_version); // check version of database schema for compatibility dbreturn = testXastirVersionMysql(aDbConnection); if (dbreturn==1) { fprintf(stderr,"Compatible Xastir database version found on server.\n"); // are the needed tables present [required] // check schema type (simple, simple+cad, full, aprsworld) // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have insert privileges [optional] // does the user have delete privileges [optional] returnvalue = True; } else { fprintf(stderr,"Xastir database version on server is not compatible with this version of Xastir.\n"); // aDbConnection->errormessage should have been set in testXastirVersionMysql xastir_snprintf(warning, 100, "%s",aDbConnection->errormessage); } } else { // version too low fprintf(stderr,"MySQL Server version %d.%d is too low and is not supported in Xastir.\n",major_version,minor_version); xastir_snprintf(warning, 100, "MySQL Server version %d.%d is too low and is not supported in Xastir.",major_version,minor_version); } } else { // ? mysql<4.1 } } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL: // is the connection open [required] if (&aDbConnection->mhandle != NULL) { dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); } else { if (debug_level & 4096) { fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } // is the database spatially enabled [optional] // determine from db version >= 4.1 #ifdef HAVE_MYSQL_SPATIAL // mysql_server_version is new to mysql 4.1 dbreturn = mysql_get_server_version(&aDbConnection->mhandle); #endif /* HAVE_MYSQL_SPATIAL */ // are the needed tables present [required] // check schema type (simple, simple+cad, aprsworld) // full requires objects, not supported here. // check version of database schema for compatibility dbreturn = testXastirVersionMysql(aDbConnection); // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have insert privileges [optional] // does the user have delete privileges [optional] } } break; #endif /* HAVE_MYSQL*/ } if (returnvalue==0) { fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Incompatible schema: %s",warning); fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); // Note: Don't close connection here, we haven't handed the error to the user yet. //closeConnection(aDbConnection,-1); fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); } return returnvalue; } // Layer 3: DBMS specific db storage code ************************************* // Functions in this section should be local to this file and not exported // Export functions in section 2a above. // // Layer 3a: DBMS specific GIS db storage code ******************************** // Functions supporting queries to specific types of GIS enabled databasesa // #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS // Postgis implementation of spatial database functions /* postgresql+postgis implementation of storeStationToGisDb(). */ int storeStationToGisDbPostgis(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToGisDbPostgis(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* postgresql+postgis implementation of storeCadToGisDb(). */ int storeCadToGisDbPostgis(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; return returnvalue; } /* function storeStationSimplePointToGisDbPostgis() * Postgresql/Postgis implementation of wrapper storeStationSimplePointToGisDb(). * Should only be called through wrapper function. Do not call directly. */ int storeStationSimplePointToGisDbPostgis(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; // Default return value is failure. int ok; // Holds results of tests when building query. char wkt[MAX_WKT]; // well know text representation of latitude and longitude of point char timestring[101]; // string representation of the time heard or the current time char call_sign[(MAX_CALLSIGN*2)+1]; // temporary holding for escaped callsign char aprs_symbol[2]; // temporary holding for escaped aprs symbol char aprs_type[2]; // temporary holding for escaped aprs type char special_overlay[2]; // temporary holding for escaped overlay char origin[(MAX_CALLSIGN*2)+1]; // temporary holding for escaped origin char node_path[(NODE_PATH_SIZE*2)+1]; // temporary holding for escaped node_path char record_type[2]; // temporary holding for escaped record_type //PGconn *conn = aDbConnection->phandle; PGresult *prepared = NULL; PGresult *result = NULL; int count; // returned value from count query const int PARAMETERS = 9; // parameter arrays for prepared query const char *paramValues[PARAMETERS]; // To use native Postgres POINT for position instead of postgis geometry point. //const Oid paramTypes[6] = { VARCHAROID, TIMESTAMPTZOID, POINTOID, VARCHAROID, VARCHAROID, VARCHAROID }; //const Oid paramTypes[6] = { 1043, 1184, 600, 1043, 1043, 1043 }; // Native postgres (8.2) geometries don't have spatial support as rich as Postgis extensions. // use postgis geometry Point instead: // lookup OID for geometry: select OID from pg_type where typname = 'geometry'; returns 19480 //const Oid paramTypes[6] = { VARCHAROID, TIMESTAMPTZOID, 19480, VARCHAROID, VARCHAROID, VARCHAROID }; //const Oid paramTypes[6] = { 1043, 1184, 19480, 1043, 1043, 1043 }; // Value 18480 is probably installation specific, use unknownOID instead: //const Oid paramTypes[9] = { VARCHAROID, TIMESTAMPTZOID, UNKNOWNOID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID }; const Oid paramTypes[9] = { 1043, 1184, 705, 1043, 1043, 1043, 1043, 1043, 1043 }; const char *sql = "insert into simpleStation (station, transmit_time, position, symbol, overlay, aprstype, origin, record_type, node_path) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)"; const char *StatementName = "InsertSimpleStation"; const char *StatementExists = "select count(*) from pg_prepared_statements where name = 'InsertSimpleStation'"; if (debug_level & 4096) { fprintf(stderr,"In postgres simple station insert\n"); fprintf(stderr,"with connection [%p] \n",aDbConnection); fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); } if (aDbConnection->phandle==NULL) { fprintf(stderr,"Trying to save station on null postgresql connection\n"); return returnvalue; } if (PQserverVersion(aDbConnection->phandle)==0) { // no connection to server fprintf(stderr,"Trying to save station on closed postgresql connection\n"); return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"Postgresql version=%d\n",PQserverVersion(aDbConnection->phandle)); } // Check to see if this prepared statement exists in the current session // and create it if it does not. // Query adds connection overhead - should probably track with a global variable, // and query/recreate statement only on failure. ok = 0; // pg_prepared_statements system view added in postgresql 8.2 if (PQserverVersion(aDbConnection->phandle)>80199) { result = PQexec(aDbConnection->phandle, "select count(*) from pg_prepared_statements where name = 'InsertSimpleStation'"); result = PQexec(aDbConnection->phandle, StatementExists); if (result==NULL) { fprintf(stderr,"Postgres Check for Prepared Query exec Failed: %s\n", PQerrorMessage(aDbConnection->phandle)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQerrorMessage(aDbConnection->phandle)); } else { count = 0; if (PQresultStatus(result) == PGRES_TUPLES_OK) { count = atoi(PQgetvalue(result,0,0)); } if (count==0) { // Statement doesn't exist, so prepare it, let PQprepare report on any error that got us a NULL result. prepared = PQprepare(aDbConnection->phandle, StatementName, sql, PARAMETERS, paramTypes); if (PQresultStatus(prepared)==PGRES_COMMAND_OK) { ok = 1; } else { // error condition - can't prepare statement fprintf(stderr,"Postgres Prepare Query Failed: %s\n", PQerrorMessage(aDbConnection->phandle)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQerrorMessage(aDbConnection->phandle)); exit(1); } } else if (count==1) { // prepared statement exists, we can go ahead with query. ok = 1; } else { fprintf(stderr,"Postgres Check for Prepared Query getvalue (count=%d) failed: %s\n",count, PQresultErrorMessage(result)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQresultErrorMessage(result)); } } } else { prepared = PQprepare(aDbConnection->phandle, StatementName, sql, PARAMETERS, paramTypes); ok = 1; } if (ok==1) { // native postgis POINT is (99.999 099.999) instead of POINT (99.999 099.999) // ok = xastirCoordToLatLongPosgresPoint(aStation->coord_lon, aStation->coord_lat, wkt); // // Prepared query is ready, get and fill in the parameter values // from the station provided, then fire the query. ok = xastirCoordToLatLongWKT(aStation->coord_lon, aStation->coord_lat, wkt); if (ok==1) { // Postgresql 8 documentation indicates that escape string should not be performed // when calling PQexecParams or its sibling routines, not explicit, but implication // is that PQexecPrepared with passed parameters is a sibling routine and we // shouldn't be running PQescapeStringConn() on the parameters. // If used, form would be: // PQescapeStringConn(conn,call_sign,aStation->call_sign,(MAX_CALLSIGN*2)+1,escape_error); xastir_snprintf(call_sign,MAX_CALLSIGN+1,"%s",aStation->call_sign); if (strlen(aStation->origin) > 0) { xastir_snprintf(origin,sizeof(origin),"%s",aStation->origin); } else { xastir_snprintf(origin,1,"%c",'\0'); } xastir_snprintf(record_type,2,"%c",aStation->record_type); if (aStation->node_path_ptr==NULL) { xastir_snprintf(node_path,2," "); } else { xastir_snprintf(node_path,sizeof(node_path),"%s",aStation->node_path_ptr); } if (debug_level & 4096) { fprintf(stderr,"node_path (12345678901234567890123456789012345678901234567890123456)\n"); fprintf(stderr,"node_path = [%s]\n",node_path); } // Get time in seconds, adjust to datetime // If aStation is my station or another unset sec_heard is // encountered, use current time instead. Conversely, use time // provided in sec_heard if sec_heard is an invalid time. get_iso_datetime(aStation->sec_heard,timestring,True,False); // set parameter values to call, transmit_time, and position paramValues[0]=call_sign; paramValues[1]=timestring; paramValues[2]=wkt; if (aStation->aprs_symbol.aprs_symbol==NULL) { xastir_snprintf(aprs_symbol,2," "); paramValues[3]=&aprs_symbol; } else { xastir_snprintf(aprs_symbol,2,"%c",aStation->aprs_symbol.aprs_symbol); paramValues[3]=aprs_symbol; } if (aStation->aprs_symbol.special_overlay==NULL) { xastir_snprintf(special_overlay,2," "); paramValues[4]=&special_overlay; } else { xastir_snprintf(special_overlay,2,"%c",aStation->aprs_symbol.special_overlay); paramValues[4]=&special_overlay; } if (aStation->aprs_symbol.aprs_type==NULL) { xastir_snprintf(aprs_type,2," "); paramValues[5]=&aprs_type; } else { xastir_snprintf(aprs_type,2,"%c",aStation->aprs_symbol.aprs_type); paramValues[5]=aprs_type; } paramValues[6]=origin; paramValues[7]=record_type; paramValues[8]=node_path; if (debug_level & 4096) { fprintf(stderr,"Inserting: Call: %s, Time: %s, Position: %s, Symbol:%s,%s,%s Origin:%s, Node_path:%s, Record type:%s\n",paramValues[0],paramValues[1],paramValues[2],paramValues[3],paramValues[4],paramValues[5],paramValues[6],paramValues[8],paramValues[7]); } // send query result = PQexecPrepared(aDbConnection->phandle,StatementName,PARAMETERS,paramValues,NULL,NULL,POSTGRES_RESULTFORMAT_TEXT); if (PQresultStatus(result)!=PGRES_COMMAND_OK) { fprintf(stderr,"Postgres Insert query failed:%s\n",PQresultErrorMessage(result)); // error, get error message. xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQresultErrorMessage(result)); } else { // query was successful returnvalue=1; } } else { // problem with coordinates of station fprintf(stderr,"Unable to save station to Postgres db, Error converting latitude or longitude from xastir coordinates\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } if (result!=NULL) { PQclear(result); } if (prepared!=NULL) { PQclear(prepared); } return returnvalue; } /* function testXastirVersionPostgis() * Postgresql/Postgis implementation of wrapper testXastirVersionPostgis(). * Should only be called through wrapper function. Do not call directly. */ int testXastirVersionPostgis(Connection *aDbConnection) { int returnvalue = 0; int version_number; int compatable_series; const char sql[100] = "select version_number, compatable_series from version order by version_number desc limit 1"; PGresult *result; PGconn *conn = aDbConnection->phandle; result = PQexec(conn,sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(conn)); fprintf(stderr, "testXastirVersionPostgis() Null result\nPostgresql Error : %s\n",PQerrorMessage(conn)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { if (PQntuples(result)!=1) { fprintf(stderr,"Version table doesn't appear to contain any rows.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version table doesn't appear to contain any rows."); } else { version_number = atoi(PQgetvalue(result,0,0)); compatable_series = atoi(PQgetvalue(result,0,1)); if (version_number == XASTIR_SPATIAL_DB_VERSION) { returnvalue = 1; } else { if (version_number < XASTIR_SPATIAL_DB_VERSION && compatable_series == XASTIR_SPATIAL_DB_COMPATABLE_SERIES) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { fprintf(stderr,"Version in schema (%d) is not compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version in schema (%d) is not compatible with this version of xastir (%d).",version_number,XASTIR_SPATIAL_DB_VERSION); fprintf(stderr,"%s",aDbConnection->errormessage); returnvalue = 0; } } } } PQclear(result); } return returnvalue; } /* function getAllSimplePositionsPostgis() * Postgresql/Postgis implementation of wrapper getAllSimplePositions(). * Should only be called through wrapper function. Do not call directly. */ int getAllSimplePositionsPostgis(Connection *aDbConnection) { int returnvalue = 0; // value to return from function, 1 for success, 0 for failure int row; // row counter for result set loop int station_count = 0; // number of new stations retrieved unsigned long x; // xastir coordinate for longitude unsigned long y; // xastir coordinate for latitude unsigned long u_long; unsigned long u_lat; char *s_lat[13]; // string latitude char *s_lon[13]; // string longitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string const char *sql = "select station, symbol, overlay, aprstype, transmit_time, AsText(position), origin, record_type, node_path, X(position), Y(position) from simpleStation order by station, transmit_time asc"; // station is column 0, symbol is column 1, etc. PGconn *conn = aDbConnection->phandle; char feedback[100]; char lastcall[MAX_CALLSIGN+1]; //holds last retrieved callsign int exists; //shortcut to skip db check if currently retrieved callsign equals last retrieved callsign DataRow *p_new_station; // pointer to new station record DataRow *p_time; // pointer to new station record int skip; int points_this_station; // number of times this station has been heard. char empty[MAX_ALTITUDE]; struct tm time; time_t sec; empty[0]='\0'; xastir_snprintf(feedback,100,"Retrieving Postgis records\n"); stderr_and_statusline(feedback); //fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); // run query and retrieve result set PGresult *result = PQexec(conn,sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(conn)); fprintf(stderr, "getAllSimplePositionsPostgis() Null result\nPostgresql Error : %s\n",PQerrorMessage(conn)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { // PQexec returned a valid result set. xastir_snprintf(feedback,100,"Retrieving %i Postgis records\n",PQntuples(result)); stderr_and_statusline(feedback); xastir_snprintf(lastcall,MAX_CALLSIGN+1," "); points_this_station = 0; for (row=0; rowcoord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } // store this trail point lat = atof(PQgetvalue(result,row,10)); lon = atof(PQgetvalue(result,row,9)); if (strlen(PQgetvalue(result,row,4)) > 0) { strptime(PQgetvalue(result,row,4), "%Y-%m-%d %H:%M:%S%z", &time); sec = mktime(&time); } if(convert_to_xastir_coordinates( &u_long, &u_lat, lon, lat)) { (void)store_trail_point(p_new_station, u_long, u_lat, sec, empty, empty, empty, 0); } if (p_new_station->sec_heard < sec) { // update the station record to this position if(convert_to_xastir_coordinates(&u_long, &u_lat, lon, lat)) { p_new_station->coord_lat = u_lat; p_new_station->coord_lon = u_long; p_new_station->sec_heard = sec; } } } } } else { // This station isn't in the xastir db. //int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time) { //const char *sql = "select station, symbol, overlay, aprstype, transmit_time, AsText(position), origin, record_type, node_path, X(position), Y(position) from simpleStation order by station, transmit_time asc"; add_simple_station(p_new_station,PQgetvalue(result,row,0), PQgetvalue(result,row,6), PQgetvalue(result,row,1), PQgetvalue(result,row,2), PQgetvalue(result,row,3), PQgetvalue(result,row,10), PQgetvalue(result,row,9), PQgetvalue(result,row,7), PQgetvalue(result,row,8), PQgetvalue(result,row,4), POSTGIS_TIMEFORMAT); station_count ++; } // end else, new station } // end else, station is not null } // end for loop stepping through rows redo_list = (int)TRUE; // update active station lists xastir_snprintf(feedback,100,"Added %d stations from Postgis\n",station_count); stderr_and_statusline(feedback); } else { // sql query had a problem retrieving result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "%s %s\n",PQresStatus(PQresultStatus(result)),PQerrorMessage(conn)); fprintf(stderr, "getAllSimplePositionsPostgis() %s\nPostgresql Error : %s\n",PQresStatus(PQresultStatus(result)),PQerrorMessage(conn)); } // done with result set, so free the resource. PQclear(result); } return returnvalue; } /* function getAllSimplePositionsPostgisInBoundingBox() * Postgresql/Postgis implementation of wrapper getAllSimplePositionsInBoundingBox(). * Should only be called through wrapper function. Do not call directly. */ int getAllSimplePositionsPostgisInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat) { int returnvalue = 0; // set up prepared query with bounding box // postgis simple table uses POINT char sql[100] = "select call, transmit_time, position from simpleStation where "; PGconn *conn = aDbConnection->phandle; return returnvalue; } #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL // Mysql 5 implementation of spatial database functions /* function storeStationToGisDbMysql * MySQL implementation of storeStationToGisDb * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an exastir database connection struct describing * the connection. * @param aStation * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeStationToGisDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToGisDbMysql(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* function storeCadToGisDbMysql * MySQL implementation of storeCadToGisDbMysql * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an exastir database connection struct describing * the connection. * @param aCadObject * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeCadToGisDbMysql(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; return returnvalue; } /* support function for prepared statements int bind_mysql_string_parameter(MYSQL_BIND *bind, int bind_number, char* buffer, int provided_length, int buffer_length, my_bool is_null) { bind[bind_number]->buffer = buffer; bind[bind_number]->length = provided_length; bind[bind_number]->buffer_length = buffer_length; bind[bind_number]->buffer_type = MYSQL_TYPE_STRING bind[bind_number]->is_null = is_null; } */ /* function storeStationSimplePointToGisDbMysql() * MySQL implementation of wrapper storeStationSimplePointToGisDb(). * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an xastir database connection struct describing * the connection. * @param aStation * Returns 0 for failure, 1 for success. * On failure sets error message in aDbConnection->errormessage. */ int storeStationSimplePointToGisDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; int mysqlreturn; // hold return value of mysql query int param_count; // check on the number of parameters present in the prepared statement int ok; // variable to store results of tests preparatory to firing query // temporary holding variables for bind buffers char wkt[MAX_WKT]; // well know text representation of latitude and longitude of point char aprs_symbol[2]; // temporary holding for escaped aprs symbol char aprs_type[2]; // temporary holding for escaped aprs type char special_overlay[2]; // temporary holding for escaped overlay char record_type[2]; // temporary holding for escaped record type char origin[MAX_CALLSIGN+1]; // temporary holding for escaped origin char node_path[NODE_PATH_SIZE+1]; // temporary holding for escaped node_path_ptr MYSQL_STMT *statement; // bind string lengths unsigned long call_sign_length; unsigned long wkt_length; unsigned long aprs_symbol_length; unsigned long aprs_type_length; unsigned long special_overlay_length; unsigned long origin_length; unsigned long record_type_length; unsigned long node_path_length; // time MYSQL_TIME timestamp; char timestring[100+1]; time_t secs_now; struct tm *ts; // to convert time to component parts for bind.buffer_type MYSQL_TYPE_DATETIME // define prepared statement and matching bind array #define SQL "INSERT INTO simpleStationSpatial (station, transmit_time, position, symbol, overlay, aprstype, origin, record_type, node_path) VALUES (?,?,PointFromText(?),?,?,?,?,?,?)" MYSQL_BIND bind[9]; // bind array for prepared query. int parameters = 9; // Note: // bind[9], SQL "?????????", and param_count must all match value of parameters // nine bound parameters, nine question marks in the statement, and param_count returned as nine. if (debug_level & 4096) { fprintf(stderr,"in storeStationSimplePointToGisDbMysql\n"); fprintf(stderr,"with connection [%p] \n",aDbConnection); } if (&aDbConnection->mhandle==NULL) { return returnvalue; } statement = mysql_stmt_init(&aDbConnection->mhandle); if (!statement) { fprintf(stderr,"Unable to create mysql prepared statement. May be out of memory.\n"); } mysql_stmt_prepare(statement, SQL, strlen(SQL)); if (!statement) { mysql_interpret_error(*mysql_error(&aDbConnection->mhandle),aDbConnection); } else { // test to make sure that statement has the correct number of parameters param_count=mysql_stmt_param_count(statement); if (param_count!=parameters) { fprintf(stderr,"Number of bound parameters %d does not match expected value %d\nFor query[%s]",param_count,parameters,SQL); fprintf(stderr, " %s\n", mysql_stmt_error(statement)); } else { // set up the buffers memset(bind, 0, sizeof(bind)); bind[0].buffer = (char *)&aStation->call_sign; bind[0].length = &call_sign_length; bind[0].buffer_length = MAX_CALLSIGN; bind[0].buffer_type = MYSQL_TYPE_STRING; bind[0].is_null = 0; bind[1].buffer = (char *)×tamp; bind[1].length = 0; bind[1].buffer_type = MYSQL_TYPE_DATETIME; bind[1].is_null = 0; bind[2].buffer = (char *)&wkt; bind[2].length = &wkt_length; bind[2].buffer_length = MAX_WKT; bind[2].buffer_type = MYSQL_TYPE_STRING; bind[2].is_null = 0; bind[3].buffer = (char *)&aprs_symbol; bind[3].length = &aprs_symbol_length; bind[3].buffer_length = 2; bind[3].buffer_type = MYSQL_TYPE_STRING; bind[3].is_null = 0; bind[4].buffer = (char *)&special_overlay; bind[4].length = &special_overlay_length; bind[4].buffer_length = 2; bind[4].buffer_type = MYSQL_TYPE_STRING; bind[4].is_null = 0; bind[5].buffer = (char *)&aprs_type; bind[5].length = &aprs_type_length; bind[5].buffer_length = 2; bind[5].buffer_type = MYSQL_TYPE_STRING; bind[5].is_null = 0; bind[6].buffer = (char *)&origin; // segfaults with origin of zero length, otherwise writes bad data bind[6].length = &origin_length; bind[6].buffer_length = MAX_CALLSIGN; bind[6].buffer_type = MYSQL_TYPE_STRING; bind[6].is_null = 0; bind[7].buffer = (char *)&record_type; bind[7].length = &record_type_length; bind[7].buffer_length = 2; bind[7].buffer_type = MYSQL_TYPE_STRING; bind[7].is_null = 0; bind[8].buffer = (char *)&node_path; bind[8].length = &node_path_length; bind[8].buffer_length = NODE_PATH_SIZE; bind[8].buffer_type = MYSQL_TYPE_STRING; bind[8].is_null = 0; ok = mysql_stmt_bind_param(statement,bind); if (ok!=0) { fprintf(stderr,"Error binding parameters to mysql prepared statement.\n"); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); fprintf(stderr,mysql_stmt_error(statement)); } else { // get call, time, and position // call is required if (aStation->call_sign!=NULL && strlen(aStation->call_sign)>0) { call_sign_length = strlen(aStation->call_sign); // get time in seconds, adjust to datetime // If my station or another unset sec_heard is // encountered, use current time instead, use time // provided if it was invalid. get_iso_datetime(aStation->sec_heard,timestring,True,False); if ((int)aStation->sec_heard==0 ) { secs_now = sec_now(); ts = localtime(&secs_now); } else { ts = localtime(&aStation->sec_heard); } timestamp.year = ts->tm_year + 1900; // tm_year is from 1900 timestamp.month = ts->tm_mon + 1; // tm_mon is from 0 timestamp.day = ts->tm_mday; // tm_mday is from 1 timestamp.hour = ts->tm_hour; timestamp.minute = ts->tm_min; timestamp.second = ts->tm_sec; ok = xastirCoordToLatLongWKT(aStation->coord_lon, aStation->coord_lat, wkt); if (ok==1) { wkt_length = strlen(wkt); if (aStation->aprs_symbol.aprs_symbol) { xastir_snprintf(aprs_symbol,2,"%c",aStation->aprs_symbol.aprs_symbol); } else { xastir_snprintf(aprs_symbol,2,"%c",'\0'); } aprs_symbol_length = strlen(aprs_symbol); if (aStation->aprs_symbol.aprs_type) { xastir_snprintf(aprs_type,2,"%c",aStation->aprs_symbol.aprs_type); } else { xastir_snprintf(aprs_type,2,"%c",'\0'); } aprs_type_length = strlen(aprs_type); if (aStation->aprs_symbol.special_overlay) { xastir_snprintf(special_overlay,2,"%c",aStation->aprs_symbol.special_overlay); } else { xastir_snprintf(special_overlay,2,"%c",'\0'); } special_overlay_length = strlen(special_overlay); if (aStation->origin) { xastir_snprintf(origin,MAX_CALLSIGN+1,"%s",aStation->origin); } else { //xastir_snprintf(origin,2,"%c",'\0'); origin[0]='\0'; } origin_length = strlen(origin); if (aStation->record_type) { xastir_snprintf(record_type,2,"%c",aStation->record_type); } else { //xastir_snprintf(record_type,2,"%c",'\0'); record_type[0]='\0'; } record_type_length = strlen(record_type); if (aStation->node_path_ptr) { if (debug_level & 4096) { fprintf(stderr,"node_path (12345678901234567890123456789012345678901234567890123456)\n"); fprintf(stderr,"node_path = [%s]\n",aStation->node_path_ptr); } xastir_snprintf(node_path,NODE_PATH_SIZE+1,"%s",aStation->node_path_ptr); } else { //xastir_snprintf(node_path,2,"%c",'\0'); node_path[0]='\0'; } node_path_length = strlen(node_path); // all the bound parameters should be available and correct if (debug_level & 4096) { fprintf(stderr,"saving station %s %d %d %d %d:%d:%d wkt=%s [%s][%s][%s] \n",aStation->call_sign,ts->tm_year,ts->tm_mon,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec,wkt,aprs_type,aprs_symbol,record_type); } // send query mysqlreturn = mysql_stmt_execute(statement); if (mysqlreturn!=0) { returnvalue=0; fprintf(stderr,"%s\n",mysql_stmt_error(statement)); mysql_interpret_error(mysqlreturn,aDbConnection); } else { returnvalue=1; } } else { fprintf(stderr,"Unable to save station to mysql db, Error converting latitude or longitude from xastir coordinates\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } else { // set call not null error message fprintf(stderr,"Unable to save station to mysql db, Station call sign was blank or null.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Station callsign is required and was blank or null."); } } // end of bind check } // end of parameter count check } mysql_stmt_free_result(statement); mysql_stmt_close(statement); if (returnvalue==0) { pingConnection(aDbConnection); } return returnvalue; } int getAllSimplePositionsMysqlSpatial(Connection *aDbConnection) { int returnvalue = 0; DataRow *p_new_station; int station_count = 0; // number of new stations retrieved char *s_lat[13]; // string latitude char *s_lon[13]; // string longitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string unsigned long u_lat; unsigned long u_long; int points_this_station; char feedback[100]; struct tm time; time_t sec; int skip; // used in identifying mobile stations char sql[] = "select station, transmit_time, AsText(position), symbol, overlay, aprstype, origin, record_type, node_path from simpleStationSpatial order by station, transmit_time asc"; char lastcall[MAX_CALLSIGN+1]; //holds last retrieved callsign int exists; //shortcut to skip db check if currently retrieved callsign equals last retrieved callsign MYSQL_RES *result; MYSQL_ROW row; char empty[MAX_ALTITUDE]; int ok; // to hold mysql_query return value empty[0]='\0'; ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { xastir_snprintf(feedback,100,"Retrieving MySQL records\n"); stderr_and_statusline(feedback); // with mysql_use_result each call to mysql_fetch_row retrieves // a row of data from the server. Mysql_store_result might use // too much memory in retrieving a large result set all at once. xastir_snprintf(lastcall,MAX_CALLSIGN+1," "); points_this_station=0; while ((row = mysql_fetch_row(result))) { // retrieve data from the row // test to see if this is a valid station if (row[0]==NULL) { // station is null, skip } else { p_new_station = NULL; exists = 0; // Shortcut check to see if station has allready been heard // works as query is ordered by station. if (strcmp(lastcall,row[0])==1) { exists = 1; points_this_station++; } else { if (search_station_name(&p_new_station,row[0],1)) { exists = 1; points_this_station++; } else { points_this_station=1; } } xastir_snprintf(lastcall,MAX_CALLSIGN+1,row[0]); if (exists==1) { // This station is allready in present as a DataRow in the xastir db. // check to see if this is likely to be a mobile station // We can't easily identify mobile stations from position position // because of rounding errors, therefore exclude stations that are likely to be fixed. // _/ = wx skip = 0; if ((strcmp(row[3],"_")==0) & (strcmp(row[5],"/")==0)) { skip = 1; // wx } if ((strcmp(row[3],"-")==0) & (strcmp(row[5],"/")==0)) { skip = 1; // house } if (skip==0) { // add to track if (search_station_name(&p_new_station,row[0],1)) { if (points_this_station<3) { //existing station record needs to be added as a trailpoint (void)store_trail_point(p_new_station, p_new_station->coord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } // store this trail point lat = xastirWKTPointToLatitude(row[2]); lon = xastirWKTPointToLongitude(row[2]); if (strlen(row[1]) > 0) { strptime(row[1], "%Y-%m-%d %H:%M:%S", &time); sec = mktime(&time); //fprintf(stderr,"trailpoint time: %ld [%s]\n", sec, row[1]); } if(convert_to_xastir_coordinates( &u_long, &u_lat, lon, lat)) { (void)store_trail_point(p_new_station, u_long, u_lat, sec, empty, empty, empty, 0); } if (p_new_station->sec_heard < sec) { // update the station record to this position if(convert_to_xastir_coordinates(&u_long, &u_lat, lon, lat)) { p_new_station->coord_lat = u_lat; p_new_station->coord_lon = u_long; p_new_station->sec_heard = sec; } } } // search_station_name } // !skip } else { // This station isn't in the xastir db. // Add a datarow using the retrieved station record from the postgis database. lat = xastirWKTPointToLatitude(row[2]); lon = xastirWKTPointToLongitude(row[2]); xastir_snprintf(s_lat,13,"%3.6f",lat); xastir_snprintf(s_lon,13,"%3.6f",lon); add_simple_station(p_new_station, row[0], row[6], row[3], row[4], row[5], s_lat, s_lon, row[7], row[8], row[1],(char*)MYSQL_TIMEFORMAT); station_count++; } } } } else { // error fetching the result set fprintf(stderr,"mysql error: %s\n",mysql_error(&aDbConnection->mhandle)); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); } xastir_snprintf(feedback,100,"Retrieved %d new stations from MySQL\n",station_count); stderr_and_statusline(feedback); mysql_free_result(result); } else { // query didn't execute correctly mysql_interpret_error(ok,aDbConnection); } return returnvalue; } int getAllCadFromGisDbMysql(Connection *aDbConnection) { int returnvalue = 0; int mysqlreturn; MYSQL *conn = &aDbConnection->mhandle; return returnvalue; } int getAllSimplePositionsMysqlSpatialInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat) { int returnvalue = 0; int mysqlreturn; MYSQL *conn = &aDbConnection->mhandle; return returnvalue; } /* // some thoughts on database schema elements create database xastir; grant select on xastir to user xastir_user@localhost identified by encrypted password ''; create table version ( version_number int, compatable_series int ); grant select on version to xastir_user@localhost insert into version (version_number) values (XASTIR_SPATIAL_DB_VERSION); insert into version (version_number) values (XASTIR_SPATIAL_DB_COMPATIBLE_SERIES); # should be minimum fields needed to populate a DataRow and a related # APRS_Symbol in xastir create table simpleStation ( simpleStationId int primary key not null auto_increment station varchar(MAX_CALLSIGN) not null, # callsign of station, length up to max_callsign symbol varchar(1), # aprs symbol character overlay varchar(1), # aprs overlay table character aprstype varchar(1), # aprs type, required??? transmit_time datetime not null default now(), # transmission time, if available, otherwise storage time position POINT # position of station or null if latitude and longitude are not available ); grant select, insert on simpleStation to xastir_user@localhost; create table datarow ( datarow_id int not null primary key auto_increment, call_sign varchar(10) not null, tactical_call_sign varchar() not null default '', c_aprs_symbol_id int location POINT, time_sn int, sec_heard long, heard_via_tnc_last_time long, direct_heard long, packet_time varchar, pos_time varchar, flag int, pos_amb varchar(1), error_ellipse_radius int, lon_precision int, lat_precision int, trail_color int, record_type varchar(1), data_via varchar(1), heard_via_tnc_port int, last_port_heard int, num_packets int, altitude varchar([MAX_ALTITUDE]), speed varchar([MAX_SPEED+1]), course varchar([MAX_COURSE+1]), bearing varchar([MAX_COURSE+1]), NRQ varchar([MAX_COURSE+1]), power_gain varchar([MAX_POWERGAIN+1]), signal_gain varchar([MAX_POWERGAIN+1]) ); */ #endif /* HAVE_MYSQL_SPATIAL */ #endif /* HAVE_SPATIAL_DB */ // Layer 3b: DBMS specific db storage code for non spatial databases ********** // Functions supporting queries to specific types of databases that lack // spatial extensions. Limited to storing points using latitude and longitude // fields without spatial objects or spatial indexing. // #ifdef HAVE_MYSQL // functions for MySQL database version < 4.1, or MySQL schema objects that don't // include spatial indices. // //********* Support for MySQL < 4.1 is depreciated ***************************** //********* Expect MySQL support to be limited to MySQL 5+ ********************** // /* function storeStationSimplePointToDbMysql() * MySQL implementation of wrapper storeStationSimplePointToGisDb(). * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeStationSimplePointToDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; // default return value is failure. int mysqlreturn = 1; // result of sending mysql query. char sql[400]; // Next three variables are one character in two bytes plus one character for // filling by mysql_real_escape_string(). char aprs_symbol[3]; // temporary holding for escaped aprs symbol char aprs_type[3]; // temporary holding for escaped aprs type char special_overlay[3]; // temporary holding for escaped overlay char record_type[3]; // temporary holding for escaped record type char from[3]; // temporary holding for all of the above length 3 variables char call_sign[(MAX_CALLSIGN)*2+1]; // temporary holding for escaped callsign char origin[(MAX_CALLSIGN)*2+1]; // temporary holding for escaped origin char node_path[(NODE_PATH_SIZE*2)+1]; // temporary holding for escaped node_path_ptr float longitude; float latitude; int ok; char timestring[100+1]; if (debug_level & 4096) { fprintf(stderr,"In storestationsimpletodbmysql()\n"); } // prepared statements not present below MySQL version 4.1 // details of prepared statement support changed between versions 4.1 and 5.0. // char [] sql = "insert into simpleStation (call, transmit_time, latitude, longitude) values ('%1','%2','%3','%4'))"; // call is a required element for a simple station if (aStation!=NULL && aStation->call_sign!=NULL && strlen(aStation->call_sign)>0) { // get time in seconds, adjust to datetime // If my station or another unset sec_heard is // encountered, use current time instead, use time // provided if it was invalid. get_iso_datetime(aStation->sec_heard,timestring,True,False); // get coord_lat, coord_long in xastir coordinates and convert to decimal degrees ok = convert_from_xastir_coordinates (&longitude, &latitude, aStation->coord_lon, aStation->coord_lat); // latitude and longitude are required elements for a simple station record. if (ok==1) { // build insert query with call, time, and position // handle special cases of null, \ and ' characters in type, symbol, and overlay. if (aStation->aprs_symbol.aprs_symbol) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.aprs_symbol); mysql_real_escape_string(&aDbConnection->mhandle,aprs_symbol,from,1); } else { xastir_snprintf(aprs_symbol,2,"%c",'\0'); } if (aStation->aprs_symbol.aprs_type) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.aprs_type); mysql_real_escape_string(&aDbConnection->mhandle,aprs_type,from,1); } else { xastir_snprintf(aprs_type,2,"%c",'\0'); } if (aStation->aprs_symbol.special_overlay) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.special_overlay); mysql_real_escape_string(&aDbConnection->mhandle,special_overlay,from,1); } else { xastir_snprintf(special_overlay,2,"%c",'\0'); } // Need to escape call sign - may contain special characters: // insert into simpleStation (station, symbol, overlay, aprstype, transmit_time, latitude, longitude) // values ('Fry's','/\0\0',' ','//\0','2007-08-07 21:55:43 -0400','47.496834','-122.198166') mysql_real_escape_string(&aDbConnection->mhandle,call_sign,(aStation->call_sign),strlen(aStation->call_sign)); // just in case, set a default value for record_type and escape it. if (aStation->record_type) { fprintf(stderr,"record_type: %c\n",aStation->record_type); xastir_snprintf(from,2,"%c",aStation->record_type); mysql_real_escape_string(&aDbConnection->mhandle,record_type,from,1); } else { xastir_snprintf(record_type,2,"%c",NORMAL_APRS); } if (strlen(aStation->origin) > 0) { mysql_real_escape_string(&aDbConnection->mhandle,origin,(aStation->origin),strlen(aStation->origin)); } else { xastir_snprintf(origin,2,"%c",'\0'); } if (aStation->node_path_ptr) { //mysql_real_escape_string(conn,&node_path,aStation->node_path_ptr,((strlen(aStation->node_path_ptr)*2)+1)); xastir_snprintf(node_path,sizeof(node_path),"%s",aStation->node_path_ptr); } else { xastir_snprintf(node_path,2,"%c",'\0'); } xastir_snprintf(sql,sizeof(sql),"insert into simpleStation (station, symbol, overlay, aprstype, transmit_time, latitude, longitude, origin, record_type, node_path) values ('%s','%s','%s','%s','%s','%3.6f','%3.6f','%s','%s','%s')", call_sign, aprs_symbol, special_overlay, aprs_type,timestring,latitude,longitude,origin,record_type,node_path); if (debug_level & 4096) { fprintf(stderr,"MySQL Query:\n%s\n",sql); } // send query mysql_ping(&aDbConnection->mhandle); mysqlreturn = mysql_real_query(&aDbConnection->mhandle, sql, strlen(sql)+1); if (mysqlreturn!=0) { // get the mysql error message fprintf(stderr,mysql_error(&aDbConnection->mhandle)); fprintf(stderr,"\n"); mysql_interpret_error(mysqlreturn,aDbConnection); } else { // insert query was successful, return value is ok. returnvalue=1; } } else { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } else { // set call not null error message xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Station callsign is required and was blank or null."); } return returnvalue; } /* function testXastirVersionMysql() * checks the xastir database version number of a connected MySQL database against the * version range supported by the running copy of xastir. * @param aDbConnection pointer to a Connection struct describing the connection * @returns 0 if incompatible, 1 if compatible, -1 on connection failure. * * db program * v cs v cs compatible * 1 1 1 1 1 identical * 2 1 1 1 1 database newer than program (added fields, not queried) * 1 1 2 1 0 program newer than database (added fields, queries fail). * 3 2 2 1 0 different series * 2 1 3 2 0 different series * * TODO: Need function to test for available schemas with mysql_list_tables() */ int testXastirVersionMysql(Connection *aDbConnection) { int returnvalue = -1; MYSQL_RES *result; MYSQL_ROW row; int version_number; int compatible_series; char sql[] = "select version_number, compatable_series from version order by version_number desc limit 1"; int ok; // to hold mysql_query return value ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { if ((row = mysql_fetch_row(result))) { version_number = atoi((char *)row[0]); if (version_number == XASTIR_SPATIAL_DB_VERSION) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is the same as this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { compatible_series = atoi((char *)row[1]); if (version_number < XASTIR_SPATIAL_DB_VERSION && compatible_series == XASTIR_SPATIAL_DB_COMPATABLE_SERIES) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { fprintf(stderr,"Version in schema (%d) is not compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version in schema (%d) is not compatible with this version of xastir (%d).",version_number,XASTIR_SPATIAL_DB_VERSION); fprintf(stderr,"%s",aDbConnection->errormessage); returnvalue = 0; } } } else { // result returned, but no rows = incompatible returnvalue = 0; fprintf(stderr,"Version table doesn't appear to contain any rows.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version table doesn't appear to contain any rows."); } } else { fprintf(stderr,"Schema doesn't appear to contain a version table.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Schema doesn't appear to contain a version table."); } mysql_free_result(result); } else { fprintf(stderr,"Query failed, Schema doesn't appear to contain a version table.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Query for version table failed."); } return returnvalue; } /* function storeStationToDbMysql() */ int storeStationToDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToDbMysql(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* function getAllSimplePositionsMysql() * MySQL implementation of getAllSimplePositions for a MySQL database that * does not include spatial support. * @param aDbConnection an exastir database connection struct describing * the connection. * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int getAllSimplePositionsMysql(Connection *aDbConnection) { int returnvalue = 0; DataRow *p_new_station; //DataRow *p_time; int station_count = 0; // number of new stations retrieved //unsigned long x; // xastir coordinate for longitude //unsigned long y; // xastir coordinate for latitude //float lat; // latitude converted from retrieved string //float lon; // longitude converted from retrieved string char feedback[100]; //struct tm time; char sql[] = "select station, transmit_time, latitude, longitude, symbol, overlay, aprstype, origin, record_type, node_path from simpleStation order by station, transmit_time"; MYSQL_RES *result; MYSQL_ROW row; int ok; // to hold mysql_query return value ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { xastir_snprintf(feedback,100,"Retrieving MySQL records\n"); stderr_and_statusline(feedback); // with mysql_use_result each call to mysql_fetch_row retrieves // a row of data from the server. Mysql_store_result might use // too much memory in retrieving a large result set all at once. while ((row = mysql_fetch_row(result))) { // retrieve data from the row // test to see if this is a valid station if (row[0]==NULL) { // station is null, skip } else { p_new_station = NULL; if (search_station_name(&p_new_station,row[0],1)) { // This station is allready in present as a DataRow in the xastir db. // Add data to the station's track. } else { // This station isn't in the xastir db. // Add a datarow using the retrieved station record from the postgis database. add_simple_station(p_new_station, row[0], row[7], row[4], row[5], row[6], row[2], row[3], row[8], row[9], row[1],(char*)MYSQL_TIMEFORMAT); station_count++; } } } } else { // error fetching the result set fprintf(stderr,"mysql error: %s\n",mysql_error(&aDbConnection->mhandle)); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); } xastir_snprintf(feedback,100,"Retrieved %d new stations from MySQL\n",station_count); stderr_and_statusline(feedback); mysql_free_result(result); } else { // query didn't execute correctly mysql_interpret_error(ok,aDbConnection); } return returnvalue; } int getAllSimplePositionsMysqlInBoundingBox(Connection *aDbConnection, char *str_e_long, char *str_w_long, char *str_n_lat, char *str_s_lat) { int returnvalue = 0; return returnvalue; } /* function mysql_interpret_error() * given a mysql error code and an xastir connection, sets an appropriate * error message in the errormessage field of the connection. Interprets * numeric error codes returned by mysql functions. * @param errorcode A result returned by a mysql function that can be * interpreted as an error code. * @param aDbConnection an xastir database connection struct describing the * connection and its current state. * Note - it is possible to give this function a connection on which an * error has not occurred along with an error code. This function does * not check the connection or assess whether an error actually occurred * on it or not, it simply interprets an error code and writes the * interpretation into the connection that was passed to it. */ void mysql_interpret_error(int errorcode, Connection *aDbConnection) { fprintf(stderr,"Error communicating with MySQL database. Error code=%d\n",errorcode); switch (errorcode) { case CR_OUT_OF_MEMORY : // insufficient memory for query xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Out of Memory"); // notify the connection status listener break; // mysql_query errors case CR_COMMANDS_OUT_OF_SYNC : // commands in improper order xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Commands out of sync"); break; case CR_SERVER_GONE_ERROR : // mysql server has gone away xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Connection to server lost"); // notify the connection status listener break; case CR_SERVER_LOST : // server connection was lost during query xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Connection to server lost during query"); // notify the connection status listener break; case CR_UNKNOWN_ERROR : xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Unknown Error"); break; default: xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Unrecognized error Code [%d]", errorcode); } fprintf(stderr,"%s\n",aDbConnection->errormessage); } #endif /* HAVE_MYSQL*/ // add code for a lightweight database here #endif /* HAVE_DB*/ // Functions related to GIS, but not database specific ************************ /* Function xastirCoordToLatLongPostgresPoint * converts a point in xastir coordinates to a native postgres representation * of a point using latitude and longitude in decimal degrees in the WGS84 * projection EPSG:4326. Format is similar to WKT, but without leading POINT. * @param x longitude in xastir coordinates = decimal 100ths of a second. * @param y latitude in xastir coordinates = decimal 100ths of a second. * @param pointer to a char[ at least 24] string to hold point representation. * returns 1 on success, 0 on failure. */ int xastirCoordToLatLongPostgresPoint(long x, long y, char *wkt) { // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 360000 xastir coordinates = 1 degree // conversion to string decimal degrees handled by utility functions int returnvalue = 0; // defaults to failure float latitude; float longitude; int ok; ok = convert_from_xastir_coordinates (&longitude,&latitude, x, y); if (ok>0) { xastir_snprintf(wkt, MAX_WKT, "(%3.6f, %3.6f)", latitude, longitude); returnvalue = 1; } return returnvalue; } /* Function xastirCoordToLatLongWKT * converts a point in xastir coordinates to a well known text string (WKT) * representation of a point using latitude and longitude in decimal degrees * in the WGS84 projection EPSG:4326 * @param x longitude in xastir coordinates = decimal 100ths of a second. * @param y latitude in xastir coordinates = decimal 100ths of a second. * @param pointer to a char[29] string to hold well known text representation. * returns 1 on success, 0 on failure. */ int xastirCoordToLatLongWKT(long x, long y, char *wkt) { // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 360000 xastir coordinates = 1 degree // conversion to string decimal degrees handled by utility functions int returnvalue = 0; // defaults to failure float latitude; float longitude; int ok; ok = convert_from_xastir_coordinates (&longitude,&latitude, x, y); if (ok>0) { xastir_snprintf(wkt, MAX_WKT, "POINT(%3.6f %3.6f)", longitude, latitude); returnvalue = 1; } return returnvalue; } float xastirWKTPointToLongitude(char *wkt) { float returnvalue = 0.0; char temp[MAX_WKT]; char *space = NULL; int x; if (wkt[0]=='P' && wkt[1]=='O' && wkt[2]=='I' && wkt[3]=='N' && wkt[4]=='T' && wkt[5]=='(') { // this is a point xastir_snprintf(temp, MAX_WKT, "%s", wkt); // truncate at the space space = strchr(temp,' '); if (space != NULL) { *space = '\0'; } // remove the leading "POINT(" for (x=0; x<6; x++) { temp[x]=' '; } returnvalue = atof(temp); } return returnvalue; } float xastirWKTPointToLatitude(char *wkt) { float returnvalue = 0.0; char temp[MAX_WKT]; char *paren = NULL; int x; if (wkt[0]=='P' && wkt[1]=='O' && wkt[2]=='I' && wkt[3]=='N' && wkt[4]=='T' && wkt[5]=='(') { // this is a point xastir_snprintf(temp, MAX_WKT, "%s", wkt); // truncate at the trailing parenthesis paren = strchr(temp,')'); if (paren != NULL) { *paren = '\0'; } // convert all leading characters up to the space to spaces. for (x=0; x<(int)(strlen(temp)); x++) { if (temp[x]==' ') { x = (int)(strlen(temp)); } else { temp[x] = ' '; } } returnvalue = atof(temp); } return returnvalue; } Xastir-Release-2.2.2/src/db_gis.h000066400000000000000000000162751501463444000165500ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include "xastir.h" #include "interface.h" // ioparam struct is used to store descriptions of databases // to which to connect. extern int xastirCoordToLatLongWKT(long x, long y, char *wkt); extern int xastirCoordToLatLongPoint(long x, long y, char *wkt); extern float xastirWKTPointToLatitude(char *wkt); extern float xastirWKTPointToLongitude(char *wkt); // maximum size of a well known text representation of a geometry // 100 should be fine for points, will need to be longer for other geometries. #define MAX_WKT 100 #ifdef HAVE_DB // maximum number of open database connections #define MAX_DB_CONNECTIONS 20 // includes for database client libraries and // constants to identify database types // constants are used in interface_gui.c // where the specify order on picklist // *** Need to localize these and the schema types *** #ifdef HAVE_MYSQL // MySQL version 3.x and higher #include // mysql error message codes #include #define DB_MYSQL 1 #endif /* HAVE_MYSQL */ #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS // Postgresql with postgis #include #define DB_POSTGIS 2 #define POSTGRES_RESULTFORMAT_TEXT 0 #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL // MySQL version 4.1 and higher #define DB_MYSQL_SPATIAL 3 #endif /* HAVE_MYSQL_SPATIAL */ #define MAX_DB_TYPE 3 // largest value for DB_ // used in load_data_or_default #define NODE_PATH_SIZE 56 // field size for node_path, for data_row.node_path_ptr // constants to control database schema versioning // Version of the mysql/postgresql table structures this version of xastir expects to find. // Any change or addition of database schema elements should trigger a version change. // Newer versions of xastir should require an older database to be upgraded to the // current version before allowing queries to run against that database. #define XASTIR_SPATIAL_DB_VERSION 1 // Allow grouping of forward compatible table structures allowing an older version of xastir to // interact with a database created by a newer version of xastir of the same compatble series // addition of new tables and fields shouldn't change comapatable series, but renamed, deleted, // or shortened schema elements should change compatible series (changes where a select or // or insert query run by an older version of xastir will fail against a newer database). #define XASTIR_SPATIAL_DB_COMPATABLE_SERIES 1 // constants to indicate schema to use in a database #define XASTIR_SCHEMA_SIMPLE 1 // simple station table only #define XASTIR_SCHEMA_CAD 2 // simple station table and cad objects #define XASTIR_SCHEMA_COMPLEX 3 // full aprs concept support #define XASTIR_SCHEMA_APRSWORLD 4 // aprs world implementation #define MAX_XASTIR_SCHEMA 4 // largest value for xastir_schema_ // used in load_data_or_default #define XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE 50 // largest allowed size of a localized schema descriptor string #define XASTIR_DB_DESCRIPTOR_MAX_SIZE 50 // largest allowed size of a localized dbms descriptor string // description of a database // replaced with extension of ioparam struct in interface.h /* typedef struct { char name[MAX_DEVICE_NAME+1]; // name of connection to display to user - ioparam device_name char host[255]; // hostname for database server - ioparam device_host_name int port; // port on which to connect to database server - ioparam sp char password[20]; // password to use to connect to database - ioparam device_host_password char username[20]; // username to use to connect to database int type; // type of dbms (posgresql, mysql, etc) char schema[20]; // name of database or schema to use char makeerrormessage[255]; // most recent error message from attempting to make a // connection with using this descriptor. int schema_type; // table structures to use in the database // A database schema could contain both APRSWorld // and XASTIR table structures, but a separate database // descriptor should be defined for each. char unix_socket[255]; // MySQL - unix socket parameter (path and filename) //connection_list open_connections // list of open connections to this database } DbDescriptor; */ #define MAX_CONNECTION_ERROR_MESSAGE 255 // a database connection typedef struct { int type; // type of dbms (postgresql, mysql, etc, redundant from descriptor->type) ioparam *descriptor; // connection parameters used to establish this connection // stored in ioparam struct defined in interface.h #ifdef HAVE_MYSQL MYSQL mhandle; // mysql connection #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS PGconn *phandle; // postgres connection #endif /* HAVE_POSTGIS */ char errormessage[MAX_CONNECTION_ERROR_MESSAGE]; // most recent error message on this connection. int interface_number; // number of the interface on which this connection is managed } Connection; // list of database connections //typedef struct{ // Connection *conn; // a database connection // ioparam *iface; // interface definition for the connection //} ConnectionList; //extern ConnectionList connections[MAX_IFACE_DEVICES]; extern Connection connections[MAX_IFACE_DEVICES]; extern int connections_initialized; // connection management extern int openConnection (ioparam *aioparm, Connection *conn); int initAConnection(Connection *connection, int x); extern int closeConnection (Connection *aDbConnection, int port_number); extern int testConnection(Connection *aDbConnection); int pingConnection(Connection *aDbConnection); extern char xastir_dbms_type[4][51]; extern char xastir_schema_type[5][51]; // storing and retrieving data from a database extern int storeStationToGisDb(Connection *aDbConnection, DataRow *aStation); extern int storeCadToGisDb(Connection *aDbConnection, CADRow *aCadObject); extern int storeStationSimpleToGisDb(Connection *aDbConnection, DataRow *aStation); extern int getAllSimplePositions(Connection *aDbConnection); extern int getAllSimplePositionsInBoundingBox(Connection *aDbConnection, int east, int west, int north, int south); extern ioparam simpleDbTest(void); #endif /* HAVE_SPATIAL_DB */ extern int initConnections(void); #endif /* HAVE_DB */ // structure to hold a latutude and longitude in decimal degrees typedef struct { float latitude; float longitude; } Point; Xastir-Release-2.2.2/src/dbfawk.c000066400000000000000000000240021501463444000165350ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ /* * This library glues the Awk-like functions (see awk.c) to attributes * for shapefiles (contained in DBF files). * * Alan Crosswell, n2ygk@weca.org * */ // // Functions which allocate memory: // -------------------------------- // dbfawk_field_list // dbfawk_load_sigs // dbfawk_find_sig // dbfawk_parse_record (indirectly) // // Functions which free memory: // ---------------------------- // dbfawk_free_info // dbfawk_load_sigs // dbfawk_free_sig // dbfawk_free_sigs // dbfawk_find_sig // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #include #include #include "awk.h" #include "dbfawk.h" #include "snprintf.h" #include "maps.h" #include // Must be last include file #include "leak_detection.h" /* * dbfawk_sig: Generate a signature for a DBF file. * Fills in sig and returns number of fields. */ int dbfawk_sig(DBFHandle dbf, char *sig, int size) { int nf = 0; if (sig && size > 0 && dbf) { int i; char *sp; int width,prec; nf = DBFGetFieldCount(dbf); for (i = 0, sp=sig; sp < &sig[size-XBASE_FLDHDR_SZ] && i < nf ; i++) { DBFGetFieldInfo(dbf,i,sp,&width,&prec); sp += strlen(sp); *sp++ = ':'; /* field name separator */ } if (i) { *--sp = '\0'; /* clobber the trailing sep */ } } return nf; } /* Free a field list */ void dbfawk_free_info ( dbfawk_field_info *list) { dbfawk_field_info *x, *p; for ( p = list; p != NULL; ) { x = p; p = p->next; free(x); } } /* * dbfawk_field_list: Generate a list of info about fields to read for * a given DBFHandle and colon-separated list of fieldnames. */ dbfawk_field_info *dbfawk_field_list(DBFHandle dbf, char *dbffields) { dbfawk_field_info *fi = NULL, *head = NULL, *prev; int nf; char *sp; /* now build up the list of fields to read */ for (nf = 0, sp = dbffields, prev = NULL; *sp; nf++) { char *d,*p = sp; char junk[XBASE_FLDHDR_SZ]; int w,prec; fi = calloc(1,sizeof(dbfawk_field_info)); if (!fi) { fprintf(stderr,"dbfawk_field_list: first calloc failed\n"); return NULL; } if (prev) { prev->next = fi; } else /* no prev, must be first one */ { head = fi; } d = fi->name; while (*p && *p != ':') { *d++ = *p++; } if (*p == ':') { *p++ = '\0'; } *d='\0'; fi->num = DBFGetFieldIndex(dbf, fi->name); fi->type = DBFGetFieldInfo(dbf, fi->num, junk, &w, &prec); sp = p; prev = fi; } return head; } /* * dbfawk_load_sigs: Load up dbfawk signature mappings * Reads *.dbfawk and registers dbffields "signature". * Returns head of sig_info list. * * TODO - consider whether it makes sense to use a private symtbl, * compile and then free here or require the caller to pass in a * symtbl that has dbfinfo declared. */ // Malloc's dbfawk_sig_info and returns a filled-in list dbfawk_sig_info *dbfawk_load_sigs(const char *dir, /* directory path */ const char *ftype) /* filetype */ { DIR *d; struct dirent *e; struct stat nfile; char fullpath[MAX_FILENAME]; int ftlen; dbfawk_sig_info *i = NULL, *head = NULL; awk_symtab *symtbl; char dbfinfo[1024]; /* local copy of signature */ if (!dir || !ftype) { return NULL; } ftlen = strlen(ftype); d = opendir(dir); if (!d) { return NULL; } symtbl = awk_new_symtab(); if (!symtbl) { return NULL; } awk_declare_sym(symtbl,"dbfinfo",STRING,dbfinfo,sizeof(dbfinfo)); while ((e = readdir(d)) != NULL) { int len = strlen(e->d_name); char *path = calloc(1,len+strlen(dir)+2); // Check for hidden files or directories if (e->d_name[0] == '.') { // Hidden, skip it free(path); continue; } // Check for regular files xastir_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, e->d_name); if (stat(fullpath, &nfile) != 0) { // Couldn't stat file free(path); continue; } if ((nfile.st_mode & S_IFMT) != S_IFREG) { // Not a regular file free(path); continue; } if (!path) { if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } fprintf(stderr,"failed to malloc in dbfawk.c!\n"); closedir(d); return NULL; } *dbfinfo = '\0'; if (len > ftlen && (strcmp(&e->d_name[len-ftlen],ftype) == 0)) { if (!head) { i = head = calloc(1,sizeof(dbfawk_sig_info)); if (!i) { fprintf(stderr,"failed to malloc in dbfawk.c!\n"); free(path); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } closedir(d); return NULL; } } else { i->next = calloc(1,sizeof(dbfawk_sig_info)); if (!i->next) { fprintf(stderr,"failed to malloc in dbfawk.c!\n"); free(path); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } closedir(d); return head; // Return what we were able to gather. } i = i->next; } xastir_snprintf(path, len+strlen(dir)+2, "%s/%s", dir, e->d_name); i->prog = awk_load_program_file(path); if (awk_compile_program(symtbl,i->prog) < 0) { fprintf(stderr,"%s: failed to parse\n",e->d_name); } else { /* dbfinfo must be defined in BEGIN rule */ awk_exec_begin(i->prog); i->sig = strdup(dbfinfo); awk_uncompile_program(i->prog); } } free(path); } closedir(d); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } return head; } void dbfawk_free_sig(dbfawk_sig_info *ptr) { if (ptr) { if (ptr->prog) { awk_free_program(ptr->prog); } if (ptr->sig) { free(ptr->sig); } free(ptr); } } void dbfawk_free_sigs(dbfawk_sig_info *list) { dbfawk_sig_info *x, *p; for (p = list; p; ) { x = p; p = p->next; dbfawk_free_sig(x); } } /* * dbfawk_find_sig: Given a DBF file's "signature", find the appropriate * awk program. If filename is not null, see if there's a per-file .dbfawk * and load it. */ dbfawk_sig_info *dbfawk_find_sig(dbfawk_sig_info *Dbf_sigs, const char *sig, const char *file) { dbfawk_sig_info *result = NULL; if (file) { int perfilesize=strlen(file)+8; char *dot, *perfile = calloc(1,perfilesize); dbfawk_sig_info *info; if (!perfile) { fprintf(stderr,"failed to malloc in dbfawk_find_sig!\n"); return NULL; } xastir_snprintf(perfile, perfilesize-1, "%s", file); dot = strrchr(perfile,'.'); if (dot) { *dot = '\0'; } strncat(perfile, ".dbfawk", perfilesize-1); info = calloc(1,sizeof(*info)); if (!info) { fprintf(stderr,"failed to malloc in dbfawk_find_sig!\n"); free(perfile); return NULL; } info->prog = awk_load_program_file(perfile); /* N.B. info->sig is left NULL since it won't be searched, and to flag that it's safe to free this memory when we're done with it */ info->sig = NULL; free(perfile); if (info->prog) { return info; } else { dbfawk_free_sigs(info); } /* fall through and do normal signature search */ } for (result = Dbf_sigs; result; result = result->next) { if (strcmp(result->sig,sig) == 0) { return result; } } return NULL; } /* * dbfawk_parse_record: Read a dbf record and parse only the fields * listed in 'fi' using the program, 'rs'. */ void dbfawk_parse_record(awk_program *rs, DBFHandle dbf, dbfawk_field_info *fi, int i) { dbfawk_field_info *finfo; awk_exec_begin_record(rs); /* execute a BEGIN_RECORD rule if any */ for (finfo = fi; finfo ; finfo = finfo->next) { char qbuf[1024]; switch (finfo->type) { case FTString: sprintf(qbuf,"%s=%s",finfo->name,DBFReadStringAttribute(dbf,i,finfo->num)); break; case FTInteger: sprintf(qbuf,"%s=%d",finfo->name,DBFReadIntegerAttribute(dbf,i,finfo->num)); break; case FTDouble: sprintf(qbuf,"%s=%f",finfo->name,DBFReadDoubleAttribute(dbf,i,finfo->num)); break; case FTInvalid: default: sprintf(qbuf,"%s=??",finfo->name); break; } if (awk_exec_program(rs,qbuf,strlen(qbuf)) == 2) { break; } } awk_exec_end_record(rs); /* execute an END_RECORD rule if any */ } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.2/src/dbfawk.h000066400000000000000000000046741501463444000165570ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef DBFAWK_H #define DBFAWK_H #ifndef _SHAPEFILE_H_INCLUDED #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #endif // _SHAPEFILE_H_INCLUDED typedef struct dbfawk_field_info_ { struct dbfawk_field_info_ *next; char name[XBASE_FLDHDR_SZ]; /* name of the field */ int num; /* column number */ DBFFieldType type; /* data type */ } dbfawk_field_info; typedef struct dbfawk_sig_info_ { struct dbfawk_sig_info_ *next; char *sig; /* dbfinfo signature */ awk_program *prog; /* the program for this signature */ } dbfawk_sig_info; extern int dbfawk_sig(DBFHandle dbf, char *sig, int size); extern dbfawk_field_info *dbfawk_field_list(DBFHandle dbf, char *dbffields); extern dbfawk_sig_info *dbfawk_load_sigs(const char *dir, const char *ftype); extern dbfawk_sig_info *dbfawk_find_sig(dbfawk_sig_info *info, const char *sig, const char *file); extern void dbfawk_free_sig(dbfawk_sig_info *sig); extern void dbfawk_free_sigs(dbfawk_sig_info *list); extern void dbfawk_free_info(dbfawk_field_info *list); extern void dbfawk_parse_record(awk_program *rs, DBFHandle dbf, dbfawk_field_info *fi, int i); #endif /* !DBFAWK_H*/ Xastir-Release-2.2.2/src/dlm.c000066400000000000000000000734151501463444000160670ustar00rootroot00000000000000/* * * $Id: dlm.c,v 1.10 2018/07/14 21:32:43 MikeNix Exp $ * * Copyright (C) 2018-2023 The Xastir Group * * This file was contributed by Mike Nix. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #ifdef HAVE_LIBCURL #include #endif #include "xastir.h" #include "maps.h" // only for MAX_FILENAME #include "main.h" #include "dlm.h" // Must be last include file #include "leak_detection.h" /********************************************************** * DLM - DownLoad Manager - manage a list of items to download **********************************************************/ /* Notes on curl_multi and the tile queue: We could have used a thread for each transfer, but that's messy and wasteful. We could have used the curl_multi list as the queue, but that would end up with us either waiting until the last few tiles were downloading before returning, or just adding all the tiles and letting curl go for it - which could end up with hundreds of simultaneous transfers, although curl is supposed to have a limiter of some kind, it delivers no control over what order to process the queue. Our approach is to queue all the tiles in our own queue, and return immediately while letting a download thread feed curl the most recently added tiles first. This way, if you scroll past an area, the tiles will all be queued for checking but we will always start downloading tiles in the current view (ie most recently added) first - without cancelling any tiles already started. Mini HowTo: in your drawing function, before reading tiles, do this: DLM_queue_tile(...) each map tile you want call DLM_do_transfers() - this only does anything if the DLM was compiled with threading disabled optionally call DLM_wait_done() if you want to wait for all downloads to finish Draw your maps using the tiles available in your cache. When each download completes, the global request_new_image is incremented which triggers a redraw from the top level. It is safe to repeat this whole sequence at each redraw as tiles are only added to the queue if they are not in the queue already and the file does not exist, or the file is older than 7 days. */ // Enable use of a separate download thread in the background #define DLM_QUEUE_THREADED // Enable using curl_multi_* to download more than one tile at a time // Define this to use the code, set the number to limit the // simultaneous transfers // WARNING: defining this less than 1 will allow starting an unlimited number // of transfers. You probably shouldn't do that! // Also, don't set this too high or slow internet connections will have to // wait too long before starting to download tiles in the current view // when the user scrolls around a bit #define USE_CURL_MULTI 8 #define DLM_Q_STOP 0 #define DLM_Q_STARTING 1 #define DLM_Q_RUN 5 #define DLM_Q_IDLE 8 #define DLM_Q_QUIT 9 #define MAX_DESCLEN 40 struct DLM_queue_entry { struct DLM_queue_entry *next; struct DLM_queue_entry *prev; // These are only used by DLM_queue_tile for // checking if a tile is already queued // osm_zl is also used as a type flag (>=0 for tile, <0 for file) unsigned long x; unsigned long y; int osm_zl; int state; xastir_mutex lock; char fileName[MAX_FILENAME]; char desc[MAX_DESCLEN]; char *tempName; char *url; #ifdef HAVE_LIBCURL FILE *stream; #ifdef USE_CURL_MULTI char *curlErrBuf; CURL *curlSession; #endif #endif }; /* DLM_queue_lock is held whenever reading or changing DLM_queue_entry or * the linkages of the items in the queue. Each item also has a lock * for changing data in that item. */ xastir_mutex DLM_queue_lock = { .threadID=0, .lock=PTHREAD_MUTEX_INITIALIZER }; pthread_t DLM_queue_thread; volatile int DLM_queue_progress_flag=0; /* DLM_queue_state is protected by a lock to ensure memory consistency * between threads. It is held for every read or write of DLM_queue_state */ xastir_mutex DLM_state_lock = { .threadID=0, .lock=PTHREAD_MUTEX_INITIALIZER }; volatile int DLM_queue_state=DLM_Q_STOP; struct DLM_queue_entry *DLM_queue=NULL; void (*DLM_progress_callback)(void)=NULL; /********************************************************** * DLM_get_queue_state - Read DLM_queue_state while * ensuring it is locked **********************************************************/ static int DLM_get_queue_state(void) { int state; begin_critical_section(&DLM_state_lock, "DLM_get_queue_state"); state = DLM_queue_state; end_critical_section(&DLM_state_lock, "DLM_get_queue_state"); return state; } /********************************************************** * DLM_wait_done - wait until the transfers are all complete * returns the number of items in the queue if it timed out **********************************************************/ int DLM_wait_done(time_t timeout) { #ifdef DLM_QUEUE_THREADED while ((timeout > 0) && (DLM_get_queue_state() == DLM_Q_RUN)) { sleep(1); timeout--; } #else if (DLM_queue_len()>0) { DLM_do_transfers(); } #endif return DLM_queue_len(); } /********************************************************** * DLM_check_progress - check if we have more tiles since last call **********************************************************/ int DLM_check_progress(void) { int p=DLM_queue_progress_flag; DLM_queue_progress_flag=0; return p; } /********************************************************** * DLM_queue_progress - called when new tiles are available **********************************************************/ static void DLM_queue_progress(int prog) { if (prog) { DLM_queue_progress_flag=1; // trigger a redraw of the screen request_new_image++; if (DLM_progress_callback!=NULL) { DLM_progress_callback(); } } } /********************************************************** * DLM_queue_len - return number of tiles queued for download/check **********************************************************/ int DLM_queue_len(void) { struct DLM_queue_entry *q=DLM_queue; int count=0; begin_critical_section(&DLM_queue_lock, "DLM_queue_len"); while (q) { count++; q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_len"); //fprintf(stderr,"DLM_queue_len is %d\n", count); return count; } /********************************************************** * abort_DLM_queue_abort() - stop the transfer thread **********************************************************/ void DLM_queue_abort(void) { begin_critical_section(&DLM_state_lock, "DLM_queue_abort"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_queue_abort"); //fprintf(stderr, "DLM_queue aborting\n"); } /********************************************************** * DLM_queue_entry_alloc() - allocate a queue entry **********************************************************/ static struct DLM_queue_entry *DLM_queue_entry_alloc(void) { return malloc(sizeof(struct DLM_queue_entry)); } /********************************************************** * DLM_queue_entry_free() - free memory used by a tile queue entry **********************************************************/ static void DLM_queue_entry_free(struct DLM_queue_entry *q) { if (q) { begin_critical_section(&DLM_queue_lock, "DLM_queue_entry_free:Queue Lock"); begin_critical_section(&(q->lock), "DLM_queue_entry_free:tile lock"); //fprintf(stderr, "DLM_queue_free %s, ishead=%d\n", q->desc, DLM_queue_entry == q); if ((q->state==DLM_Q_IDLE) || (q->state==DLM_Q_STOP)) { // mark as being freed, just in case q->state=-1; // if we are the head of the queue, it needs updating if (DLM_queue == q) { DLM_queue = q->next; } // remove this entry from whatever list it's in if (q->next) { q->next->prev = q->prev; } if (q->prev) { q->prev->next = q->next; } // free anything we point to if (q->url) { free(q->url); } if (q->tempName) { free(q->tempName); } // if (q->serverURL) free(q->serverURL); // if (q->baseDir) free(q->baseDir); // if (q->ext) free(q->ext); #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI if (q->curlErrBuf) { free(q->curlErrBuf); } if (q->curlSession) { curl_easy_cleanup(q->curlSession); } if (q->stream) { fclose(q->stream); } #endif #endif // free us end_critical_section(&(q->lock), "DLM_queue_entry_free:tile unlock"); free(q); } else { end_critical_section(&(q->lock), "DLM_queue_entry_free:tile_unlock"); } end_critical_section(&DLM_queue_lock, "DLM_queue_entry_free:Queue_unlock"); } } /********************************************************** * DLM_queue_destroy() - free all entries in the queue **********************************************************/ static void DLM_queue_destroy(void) { struct DLM_queue_entry *next, *q; int count=0; q = DLM_queue; while (q) { next=q->next; if (q->state==DLM_Q_IDLE) { DLM_queue_entry_free(q); count++; } q=next; } //fprintf(stderr, "DLM_queue_destroy: %d entries dropped\n", count); } /********************************************************** * DLM_queue_abort_tiles() - free all tiles in the queue **********************************************************/ void DLM_queue_abort_tiles(void) { struct DLM_queue_entry *next, *q; int count=0; q = DLM_queue; while (q) { next=q->next; if ((q->state==DLM_Q_IDLE) && (q->osm_zl>=0)) { DLM_queue_entry_free(q); count++; } q=next; } //fprintf(stderr, "DLM_queue_abort_tiles: %d entries dropped\n", count); } /********************************************************** * DLM_queue_abort_files() - free all non-tiles in the queue **********************************************************/ void DLM_queue_abort_files(void) { struct DLM_queue_entry *next, *q; int count=0; q = DLM_queue; while (q) { next=q->next; if ((q->state==DLM_Q_IDLE) && (q->osm_zl<0)) { DLM_queue_entry_free(q); count++; } q=next; } //fprintf(stderr, "DLM_queue_abort_files: %d entries dropped\n", count); } /********************************************************** * DLM_store_file() - move the temp file into place if we used one **********************************************************/ static int DLM_store_file(struct DLM_queue_entry *q) { int rc; if (!q->tempName) { return 0; } //unlink(t->fileName); // not needed on Linux (the other OS?) if ((rc=rename(q->tempName, q->fileName))) { fprintf(stderr, "DLM_transfer_thread: unable to rename %s->%s: errno=%d\n", q->tempName, q->fileName, errno); } else { free(q->tempName); q->tempName=NULL; } return rc; } /********************************************************** * DLM_get_next_tile() - find the next idle tile ready for download * also locks that tile **********************************************************/ static struct DLM_queue_entry *DLM_get_next_tile(int state) { struct DLM_queue_entry *q; begin_critical_section(&DLM_queue_lock, "DLM_transfer_thread: queue lock"); q = DLM_queue; while (q && (q->state!=state)) { q=q->next; } if (q) { begin_critical_section(&(q->lock), "DLM_transfer_thread: tile lock"); } end_critical_section(&DLM_queue_lock, "DLM_transfer_thread: queue unlock"); return q; } #ifdef HAVE_LIBCURL /********************************************************** * DLM_curl_fwrite_callback() - callback for curl_multi **********************************************************/ static size_t DLM_curl_fwrite_callback(void *buffer, size_t size, size_t nmemb, void *stream) { struct DLM_queue_entry *out = (struct DLM_queue_entry *)stream; if (out && !out->stream) { out->stream=fopen((out->tempName ? out->tempName : out->fileName), "wb"); //fprintf(stderr,"DLM_curl_fwrite_callback: Opening %s\n", out->fileName); if (!out->stream) { return -1; } } return fwrite(buffer, size, nmemb, out->stream); } /********************************************************** * DLM_curl_progress_callback() - callback for curl_multi **********************************************************/ static int DLM_curl_progress_callback(void *p, double UNUSED(dltotal), double UNUSED(dlnow), double UNUSED(ultotal), double UNUSED(ulnow) ) { struct DLM_queue_entry *tile = (struct DLM_queue_entry *)p; if (!tile) { return 0; } // possibly update some display somewhere? return 0; } /********************************************************** * DLM_curl_set_queue_entry() - curl session options we can't set * at initialization in some cases. **********************************************************/ static void DLM_curl_set_queue_entry(CURL *mySession, struct DLM_queue_entry *qentry) { curl_easy_setopt(mySession, CURLOPT_FILE, qentry); curl_easy_setopt(mySession, CURLOPT_PROGRESSDATA, qentry); curl_easy_setopt(mySession, CURLOPT_PRIVATE, qentry); #ifdef USE_CURL_MULTI qentry->curlSession = mySession; #endif } /********************************************************** * DLM_curl_init() - prep a curl handle our way * **********************************************************/ static CURL *DLM_curl_init(char *errBuf) { CURL *mySession; char agent_string[15]; mySession = curl_easy_init(); if (mySession != NULL) { if (debug_level & 8192) { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 1); } else { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 0); } curl_easy_setopt(mySession, CURLOPT_ERRORBUFFER, errBuf); xastir_snprintf(agent_string, sizeof(agent_string),"Xastir"); curl_easy_setopt(mySession, CURLOPT_USERAGENT, agent_string); // write and progress functions curl_easy_setopt(mySession, CURLOPT_WRITEFUNCTION, DLM_curl_fwrite_callback); curl_easy_setopt(mySession, CURLOPT_PROGRESSFUNCTION, DLM_curl_progress_callback); curl_easy_setopt(mySession, CURLOPT_TIMEOUT, (long)net_map_timeout); curl_easy_setopt(mySession, CURLOPT_CONNECTTIMEOUT, (long)(net_map_timeout/2)); // Added in libcurl 7.9.8 #if (LIBCURL_VERSION_NUM >= 0x070908) curl_easy_setopt(mySession, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.6 #if (LIBCURL_VERSION_NUM >= 0x071006) curl_easy_setopt(mySession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.7 #if (LIBCURL_VERSION_NUM >= 0x071007) curl_easy_setopt(mySession, CURLOPT_PROXYAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10 #if (LIBCURL_VERSION_NUM >= 0x070a00) // This prevents a segfault for the case where we get a timeout on // domain name lookup. It has to do with the ALARM signal // and siglongjmp(), which we use in hostname.c already. // This URL talks about it a bit more, plus see the libcurl // docs: // // http://curl.haxx.se/mail/lib-2002-12/0103.html // curl_easy_setopt(mySession, CURLOPT_NOSIGNAL, 1); #endif // LIBCURL_VERSION_NUM } return(mySession); } // DLM_curl_init() #endif // HAVE_LIBCURL /********************************************************** * DLM_transfer_thread() - retrieve item queued for download **********************************************************/ static void *DLM_transfer_thread(void * UNUSED(arg) ) { struct DLM_queue_entry *tile; #ifdef DLM_QUEUE_THREADED int idleCnt; #endif #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI CURLM *multiSession; CURLMsg *msg; int msgsLeft; int runningTransfers; #else CURL *mySession; char errBuf[CURL_ERROR_SIZE]; int curl_result; #endif #endif // HAVE_LIBCURL // detach - we don't care about the result, and won't be calling pthread_join() pthread_detach(pthread_self()); begin_critical_section(&DLM_state_lock, "DLM_transfer_thread set to run"); DLM_queue_state = DLM_Q_RUN; end_critical_section(&DLM_state_lock, "DLM_transfer_thread set to run"); #ifdef DLM_QUEUE_THREADED idleCnt=0; #endif if (debug_level & 1) { fprintf(stderr, "DLM_transfer_thread started\n"); } #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI multiSession = curl_multi_init(); runningTransfers=0; #else mySession = DLM_curl_init(errBuf); #endif #endif // HAVE_LIBCURL // get the tiles while (DLM_get_queue_state() != DLM_Q_QUIT) { #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI curl_multi_perform(multiSession, &runningTransfers); // handle any "download complete" messages from curl while ((msg=curl_multi_info_read(multiSession, &msgsLeft))) { if (msg->msg==CURLMSG_DONE) { if (msg->easy_handle) { struct DLM_queue_entry *t; curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (void *)&t); t->state=DLM_Q_STOP; if (t->stream) { fclose(t->stream); t->stream=NULL; } if (msg->data.result != 0) { fprintf(stderr, "CURL error downloading %s: %d\nURL:%s\n%s\n", t->desc, msg->data.result, t->url, t->curlErrBuf); } if ((msg->data.result==0) && (!DLM_store_file(t))) { DLM_queue_progress(1); } else { unlink(t->tempName); } //fprintf(stderr,"DLM_transfer_queue: completed item %s\n",t->desc); curl_multi_remove_handle(multiSession, msg->easy_handle); curl_easy_cleanup(msg->easy_handle); t->curlSession=NULL; DLM_queue_entry_free(t); } } else { fprintf(stderr, "CURL Message: (%d)\n", msg->msg); } } #ifdef DLM_QUEUE_THREADED if (runningTransfers>0) { idleCnt=0; } #endif if ((USE_CURL_MULTI < 1) || (runningTransfers < USE_CURL_MULTI)) { #endif #endif // get the next tile that is idle. Tile is locked for us tile=DLM_get_next_tile(DLM_Q_IDLE); if (tile) { tile->state = DLM_Q_RUN; #ifdef DLM_QUEUE_THREADED idleCnt=0; #endif end_critical_section(&(tile->lock), "DLM_transfer_thread: tile unlock"); //fprintf(stderr,"DLM_transfer_queue: started item %s, qlen=%d\n",tile->desc,DLM_queue_len()); #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI if (!tile->curlErrBuf) { tile->curlErrBuf=malloc(CURL_ERROR_SIZE); } if (!tile->curlSession) { tile->curlSession=DLM_curl_init(tile->curlErrBuf); } DLM_curl_set_queue_entry(tile->curlSession, tile); curl_easy_setopt(tile->curlSession, CURLOPT_URL, tile->url); curl_easy_setopt(tile->curlSession, CURLOPT_FAILONERROR, 1); curl_multi_add_handle(multiSession, tile->curlSession); #else // USE_CURL_MULTI DLM_curl_set_queue_entry(mySession, tile); curl_easy_setopt(mySession, CURLOPT_URL, tile->url); curl_easy_setopt(mySession, CURLOPT_FAILONERROR, 1); curl_result = curl_easy_perform(mySession); if (tile->stream) { fclose(tile->stream); tile->stream=NULL; } if (curl_result != CURLE_OK) { fprintf(stderr, "Download error for %s: curl result %d\nURL:%s\ncurlerr:%s", tile->desc, curl_result, tile->url, errBuf); } else { if (!DLM_store_file(tile)) { DLM_queue_progress(1); } } #endif // USE_CURL_MULTI #else // HAVE_LIBCURL // We have no other option - use wget, one file at a time { char cmd[500]; xastir_snprintf(cmd, sizeof(cmd), "%s --server-response --user-agent=Xastir --tries=1 --timeout=%d --output-document=\'%s\' \'%s\' 2> /dev/null\n", "wget", net_map_timeout, (tile->tempName ? tile->tempName : tile->fileName), tile->url); if (system(cmd)) { fprintf(stderr, "Couldn't download the file with wget\n"); } else { if (!DLM_store_file(tile)) { DLM_queue_progress(1); } } } #endif // HAVE_LIBCURL #if defined(HAVE_LIBCURL) && defined(USE_CURL_MULTI) #else tile->state = DLM_Q_STOP; //fprintf(stderr,"DLM_transfer_queue: done item %s\n",tile->desc); DLM_queue_entry_free(tile); #endif #ifdef DLM_QUEUE_THREADED } else if (idleCnt < 10) { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread idle check"); DLM_queue_state = DLM_Q_IDLE; end_critical_section(&DLM_state_lock, "DLM_transfer_thread idle check"); //fprintf(stderr,"DLM_transfer_queue: idling\n"); sleep(1); idleCnt++; #endif } else { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread set quit"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_transfer_thread set quit"); } #ifndef DLM_QUEUE_THREADED HandlePendingEvents(app_context); if (interrupt_drawing_now) { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread interrupt quit"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_transfer_thread interrupt quit"); } #endif #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI } usleep(100000); // 0.1 seconds - don't hog the CPU :) // also limits us to starting 10 downloads/second // and staggers the downloads a bit #endif #endif } #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI curl_multi_cleanup(multiSession); #else curl_easy_cleanup(mySession); #endif #endif // HAVE_LIBCURL DLM_queue_destroy(); if (debug_level & 1) { fprintf(stderr,"DLM_transfer_thread stopped\n"); } begin_critical_section(&DLM_state_lock, "DLM_transfer_thread stop update"); DLM_queue_state = DLM_Q_STOP; end_critical_section(&DLM_state_lock, "DLM_transfer_thread stop update"); return NULL; } /********************************************************** * DLM_queue_start_if_needed() * Start the transfers if they need starting **********************************************************/ static void DLM_queue_start_if_needed(void) { #ifdef DLM_QUEUE_THREADED if (DLM_get_queue_state() == DLM_Q_STOP) { // start the thread // Queue state lock not needed as there is no other thread running here DLM_queue_state = DLM_Q_STARTING; if (pthread_create(&DLM_queue_thread, NULL, DLM_transfer_thread, NULL)) { //fprintf(stderr,"Error creating OSM transfer thread\n"); DLM_queue_state = DLM_Q_STOP; } } #endif } /********************************************************** * DLM_do_transfers() - download all tiles now * Does nothing if we are in threaded mode **********************************************************/ void DLM_do_transfers(void) { #ifdef DLM_QUEUE_THREADED if (DLM_queue_len()>0) { DLM_queue_start_if_needed(); } #else DLM_transfer_thread(NULL); #endif } /********************************************************** * DLM_queue_add() - Queue a prepared entry for download. * Internal use only - no checking is done! **********************************************************/ static void DLM_queue_add(struct DLM_queue_entry *ent) { if (ent->url && ent->tempName) { // if the thread is quitting, wait till it's done while (DLM_get_queue_state() == DLM_Q_QUIT); // queue this tile //fprintf(stderr,"OSM queueing %s, qlen=%d\n",tile->fileName,DLM_queue_len()); begin_critical_section(&DLM_queue_lock, "DLM_queue_add"); if (DLM_queue) { DLM_queue->prev=ent; } ent->next = DLM_queue; DLM_queue = ent; end_critical_section(&DLM_queue_lock, "DLM_queue_add"); DLM_queue_start_if_needed(); } else { DLM_queue_entry_free(ent); } } /********************************************************** * DLM_queue_tile() - queue map tiles for download * Written for OpenStreetMap but generic enough to live here. **********************************************************/ void DLM_queue_tile( char *serverURL, unsigned long x, unsigned long y, int osm_zl, char *baseDir, char *ext ) { struct DLM_queue_entry *tile, *q; struct stat sb; int len; // see if it's already queued begin_critical_section(&DLM_queue_lock, "DLM_queue_tile:check queue"); q=DLM_queue; while (q && ((q->x!=x) || (q->y!=y) || (q->osm_zl!=osm_zl) )) { q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_tile:check queue"); if (q) { //fprintf(stderr, "OSM %s already queued\n", q->desc); return; } tile=DLM_queue_entry_alloc(); if (!tile) { return; } tile->next = NULL; tile->prev = NULL; // tile->serverURL = strndup(serverURL, MAX_FILENAME); // tile->baseDir = strndup(baseDir, MAX_FILENAME); // tile->ext = strndup(ext, MAX_FILENAME); tile->x = x; tile->y = y; tile->osm_zl = osm_zl; tile->state = DLM_Q_IDLE; tile->url = NULL; tile->fileName[0]='\0'; init_critical_section(&(tile->lock)); #ifdef HAVE_LIBCURL tile->stream=NULL; #ifdef USE_CURL_MULTI tile->curlErrBuf=NULL; tile->curlSession=NULL; #endif #endif xastir_snprintf(tile->desc, sizeof(tile->desc), "Tile:%u/%lu/%lu", osm_zl, x, y); xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%u/%lu/%lu.%s", osm_zl, x, y, ext); len = strlen(serverURL) + strlen(tile->fileName) +2; tile->url = malloc(len); if (tile->url) { xastir_snprintf(tile->url, len, "%s/%s", serverURL, tile->fileName); } xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s/%u/%lu/%lu.%s.part", baseDir, osm_zl, x, y, ext); tile->tempName = strdup(tile->fileName); xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s/%u/%lu/%lu.%s", baseDir, osm_zl, x, y, ext); // if we have the file and it's < 7 days old, don't queue it if (stat(tile->fileName, &sb) != -1) { if ((sb.st_mtime + (7 * 24 * 60 * 60)) >= time(NULL)) { //fprintf(stderr,"%s is fresh in cache\n", tile->fileName); tile->state=DLM_Q_STOP; DLM_queue_entry_free(tile); return; } } DLM_queue_add(tile); } /********************************************************** * DLM_queue_file() - Queue a file for download. **********************************************************/ void DLM_queue_file( char *url, char *filename, time_t expiry ) { struct DLM_queue_entry *tile, *q; struct stat sb; char *p; // see if it's already queued begin_critical_section(&DLM_queue_lock, "DLM_queue_file:check queue"); q=DLM_queue; while (q && (q->osm_zl>=0) && strncmp(filename,q->fileName,sizeof(q->fileName))) { q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_file:check queue"); if (q) { //fprintf(stderr, "OSM %s already queued\n", filename); return; } tile=DLM_queue_entry_alloc(); if (!tile) { return; } tile->next = NULL; tile->prev = NULL; // tile->serverURL = strndup(serverURL, MAX_FILENAME); // tile->baseDir = strndup(baseDir, MAX_FILENAME); // tile->ext = strndup(ext, MAX_FILENAME); tile->x = 0; tile->y = 0; tile->osm_zl = -1; tile->state = DLM_Q_IDLE; tile->url = strdup(url); init_critical_section(&(tile->lock)); #ifdef HAVE_LIBCURL tile->stream=NULL; #ifdef USE_CURL_MULTI tile->curlErrBuf=NULL; tile->curlSession=NULL; #endif #endif p=filename; while (p && *p) { p++; } p-=sizeof(tile->desc)-6; if (pdesc, sizeof(tile->desc), "File:%s", filename); } else { xastir_snprintf(tile->desc, sizeof(tile->desc), "File:...%s", p+3); } xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s.part", filename); tile->tempName = strdup(tile->fileName); strncpy(tile->fileName, filename, sizeof(tile->fileName)); // if we have the file and it's < expiry seconds old or expiry<0, don't queue it if ((expiry!=0) && stat(tile->fileName, &sb) != -1) { time_t age = time(NULL) - sb.st_mtime; if ((expiry < 0) || (age < expiry)) { //fprintf(stderr,"%s is fresh\n", tile->fileName); tile->state=DLM_Q_STOP; DLM_queue_entry_free(tile); return; } } DLM_queue_add(tile); } ///////////////////////////////////////////// End of DownLoadManager code /////////////////////////////////////// Xastir-Release-2.2.2/src/dlm.h000066400000000000000000000027331501463444000160670ustar00rootroot00000000000000/* * $Id: dlm.h,v 1.5 2018/07/14 21:32:43 MikeNix Exp $ * * Copyright (C) 2018-2023 The Xastir Group * * This file was contributed by Mike Nix. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef DLM_H #define DLM_H #include // for KeySym int DLM_wait_done(time_t timeout); int DLM_check_progress(void); int DLM_queue_len(void); void DLM_queue_abort(void); void DLM_queue_abort_tiles(void); void DLM_queue_abort_files(void); void DLM_do_transfers(void); void DLM_queue_tile( char *serverURL, unsigned long x, unsigned long y, int osm_zl, char *baseDir, char *ext ); void DLM_queue_file( char *url, char *filename, time_t expiry ); #endif //DLM_H Xastir-Release-2.2.2/src/draw_symbols.c000066400000000000000000003525231501463444000200200ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include "xastir.h" #include "database.h" #include "draw_symbols.h" #include "main.h" #include "util.h" #include "color.h" #include "maps.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define ANGLE_UPDOWN 45 /* prefer horizontal cars if less than 45 degrees */ int symbols_loaded = 0; int symbols_cache[5] = {0,0,0,0,0}; Widget select_symbol_dialog = (Widget)NULL; static xastir_mutex select_symbol_dialog_lock; Pixmap select_icons[(126-32)*2]; //33 to 126 with both '/' and '\' symbols (94 * 2) or 188 int symbol_change_requested_from = 0; void draw_symbols_init(void) { init_critical_section( &select_symbol_dialog_lock ); } /*** symbol data ***/ void clear_symbol_data(void) { int my_size; int i; char *data_ptr; data_ptr = (char *)symbol_data; my_size = (int)sizeof(SymbolData); for (i=0; i screen_width) { return; } if (x < 0) { return; } if (y > screen_height) { return; } if (y < 0) { return; } // With a large font, the background rectangle is too small. Need // to include the font metrics in this drawing algorithm. gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); font_width = (int)((xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->min_bounds.width) / 4); font_height = xfs_ptr->max_bounds.ascent + xfs_ptr->max_bounds.descent; switch (style) { case 0: // make outline style (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); // draw an outline 1 pixel bigger than text (void)XDrawString(XtDisplay(w),where,gc,x+1,y-1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x+1,y,text,length); (void)XDrawString(XtDisplay(w),where,gc,x+1,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y-1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x,y-1,text,length); break; case 1: // draw text the old way in a gray box // Leave this next one hard-coded to 0xff. This keeps // the background as gray. (void)XSetForeground(XtDisplay(w),gc,colors[0xff]); (void)XFillRectangle( XtDisplay(w), where, gc, x, // X y-(font_height-(font_height/4)), // Y // Get the actual width of the text in pixels get_text_width(w,text), // width font_height); // height (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x+(font_height/10),y+(font_width/8),text,length); break; case 2: // draw white or colored text in a black box (void)XSetForeground( XtDisplay(w), gc, GetPixelByName(w,"black") ); (void)XFillRectangle( XtDisplay(w), where, gc, x, // X y-(font_height-(font_height/4)), // Y // Get the actual width of the text in pixels get_text_width(w,text), font_height); // height break; // Case three will be used in a future release with an additional // Station Text Style selection case 3: default: // Real Shadow text on a transparent background (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x+(font_height/10),y+(font_width/8),text,length); break; } // finally draw the text (void)XSetForeground(XtDisplay(w),gc,colors[fgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x,y,text,length); // And free our font info if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } } /* symbol drawing routines */ // Function to draw a line between a WP symbol "\/" and the // transmitting station. We pass it the WP symbol. It does a // lookup for the transmitting station callsign to get those // coordinates, then draws a line between the two symbols if // possible (both on screen). // // If the symbol was a Waypoint symbol, "\/", we need to draw a line // from the transmitting station to the waypoint symbol according to // the spec. Take care to not draw the line any longer than needed // (don't exercise the X11 long-line drawing bug). According to the // spec we also need to change the symbol to just a red dot, but // it's nice having the "WP" above it so we can differentiate it // from the other red dot symbol. // // We should skip drawing the line if the object/item is not being drawn. // Should we skip it if the origination station isn't being drawn? // Do we need to add yet another togglebutton to enable/disable this line? // // Note that this type of operation, making a relation between two // symbols, breaks our paradism quite a bit. Until now all symbols // have been independent of each other. Perhaps we should store the // location of one symbol in the data of the other so that we won't // have to compare back and forth. This won't help much if either // or both symbols are moving. Probably better to just do a lookup // of the originating station by callsign through our lists and then // draw the line between the two coordinates each time. // void draw_WP_line(DataRow *p_station, int ambiguity_flag, long ambiguity_coord_lon, long ambiguity_coord_lat, Pixmap where, Widget UNUSED(w) ) { DataRow *transmitting_station = NULL; int my_course; long x_long, y_lat; long x_long2, y_lat2; double lat_m; long x, y; long x2, y2; double temp; int color = trail_colors[p_station->trail_color]; float temp_latitude, temp_latitude2; float temp_longitude, temp_longitude2; // Compute screen position of waypoint symbol if (ambiguity_flag) { x_long = ambiguity_coord_lon; y_lat = ambiguity_coord_lat; } else { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } // x & y are screen location of waypoint symbol x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; // Find transmitting station, get it's position. // p_station->origin contains the callsign for the transmitting // station. Do a lookup on that callsign through our database // to get the position of that station. if (!search_station_name(&transmitting_station,p_station->origin,1)) { // Can't find call, return; } x_long2 = transmitting_station->coord_lon; y_lat2 = transmitting_station->coord_lat; // x2 & y2 are screen location of transmitting station x2 = (x_long2 - NW_corner_longitude)/scale_x; y2 = (y_lat2 - NW_corner_latitude)/scale_y; /* if ((x2 - x) > 0) { my_course = (int)( 57.29578 * atan( (double)((y2-(y*1.0)) / (x2-(x*1.0) ) ) ) ); } else { my_course = (int)( 57.29578 * atan( (double)((y2-(y*1.0)) / (x-(x2*1.0) ) ) ) ); } */ // Use the mid-latitude formulas for calculating the rhumb line // course. Modified to minimize the number of conversions we // need to do. // lat_m = (double)( (y_lat + y_lat2) / 2.0 ); // Convert from Xastir coordinate system // lat_m = (double)( -((lat_m - 32400000l) / 360000.0) ); lat_m = -((y_lat - 32400000l) / 360000.0) + -((y_lat2 - 32400000l) / 360000.0); lat_m = lat_m / 2.0; convert_from_xastir_coordinates(&temp_longitude2, &temp_latitude2, x_long2, y_lat2); convert_from_xastir_coordinates(&temp_longitude, &temp_latitude, x_long, y_lat); temp = (double)( (temp_longitude2 - temp_longitude) / (temp_latitude2 - temp_latitude) ); // Check for divide-by-zero here???? // Calculate course and convert to degrees my_course = (int)( 57.29578 * atan( cos(lat_m) * temp) ); // The arctan function returns values between -90 and +90. To // obtain the true course we apply the following rules: if (temp_latitude2 > temp_latitude && temp_longitude2 > temp_longitude) { // Do nothing. } else if (temp_latitude2 < temp_latitude && temp_longitude2 > temp_longitude) { my_course = 180 - my_course; } else if (temp_latitude2 < temp_latitude && temp_longitude2 < temp_longitude) { my_course = 180 + my_course; } else if (temp_latitude2 > temp_latitude && temp_longitude2 < temp_longitude) { my_course = 360 - my_course; } else { // ?? // Do nothing. } //fprintf(stderr,"course:%d\n", my_course); // Convert to screen angle // my_course = my_course + 90; // Compute whether either of them are on-screen. If so, draw at // least part of the line between them. (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(x), // int l16(y), // int l16(x2), // int l16(y2)); // int } //draw_pod_circle(64000000l, 32400000l, 10, colors[0x44], pixmap_final); // // Probability of Detection circle: A circle around the point last // seen drawn at the distance that a person of that description // could travel since they were last seen. It helps to limit a // search to a reasonable area. // // It'd be nice to have some method of showing where the center of // the circle was as well, in case we don't have a PLS object placed // there also. Perhaps a small dot and/or four lines going from // that point to the edge of the circle? // // range is in miles // x_long/y_lat are in Xastir lat/lon units // void draw_pod_circle(long x_long, long y_lat, double range, int color, Pixmap where, int sec_heard) { double diameter; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's on the screen. // if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } //fprintf(stderr,"Range:%f\tDiameter:%f\n",range,diameter); (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2)), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int // We may need to check for the lat/long being way too far // off-screen, refusing to draw the circles if so, if and only if we // get into X11 drawing bugs as-is. // } // } } } // range is in centimeters (0 to 65535 representing 0 to 655.35 meters) // x_long/y_lat are in Xastir lat/lon units // lat_precision/lon-precision are in 100ths of seconds of lat/lon // void draw_precision_rectangle(long x_long, long y_lat, double UNUSED(range), // Not implemented yet unsigned int lat_precision, unsigned int lon_precision, int color, Pixmap where) { // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's on the screen. if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); if (x_long > 64800000L) { // Eastern hemisphere, add X's (go further east) x2 = x_long + lon_precision; } else { // Western hemisphere, subtract X's (go further west) x2 = x_long - lon_precision; } if (y_lat > 32400000L) { // Southern hemisphere, add Y's (go further north) y2 = y_lat + lat_precision; } else { // Northern hemisphere, subtract Y's (go further south) y2 = y_lat - lat_precision; } draw_vector(da, x_long, y_lat, x_long, y2, gc, where, 0); // x_long constant draw_vector(da, x_long, y2, x2, y2, gc, where, 0); // y2 constant draw_vector(da, x2, y2, x2, y_lat, gc, where, 0); // x2 constant draw_vector(da, x2, y_lat, x_long, y_lat, gc, where, 0); // y_lat constant } } } void draw_phg_rng(long x_long, long y_lat, char *phg, time_t sec_heard, Pixmap where) { double range, diameter; int offx,offy; double tilt; char is_rng; char *strp; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { tilt=0.0; is_rng=0; offx=0; offy=0; if (phg[0] == 'R' && phg[1] == 'N' && phg[2] == 'G') { is_rng = 1; } if (is_rng) { strp = &phg[3]; range = atof(strp); } else { range = phg_range(phg[3],phg[4],phg[5]); } // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } if (!is_rng) // Figure out the directivity, if outside range of 0-8 it's declared to be an omni { switch (phg[6]-'0') { case(0): offx=0; offy=0; break; case(1): // 45 offx=-1*(diameter/6); offy=diameter/6; tilt=5.49778; break; case(2): // 90 offx=-1*(diameter/6); offy=0; tilt=0; break; case(3): // 135 offx=-1*(diameter/6); offy=-1*(diameter/6); tilt=.78539; break; case(4): // 180 offx=0; offy=-1*(diameter/6); tilt=1.5707; break; case(5): // 225 offx=diameter/6; offy=-1*(diameter/6); tilt=2.3561; break; case(6): // 270 offx=diameter/6; offy=0; tilt=3.14159; break; case(7): // 315 offx=diameter/6; offy=diameter/6; tilt=3.92699; break; case(8): // 360 offx=0; offy=diameter/6; tilt=4.71238; break; default: offx=0; offy=0; break; } // End of switch } (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineSolid, CapButt,JoinMiter); if ((sec_old+sec_heard)>sec_now()) { (void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); } else { (void)XSetForeground(XtDisplay(da),gc,colors[0x52]); } if (is_rng || phg[6]=='0') // Draw circl { // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2)), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } else // Draw oval to depict beam heading { // If phg[6] != '0' we still draw a circle, but the center // is offset in the indicated direction by 1/3 the radius. // This debug statement will almost never wind // up selected, because 4095 means "all possible debugging" // It is being placed here SOLELY so that I can // leave the setting of "tilt" (which should determine // how an oval would be tilted to indicate directivity) // without having GCC 6.x whine about it not being used. if (debug_level == 4095) { fprintf(stderr,"If we had tilted ovals implemented, would have tilted one by %lf\n",tilt); } // Draw Circle // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } } } // Function to draw DF circles around objects/stations for DF'ing purposes. // // We change from filled circles to open circles at zoom level 128 for speed purposes. // void draw_DF_circle(long x_long, long y_lat, char *shgd, time_t sec_heard, Pixmap where) { double range, diameter; int offx,offy; double tilt; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { tilt=0.0; offx=0; offy=0; range = shg_range(shgd[3],shgd[4],shgd[5]); // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) // diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } // Figure out the directivity, if outside range of 0-8 it's declared to be an omni switch (shgd[6]-'0') { case(0): offx=0; offy=0; break; case(1): // 45 offx=-1*(diameter/6); offy=diameter/6; tilt=5.49778; break; case(2): // 90 offx=-1*(diameter/6); offy=0; tilt=0; break; case(3): // 135 offx=-1*(diameter/6); offy=-1*(diameter/6); tilt=.78539; break; case(4): // 180 offx=0; offy=-1*(diameter/6); tilt=1.5707; break; case(5): // 225 offx=diameter/6; offy=-1*(diameter/6); tilt=2.3561; break; case(6): // 270 offx=diameter/6; offy=0; tilt=3.14159; break; case(7): // 315 offx=diameter/6; offy=diameter/6; tilt=3.92699; break; case(8): // 360 offx=0; offy=diameter/6; tilt=4.71238; break; default: offx=0; offy=0; break; } if (scale_y > 128) // Don't fill in circle if zoomed in too far (too slow!) { (void)XSetLineAttributes(XtDisplay(da), gc_stipple, 1, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes(XtDisplay(da), gc_stipple, 8, LineSolid, CapButt,JoinMiter); } // Stipple the area instead of obscuring the map underneath (void)XSetStipple(XtDisplay(da), gc_stipple, pixmap_50pct_stipple); (void)XSetFillStyle(XtDisplay(da), gc_stipple, FillStippled); // Choose the color for the DF'ing circle // We try to choose similar colors to those used in DOSaprs, // which are qbasic or gwbasic colors. switch (shgd[3]) { case '9': // Light Red if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x25]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x25]); } break; case '8': // Red if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2d]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2d]); } break; case '7': // Light Magenta if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x26]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x26]); } break; case '6': // Magenta if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2e]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2e]); } break; case '5': // Light Cyan if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x24]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x24]); } break; case '4': // Cyan if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2c]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2c]); } break; case '3': // White if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x0f]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x0f]); } break; case '2': // Light Blue if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x22]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x22]); } break; case '1': // Blue if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2a]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2a]); } break; case '0': // DarkGray (APRSdos) or Black (looks better). We use Black. default: if ((sec_old+sec_heard)>sec_now()) // New (was 0x30) { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x08]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x08]); } break; } // If shgd[6] != '0' we still draw a circle, but the center // is offset in the indicated direction by 1/3 the radius. // This debug statement will almost never wind // up selected, because 4095 means "all possible debugging" // It is being placed here SOLELY so that I can // leave the setting of "tilt" (which should determine // how an oval would be tilted to indicate directivity) // without having GCC 6.x whine about it not being used. if (debug_level & 4095) { fprintf(stderr,"If we had tilted ovals implemented, would have tilted one by %lf\n",tilt); } // Draw Circle // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc_stipple, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int if (scale_y > 128) // Don't fill in circle if zoomed in too far (too slow!) { while (diameter > 1.0) { diameter = diameter - 1.0; // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc_stipple, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } } } // Change back to non-stipple for whatever drawing occurs after this (void)XSetFillStyle(XtDisplay(da), gc_stipple, FillSolid); } // Draw the ALOHA circle // Identical to draw_pod_circle when this was first written, but separated // just in case that POD functionality ever changes per the comments in it void draw_aloha_circle(long x_long, long y_lat, double range, int color, Pixmap where) { double diameter; long width, height; // Range is in miles. Bottom term is in meters before the // 0.0006214 multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } width = (((x_long-NW_corner_longitude)/scale_x)-(diameter/2)); height = (((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(width), // int l16(height), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } static int barb_len; static int barb_spacing; // Change barb parameters based on our current zoom level, so the // barbs don't get too long as we zoom out. void set_barb_parameters(void) { float factor = 1.0; // Initial settings barb_len = 16; barb_spacing = 16; // Scale factor if (scale_y > 80000) { factor = 3.0; } else if (scale_y > 40000) { factor = 2.5; } else if (scale_y > 20000) { factor = 2.0; } else if (scale_y > 10000) { factor = 1.5; } // Scale them, plus use poor man's rounding barb_len = (int)((barb_len / factor) + 0.5); barb_spacing = (int)((barb_spacing / factor) + 0.5);; } void draw_half_barbs(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Set off in the barb direction now off_y = (long)( (barb_len / 2) * sin(barb_radians) ); off_x = (long)( (barb_len / 2) * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(start_x), // int l16(start_y), // int l16(start_x + off_x), // int l16(start_y + off_y)); // int } } void draw_full_barbs(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(start_x), // int l16(start_y), // int l16(start_x + off_x), // int l16(start_y + off_y)); // int } } void draw_triangle_flags(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y, off_x2, off_y2; XPoint points[3]; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Calculate 2nd point along staff off_x2 = (barb_spacing/2) * cos(bearing_radians); off_y2 = (barb_spacing/2) * sin(bearing_radians); // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 points[0].x = start_x; points[0].y = start_y; points[1].x = start_x + off_x; points[1].y = start_y + off_y; points[2].x = start_x + off_x2; points[2].y = start_y + off_y2; // Number of points is always 3 here, so we don't need to // check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 3, Convex, CoordModeOrigin); } } void draw_square_flags(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (90/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y, off_x2, off_y2; XPoint points[4]; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Calculate 2nd point along staff off_x2 = (barb_spacing/2) * cos(bearing_radians); off_y2 = (barb_spacing/2) * sin(bearing_radians); // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 points[0].x = start_x; points[0].y = start_y; points[1].x = start_x + off_x; points[1].y = start_y + off_y; points[2].x = start_x + off_x + off_x2; points[2].y = start_y + off_y + off_y2; points[3].x = start_x + off_x2; points[3].y = start_y + off_y2; // Number of points is always 4 here, so we don't need to // check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } // Function to draw wind barbs. Use speed in knots to determine the // flags and barbs to draw along the shaft. Course is in true // degrees, in the direction that the wind is coming from. // // Square flag = 100 knots // Triangle flag = 50 knots // Full barb = 10 knots // Half barb = 5 knots // void draw_wind_barb(long x_long, long y_lat, char *speed, char *course, time_t sec_heard, Pixmap where) { int square_flags = 0; int triangle_flags = 0; int full_barbs = 0; int half_barbs = 0; int shaft_length = 0; int my_speed = atoi(speed); // In mph (so far) int my_course = atoi(course); // In ° true float bearing_radians; long off_x,off_y; long x,y; int i; // Ghost the wind barb if sec_heard is too long. if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } // What to do if my_speed is zero? Blank out any wind barbs // that were written before? // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's // on the screen. if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; // Ok to draw wind barb } else { return; } } else { return; } // Set up the constants for our zoom level set_barb_parameters(); // Convert from mph to knots for wind speed. my_speed = my_speed * 0.8689607; //fprintf(stderr,"mph:%s, knots:%d\n",speed,my_speed); // Adjust so that it fits our screen angles. We're off by // 90 degrees. my_course = (my_course - 90) % 360; square_flags = (int)(my_speed / 100); my_speed = my_speed % 100; triangle_flags = (int)(my_speed / 50); my_speed = my_speed % 50; full_barbs = (int)(my_speed / 10); my_speed = my_speed % 10; half_barbs = (int)(my_speed / 5); shaft_length = barb_spacing * (square_flags + triangle_flags + full_barbs + half_barbs + 1); // Set a minimum length for the shaft? if (shaft_length < 2) { shaft_length = 2; } if (debug_level & 128) { fprintf(stderr,"Course:%d,\tL:%d,\tsq:%d,\ttr:%d,\tfull:%d,\thalf:%d\n", atoi(course), shaft_length, square_flags, triangle_flags, full_barbs, half_barbs); } // Draw shaft at proper angle. bearing_radians = (my_course/360.0) * 2.0 * M_PI; off_y = (long)( shaft_length * sin(bearing_radians) ); off_x = (long)( shaft_length * cos(bearing_radians) ); x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(x), // int l16(y), // int l16(x + off_x), // int l16(y + off_y)); // int // Increment along shaft and draw filled polygons at: // "(angle + 45) % 360" degrees to create flags. i = barb_spacing; // Draw half barbs if any if (half_barbs) draw_half_barbs(&i, half_barbs, bearing_radians, x, y, course, where); // Draw full barbs if any if (full_barbs) draw_full_barbs(&i, full_barbs, bearing_radians, x, y, course, where); // Draw triangle flags if any if (triangle_flags) draw_triangle_flags(&i, triangle_flags, bearing_radians, x, y, course, where); // Draw rectangle flags if any if (square_flags) draw_square_flags(&i, square_flags, bearing_radians, x, y, course, where); } // Function to draw beam headings for DF'ing purposes. Separates NRQ into its // components, which are Number/Range/Quality. // // If N is 0, then the NRQ value is meaningless. 1 through 8 are hits per period // of time (auto-DF'ing equipment). A value of 8 means all samples possible got // a hit. A value of 9 means that the report is manual. // // Range limits the length of the line to the original map's scale of the sending // station. The range is 2**R, so for R=4 the range would be 16 miles. // // Q is a single digit from 0-9 and provides indication of bearing accuracy: // 0 Useless // 1 <240 deg (worst) // 2 <120 deg // 3 <64 deg // 4 <32 deg // 5 <16 deg // 6 <8 deg // 7 <4 deg // 8 <2 deg // 9 <1 deg (best) // // // TODO: Should we draw with XOR for this function? Would appear on // most maps that way, and we wouldn't have to worry much about // color. // // TODO: If Q between 1 and 8, shade the entire area to show the // beam width? // // // Latest: We ignore the color parameter and draw everything using // red3. // // The distance calculations below use nautical miles. Here we // ignore the difference between nautical and statute miles as it // really doesn't make much difference how long we draw the vectors: // The angle is what is important here. // void draw_bearing(long x_long, long y_lat, char *course, char *bearing, char *NRQ, int UNUSED(color), int draw_beamwidth, int draw_bearing, time_t sec_heard, Pixmap where) { double range = 0; double real_bearing = 0.0; double real_bearing_min = 0.0; double real_bearing_max = 0.0; int width = 0; long x_long2, x_long3, x_long4, y_lat2, y_lat3, y_lat4; double screen_miles; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { // Check for a zero value for N. If found, the NRQ value is meaningless // and we need to assume some working default values. if (NRQ[0] != '0') { // "range" as used below is in nautical miles. range = (double)( pow(2.0,NRQ[1] - '0') ); switch (NRQ[2]) { case('1'): width = 240; // Degrees of beam width. What's the point? break; case('2'): width = 120; // Degrees of beam width. What's the point? break; case('3'): width = 64; // Degrees of beam width. What's the point? break; case('4'): width = 32; // Degrees of beam width. Starting to be usable. break; case('5'): width = 16; // Degrees of beam width. Usable. break; case('6'): width = 8; // Degrees of beam width. Usable. break; case('7'): width = 4; // Degrees of beam width. Nice! break; case('8'): width = 2; // Degrees of beam width. Nice! break; case('9'): width = 1; // Degrees of beam width. Very Nice! break; case('0'): // "Useless" beam width according to spec default: return; // Exit routine without drawing vectors break; } } else // Assume some default values. { range = 512.0; // Assume max range of 512 nautical miles width = 8; // Assume 8 degrees for beam width } // We have the course of the vehicle and the bearing from the // vehicle. Now we need the real bearing. // if (atoi(course) != 0) { real_bearing = atoi(course) + atoi(bearing); real_bearing_min = real_bearing + 360.0 - (width/2.0); real_bearing_max = real_bearing + (width/2.0); } else { real_bearing = atoi(bearing); real_bearing_min = real_bearing + 360.0 - (width/2.0); real_bearing_max = real_bearing + (width/2.0); } while (real_bearing > 360.0) { real_bearing -= 360.0; } while (real_bearing_min > 360.0) { real_bearing_min -= 360.0; } while (real_bearing_max > 360.0) { real_bearing_max -= 360.0; } // want this in nautical miles screen_miles = scale_x * calc_dscale_x(center_longitude,center_latitude) * .5400; // Shorten range to more closely fit the screen if ( range > (3.0 * screen_miles) ) { range = 3.0 * screen_miles; } // We now have a distance and a bearing for each vector. // Compute the end points via dead-reckoning here. It will give // us points between which we can draw a vector and makes the // rest of the code much easier. Need to skip adding 270 // degrees if we use that method. // if (draw_beamwidth) { compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing_min, // input in ° true (double) &x_long2, // output (*long) &y_lat2); // output (*long) compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing_max, // input in ° true (double) &x_long3, // output (*long) &y_lat3); // output (*long) } if (draw_bearing) { compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing, // input in ° true (double) &x_long4, // output (*long) &y_lat4); // output (*long) } (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); if (draw_beamwidth) { (void)XSetForeground(XtDisplay(da),gc,colors[0x4a]); // red2 draw_vector(da, x_long, y_lat, x_long2, y_lat2, gc, where, 0); draw_vector(da, x_long, y_lat, x_long3, y_lat3, gc, where, 0); } if (draw_bearing) { (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 draw_vector(da, x_long, y_lat, x_long4, y_lat4, gc, where, 0); } } // Change back to non-stipple for whatever drawing occurs after this // (void)XSetFillStyle(XtDisplay(da), gc_tint, FillSolid); } // TODO: Pass back the modified x_long/y_lat to the calling routine // and use the new lat/long to place the symbol. This will knock // off the digits on the right that the ambiguity specifies. We // then add 1/2 the rectangle offsets in order to get the symbol // placed in the middle of the rectangle. // void draw_ambiguity(long x_long, long y_lat, char amb, long *amb_x_long, long *amb_y_lat, time_t sec_heard, Pixmap UNUSED(where) ) { unsigned long left, right, top, bottom; long offset_lat, offset_long; int scale_limit; // Assign these first in case we do a sudden return from the // function. *amb_x_long = x_long; *amb_y_lat = y_lat; // if ((x_long < 0) || (x_long > 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; switch (amb) { case 1: // +- 1/10th minute offset_lat = offset_long = 600; scale_limit = 256; // Truncate digits off the right x_long = (long)(x_long / 600); x_long = x_long * 600; y_lat = (long)(y_lat / 600); y_lat = y_lat * 600; break; case 2: // +- 1 minute offset_lat = offset_long = 6000; scale_limit = 2048; // Truncate digits off the right x_long = (long)(x_long / 6000); x_long = x_long * 6000; y_lat = (long)(y_lat / 6000); y_lat = y_lat * 6000; break; case 3: // +- 10 minutes offset_lat = offset_long = 60000; scale_limit = 16384; // Truncate digits off the right x_long = (long)(x_long / 60000); x_long = x_long * 60000; y_lat = (long)(y_lat / 60000); y_lat = y_lat * 60000; break; case 4: // +- 1 degree offset_lat = offset_long = 360000; scale_limit = 65536; // Truncate digits off the right x_long = (long)(x_long / 360000); x_long = x_long * 360000; y_lat = (long)(y_lat / 360000); y_lat = y_lat * 360000; break; // TODO: The last two cases need fixing up like the above case 5: // grid square: 2.5min lat x 5min lon offset_lat = 360000.0 * 1.25 / 60.0; offset_long = 360000.0 * 2.50 / 60.0; scale_limit = 1024; break; case 6: // grid square: 1deg lat x 2deg lon offset_lat = 360000.0 * 0.5; offset_long = 360000.0 * 1.0; scale_limit = 16384; break; case 0: default: return; // if no ambiguity, do nothing break; } // Re-assign them here as they should have been truncated on the // right by the above code. We'll use these new values // to draw the symbols and the other associated symbol data // (external to this function). // *amb_x_long = x_long + (offset_long/2); *amb_y_lat = y_lat + (offset_lat / 2); if (scale_y > scale_limit) { // Ambiguity box will be smaller than smallest symbol so // don't draw it. //fprintf(stderr,"scale_y > scale_limit\n"); return; } if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } left = x_long; top = y_lat; right = x_long + offset_long; bottom = y_lat + offset_lat; (void)XSetForeground(XtDisplay(da), gc, colors[0x08]); // Draw rectangle (unfilled) plus vectors from symbol to // corners. (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineOnOffDash, CapButt,JoinMiter); // Top line of rectangle draw_vector(da,left,top,right,top,gc,pixmap_final, 0); // Bottom line of rectangle draw_vector(da,left,bottom,right,bottom,gc,pixmap_final, 1); // Left line of rectangle draw_vector(da,left,top,left,bottom,gc,pixmap_final, 1); // Right line of rectangle draw_vector(da,right,top,right,bottom,gc,pixmap_final, 1); // Diagonal lines draw_vector(da,left,top,right,bottom,gc,pixmap_final, 1); draw_vector(da,right,top,left,bottom,gc,pixmap_final, 1); } // Function which specifies whether any part of a bounding box fits // on the screen, using screen coordinates as inputs. // static __inline__ int onscreen(long left, long right, long top, long bottom) { // This checks to see if any part of a box is on the screen. if (left > screen_width || right < 0 || top > screen_height || bottom < 0) { return 0; } else { return 1; } } // According to the spec, the lat/long point is the upper left // corner of the object, and the offsets are down and to the right // (except for one line type where it's down and to the left). This // doesn't appear to be the case in dos/winAPRS. Matching what they // do: // // Type 0 Circle: Tie = center, offsets = vert/horiz. sizes. // Type 1 Line: Tie = bottom right, offsets = left and up. // Type 2 Ellipse: Tie = center, offsets = vert/horiz. sizes. // Type 3 Triangle: Tie = bottom right, offsets = height/width. // Type 4 Rectangle: Tie = lower right, offsets = left and up. // Type 5 Circle: Tie = center, offsets = vert/horiz. sizes. // Type 6 Line: Tie = bottom left, offsets = right and up. // Type 7 Ellipse: Tie = center, offsets = vert/horiz. sizes. // Type 8 Triangle: Tie = bottom right, offsets = height/width. // Type 9 Rectangle: Tie = lower right, offsets = left and up. // // Exceptions to this are the triangle, ellipse, and circle. The // ellipse and circle have the lat/long as the center point. The // triangle is an isosceles triangle with the lat/long point being // the bottom right and the bottom of the triangle being horizontal. // void draw_area(long x_long, long y_lat, char type, char color, char sqrt_lat_off, char sqrt_lon_off, unsigned int width, time_t sec_heard, Pixmap where) { long left, top, right, bottom, xoff, yoff; int c; XPoint points[4]; // Ghost the area object if sec_heard is too long. if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } // if ((x_long < 0) || (x_long > 129600000l) || // (y_lat < 0) || (y_lat > 64800000l)) // return; xoff = 360000.0 / 1500.0 * (sqrt_lon_off * sqrt_lon_off) / scale_x; yoff = 360000.0 / 1500.0 * (sqrt_lat_off * sqrt_lat_off) / scale_y; right = (x_long - NW_corner_longitude) / scale_x; bottom = (y_lat - NW_corner_latitude) / scale_y; left = right - xoff; top = bottom - yoff; // colors[0x21] is the first in the list of area object colors in main.c c = colors[0x21 + color]; (void)XSetForeground(XtDisplay(da), gc, c); if (xoff < 20 || yoff < 20) { (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); } (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // just in case (void)XSetStipple(XtDisplay(da), gc, pixmap_50pct_stipple); switch (type) { case AREA_OPEN_BOX: if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawRectangle // Tricky 'cuz the XRectangle struct has short's and unsigned short's, // while XDrawRectangle man-page says int's/unsigned int's. We'll // stick to 16-bit just to make sure. (void)XDrawRectangle(XtDisplay(da), where, gc, l16(left), // int l16(top), // int lu16(xoff), // unsigned int lu16(yoff)); // unsigned int } break; case AREA_FILLED_BOX: if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); (void)XFillRectangle(XtDisplay(da), where, gc, l16(left), l16(top), l16(xoff), l16(yoff)); } break; /* For the rest of the objects, the l16 limiting of the values is inadequate because the shapes will still be draw wrong if the value actually was limited down. However, this is slightly better than passing long or int values that would just be used as 16bit by X (i.e.: truncated) until I/we come up with some sort of clipping algorithm. In real use, what I'm talking about will occur based on two things: the size of the area and the zoom level being used. The more the extents of the area go beyond the edges of the screen, the more this will happen. N7TAP */ case AREA_OPEN_CIRCLE: case AREA_OPEN_ELLIPSE: right += xoff; bottom += yoff; if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da), where, gc, l16(left), // int l16(top), // int lu16(2*xoff), // unsigned int lu16(2*yoff), // unsigned int l16(0), // int l16(64 * 360)); // int } break; case AREA_FILLED_CIRCLE: case AREA_FILLED_ELLIPSE: right += xoff; bottom += yoff; if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); (void)XFillArc(XtDisplay(da), where, gc, l16(left), l16(top), l16(2*xoff), l16(2*yoff), 0, 64 * 360); } break; case AREA_LINE_RIGHT: left += xoff; right += xoff; if (width > 0) { double angle = atan((float)xoff/(float)yoff); // Check for divide-by-zero here??? int conv_width = width/(scale_x*calc_dscale_x(center_longitude,center_latitude)*0.0006214); points[0].x = l16(left-(conv_width * cos(angle))+xoff); points[0].y = l16(top -(conv_width * sin(angle))); points[1].x = l16(left-(conv_width * cos(angle))); points[1].y = l16(top -(conv_width * sin(angle))+yoff); points[2].x = l16(left+(conv_width * cos(angle))); points[2].y = l16(top +(conv_width * sin(angle))+yoff); points[3].x = l16(left+(conv_width * cos(angle))+xoff); points[3].y = l16(top +(conv_width * sin(angle))); if (onscreen(points[1].x, points[3].x, points[0].y, points[2].y)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 4 here, so we don't // need to check first before calling // XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da), where, gc, l16(left), // int l16(bottom), // int l16(right), // int l16(top)); // int } break; case AREA_LINE_LEFT: if (width > 0) { double angle = atan((float)xoff/(float)yoff); // Check for divide-by-zero here??? int conv_width = width/(scale_x*calc_dscale_x(center_longitude,center_latitude)*0.0006214); points[0].x = l16(left+(conv_width * cos(angle))); points[0].y = l16(top -(conv_width * sin(angle))); points[1].x = l16(left+(conv_width * cos(angle))+xoff); points[1].y = l16(top -(conv_width * sin(angle))+yoff); points[2].x = l16(left-(conv_width * cos(angle))+xoff); points[2].y = l16(top +(conv_width * sin(angle))+yoff); points[3].x = l16(left-(conv_width * cos(angle))); points[3].y = l16(top +(conv_width * sin(angle))); if (onscreen(points[3].x, points[1].x, points[0].y, points[2].y)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 4 here, so we don't // need to check first before calling // XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da), where, gc, l16(right), // int l16(bottom), // int l16(left), // int l16(top)); // int } break; case AREA_OPEN_TRIANGLE: left -= xoff; points[0].x = l16(right); points[0].y = l16(bottom); points[1].x = l16(left+xoff); points[1].y = l16(top); points[2].x = l16(left); points[2].y = l16(bottom); points[3].x = l16(right); points[3].y = l16(bottom); if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawLines. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLines(XtDisplay(da), where, gc, points, // XPoint * l16(4), // int CoordModeOrigin); // int } break; case AREA_FILLED_TRIANGLE: left -= xoff; points[0].x = l16(right); points[0].y = l16(bottom); points[1].x = l16(left+xoff); points[1].y = l16(top); points[2].x = l16(left); points[2].y = l16(bottom); if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 3 here, so we don't need // to check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 3, Convex, CoordModeOrigin); } break; default: break; } (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); } /* DK7IN: Statistics for colors in all symbols (as of 16.03.2001) 60167 . 6399 q 3686 m 3045 c 2034 j 1903 h 1726 l 1570 k 1063 g 1051 # 840 p 600 ~ 477 i 443 n 430 a 403 o 337 f 250 b 207 e 169 d */ // read pixels from file, speeding it up by smart ordering of switches void read_symbol_from_file(FILE *f, char *pixels, char table_char) { int x,y; int color; char line[100]; char pixels_copy[400]; char *p,*q; unsigned char a, b, c; for (y=0; y<20; y++) { (void)get_line(f,line,100); for (x=0; x<20; x++) { switch (line[x]) { case('.'): // transparent color=0xff; break; case('q'): // #000000 black 0% color=0x51; break; case('m'): // #FFFFFF white 100% color=0x4d; break; case('c'): // #CCCCCC gray80 80% color=0x43; break; case('j'): // #EE0000 red2 color=0x4a; break; case('h'): // #00BFFF Deep sky blue color=0x48; break; case('l'): // #0000CD mediumblue color=0x4c; break; case('k'): // #00CD00 green3 color=0x4b; break; case('g'): // #00008B blue4 color=0x47; break; case('#'): // #FFFF00 yellow color=0x40; break; case('p'): // #454545 gray27 27% color=0x50; break; case('~'): // used in the last two symbols in the file color=0xff; // what should it be? was transparent before... break; case('i'): // #006400 Dark Green color=0x49; break; case('n'): // #878787 gray53 52% color=0x4e; break; case('a'): // #CD6500 darkorange2 color=0x41; break; case('o'): // #5A5A5A gray59 35% color=0x4f; break; case('f'): // #CD3333 brown3 color=0x46; break; case('b'): // #A020F0 purple color=0x42; break; case('e'): // #FF4040 brown1 color=0x45; break; case('d'): // #CD0000 red3 color=0x44; break; case('r'): // LimeGreen DK7IN: saw this in the color definitions... color=0x52; // so we could use it break; default: color=0xff; break; } pixels[y*20+x] = (char)(color); } } // Create outline on icons, if needed // Do not change the overlays and "number" tables if((icon_outline_style != 0) && (table_char != '~') && (table_char != '#')) { switch(icon_outline_style) { case 1: color = 0x51; // Black break; //case 2: color = 0x43; // Grey 80% case 2: color = 0x4e; // Grey 52% break; case 3: color = 0x4d; // White break; default: color = 0xff; // Transparent break; } p = pixels; q = &pixels_copy[0]; for (y=0; y<20; y++) { for (x=0; x<20; x++) { *q = *p; // copy current color // If transparent see if the pixel is on the edge if(*q == (char) 0xff) { //check if left or right is none transparent b = c = 0xff; // left (left only possible if x > 0) if(x > 0) { b = p[-1]; } // right (right only possible if x < 19) if(x < 19) { c = p[+1]; } // if non-transparent color is found change pixel // to outline color if((b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } if((y > 0) && (*q == (char) 0xff)) { //check if left-up, up or right-up is none transparent //"up" only possible if y > 0 a = b = c = 0xff; // left-up (left only possible if x > 0) if(x > 0) { a = p[-21]; } // up b = p[-20]; // right-up (right only possible if x < 19) if(x < 19) { c = p[-19]; } // if non-transparent color is found change pixel // to outline color if((a != (unsigned char) 0xff) || (b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } } if((y < 19) && (*q == (char) 0xff)) { //check if left-down, down or right-down is none transparent //"down" only possible if y < 19 a = b = c = 0xff; // left-down (left only possible if x > 0) if(x > 0) { a = p[+19]; } // down b = p[+20]; // right-down (right only possible if x < 19) if(x < 19) { c = p[+21]; } // if non-transparent color is found change pixel // to outline color if((a != (unsigned char) 0xff) || (b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } } } p++; q++; } } memcpy(pixels, pixels_copy, 400); } } /* read in symbol table */ void load_pixmap_symbol_file(char *filename, int reloading) { FILE *f; char filen[500]; char line[100]; char table_char; char symbol_char; int done; char pixels[400]; char orient; busy_cursor(appshell); symbols_loaded = 0; table_char = '\0'; symbol_char = '\0'; done = 0; xastir_snprintf(filen, sizeof(filen), "%s/%s", SYMBOLS_DIR, filename); f = fopen(filen,"r"); if (f!=NULL) { while (!feof(f) && !done) { (void)get_line(f,line,100); if (strncasecmp("TABLE ",line,6)==0) { table_char=line[6]; /*fprintf(stderr,"TABLE %c\n",table_char);*/ } else { if (strncasecmp("DONE",line,4)==0) { done=1; /*fprintf(stderr,"DONE\n");*/ } else { if (strncasecmp("APRS ",line,5)==0) { symbol_char=line[5]; if (strlen(line)>=20 && line[19] == 'l') // symbol with orientation ? { orient = 'l'; // should be 'l' for left } else { orient = ' '; } read_symbol_from_file(f, pixels, table_char); // read pixels for one symbol insert_symbol(table_char,symbol_char,pixels,270,orient,reloading); // always have normal orientation if (orient == 'l') { insert_symbol(table_char,symbol_char,pixels, 0,'u',reloading); // create other orientations insert_symbol(table_char,symbol_char,pixels, 90,'r',reloading); insert_symbol(table_char,symbol_char,pixels,180,'d',reloading); } } } } } } else { fprintf(stderr,"Error opening symbol file %s\n",filen); popup_message("Error opening symbol file","Error opening symbol file"); } if (f != NULL) { (void)fclose(f); } } // add a symbol to the end of the symbol table. // // Here we actually draw the pixels into the SymbolData struct, // which contains separate Pixmap's for the icon, the transparent // background, and the ghost image. // void insert_symbol(char table, char symbol, char *pixel, int deg, char orient, int reloading) { int x,y,idx,old_next,color,last_color,last_gc2; if (symbols_loaded < MAX_SYMBOLS) { // first time loading, -> create pixmap... // when reloading -> reuse already created pixmaps... if(reloading == 0) { symbol_data[symbols_loaded].pix=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); symbol_data[symbols_loaded].pix_mask=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, 1); symbol_data[symbols_loaded].pix_mask_old=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, 1); } old_next=0; last_color = -1; // Something bogus last_gc2 = -1; // Also bogus for (y=0; y<20; y++) { for (x=0; x<20; x++) { switch (deg) { case(0): idx = 20* (19-x) + y; break; case(90): idx = 20* y + (19-x); break; case(180): idx = 20* (19-x) + (19-y); break; default: idx = 20* y + x; break; } color = (int)(pixel[idx]); if (color<0) { color = 0xff; } // Change to new color only when necessary. We use two different // GC's here, one for the main icon pixmap, and one for the symbol // mask and ghost layer. // DK7IN: is (da) correct or should this be (appshell) ? if (color != last_color) { (void)XSetForeground(XtDisplay(da),gc,colors[color]); last_color = color; } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(da), symbol_data[symbols_loaded].pix, gc, l16(x), // int l16(y)); // int // DK7IN // Create symbol mask if (color != 0xff) { if (last_gc2 != 1) { (void)XSetForeground(XtDisplay(appshell),gc2,1); // active bit last_gc2 = 1; } } else { if (last_gc2 != 0) { (void)XSetForeground(XtDisplay(appshell),gc2,0); // transparent. last_gc2 = 0; } } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(appshell), symbol_data[symbols_loaded].pix_mask, gc2, l16(x), // int l16(y)); // int // Create ghost symbol mask by setting every 2nd bit // to transparent old_next++; if (old_next>1) { old_next=0; if (last_gc2 != 0) { (void)XSetForeground(XtDisplay(appshell),gc2,0); last_gc2 = 0; } } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(appshell), symbol_data[symbols_loaded].pix_mask_old, gc2, l16(x), // int l16(y)); // int } old_next++; // shift one bit every scan line for ghost image if (old_next>1) { old_next=0; } } symbol_data[symbols_loaded].active = SYMBOL_ACTIVE; symbol_data[symbols_loaded].table = table; symbol_data[symbols_loaded].symbol = symbol; symbol_data[symbols_loaded].orient = orient; symbols_loaded++; } } // calculate symbol orientation from course // ' ' = left // 'd' = down // 'r' = right // 'u' = up char symbol_orient(char *course) { char orient; float mydir; orient = ' '; // Default = left if (strlen(course)) { mydir = (float)atof(course); if (mydir > 0) { while (mydir > 360.0) { mydir = mydir - 360.0; } while (mydir < 0.0) { mydir = mydir + 360.0; } if (mydir == 360.0) { mydir = 0.0; } orient = 'u'; // 000-045 = up if ( mydir > (float)( 0+ANGLE_UPDOWN ) ) // 046-135 = right { orient = 'r'; } if ( mydir > (float)( 90+ANGLE_UPDOWN ) ) // 136-225 = down { orient = 'd'; } if ( mydir > (float)( 180+ANGLE_UPDOWN) ) // 226-314 = left { orient = ' '; } if ( mydir >= (float)(270+ANGLE_UPDOWN) ) // 315-360 = up { orient = 'u'; } } } return(orient); } // Storage for an index into the symbol table that we may need // later. int nosym_index = -1; // Look through our symbol table for a match. // void symbol(Widget w, int ghost, char symbol_table, char symbol_id, char symbol_overlay, Pixmap where, int mask, long x_offset, long y_offset, char orient) { int i; int found; int alphanum_index = -1; if (x_offset > screen_width) { return; } if (x_offset < 0) { return; } if (y_offset > screen_height) { return; } if (y_offset < 0) { return; } /* DK7IN: orient is ' ','l','r','u','d' for left/right/up/down symbol orientation */ // if symbol could be rotated, normal symbol orientation in symbols.dat is to the left // Find the nosymbol index if we haven't filled it in by now. // This "for" loop should get run only once during Xastir's // entire runtime, so it shouldn't contribute much to CPU // loading. if (nosym_index == -1) { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == '!' && symbol_data[i].symbol == '#') { nosym_index = i; // index of special symbol (if none available) break; } } } } // Handle the overlay character. The "for" loop below gets run // once every time we encounter an overlay character, which // isn't all that often. if (symbol_overlay == '\0' || symbol_overlay == ' ') { alphanum_index = 0; // we don't want an overlay } else // Find the overlay character index { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == '#' && symbol_data[i].symbol == symbol_overlay) { alphanum_index = i; // index of symbol for character overlay break; } } } } found = -1; // Check last few symbols we used to see if we can shortcut // looking through the entire index. The symbols array really // should be turned into a hash to save time. Basically we've // implemented a very short cache here, but it keeps us from // looking through the entire symbol array sometimes. // for ( i = 0; i < 5; i++ ) { //fprintf(stderr,"Checking symbol cache\n"); if (symbol_data[symbols_cache[i]].table == symbol_table && symbol_data[symbols_cache[i]].symbol == symbol_id) { // We found the matching symbol in the cache found = symbols_cache[i]; // index of symbol //fprintf(stderr,"Symbol cache hit:%d\n",found); break; } } if (found == -1) // Not found in symbols cache { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == symbol_table && symbol_data[i].symbol == symbol_id) { // We found the matching symbol found = i; // index of symbol // Save newly found symbol in cache, shift other // cache entries down by one so that newest is // at the beginning for the cache search. //fprintf(stderr,"Saving in cache\n"); symbols_cache[4] = symbols_cache[3]; symbols_cache[3] = symbols_cache[2]; symbols_cache[2] = symbols_cache[1]; symbols_cache[1] = symbols_cache[0]; symbols_cache[0] = i; break; } } } } if (found == -1) // Didn't find a matching symbol { found = nosym_index; if (symbol_table && symbol_id && debug_level & 128) { fprintf(stderr,"No Symbol Yet! %2x:%2x\n", (unsigned int)symbol_table, (unsigned int)symbol_id); } } else // maybe we want a rotated symbol { // It looks like we originally did not want to rotate the symbol if // it was ghosted? Why? For dead-reckoning we do want it to be // rotated when ghosted. // if (!(orient == ' ' || orient == 'l' || symbol_data[found].orient == ' ' || ghost)) { if (!(orient == ' ' || orient == 'l' || symbol_data[found].orient == ' ')) { for (i = found; i < symbols_loaded; i++) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == symbol_table && symbol_data[i].symbol == symbol_id && symbol_data[i].orient == orient) { found=i; // index of rotated symbol break; } } } } } if (mask) { if (ghost) { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[found].pix_mask_old); } else { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[found].pix_mask); } } (void)XSetClipOrigin(XtDisplay(w),gc,x_offset,y_offset); (void)XCopyArea(XtDisplay(w),symbol_data[found].pix,where,gc,0,0,20,20,x_offset,y_offset); if(alphanum_index > 0) { if (ghost) { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[alphanum_index].pix_mask_old); } else { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[alphanum_index].pix_mask); } (void)XSetClipOrigin(XtDisplay(w),gc,x_offset,y_offset); (void)XCopyArea(XtDisplay(w),symbol_data[alphanum_index].pix,where,gc,0,0,20,20,x_offset,y_offset); // rot } (void)XSetClipMask(XtDisplay(w),gc,None); } // Calculate the width in pixels of the actual text // This helps us take into account proportional or non-proportional fonts long get_text_width(Widget w,char *text) { long width; GContext gcontext; XFontStruct *xfs_ptr; int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); XTextExtents(xfs_ptr, text, strlen(text), &dir, &asc, &desc, &overall); //printf("%s Width = %d\n",text,overall.width); width =overall.width; if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } return width; } // Speed is in converted units by this point (kph or mph) void draw_symbol(Widget w, char symbol_table, char symbol_id, char symbol_overlay, long x_long,long y_lat, char *callsign_text, char *alt_text, char *course_text, char *speed_text, char *my_distance, char *my_course, char *wx_temp, char* wx_wind, time_t sec_heard, int temp_show_last_heard, Pixmap where, char orient, char area_type, char *signpost, char *gauge_data, int bump_count) { long x_offset,y_offset; int length; int ghost; int posyl; int posyr; long txt_width; // Added to allow dynamic offsets for the text around a symbol // Originally it was hard coded offsets, this bases the offset on // the font height and width // N7IPB - 4/7/2016 // GContext gcontext; XFontStruct *xfs_ptr; int font_width, font_height; gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); font_width = (int)((xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->min_bounds.width) / 4); // Get the font height and use it for the distance between lineis of text font_height = xfs_ptr->max_bounds.ascent; // Free the info to avoid a memory leak if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat0) { posyr -= font_height/2; } if (strlen(callsign_text)>0) { posyr -= font_height/2; } if ( (!ghost || Select_.old_data) && strlen(speed_text)>0) { posyr -= font_height/2 ; } if ( (!ghost || Select_.old_data) && strlen(course_text)>0) { posyr -= font_height/2; } if (area_type == AREA_LINE_RIGHT) { posyr += 9; } if (signpost[0] != '\0') // Signpost data? { posyr -=font_height/2; } // we may eventually have more adjustments for different types of areas length=(int)strlen(alt_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,alt_text,0x08,0x48,length); posyr += font_height; } length=(int)strlen(callsign_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,callsign_text,0x08,0x0f,length); posyr += font_height; } length=(int)strlen(speed_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,speed_text,0x08,0x4a,length); posyr += font_height; } length=(int)strlen(course_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,course_text,0x08,0x52,length); posyr += font_height; } length=(int)strlen(signpost); // Make it white like callsign? if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,signpost,0x08,0x0f,length); posyr += font_height; } posyl = font_height; // distance and direction goes to the left. // Also minutes last heard. if ( (!ghost || Select_.old_data) && strlen(my_distance)>0) { posyl -= font_height/2; } if ( (!ghost || Select_.old_data) && strlen(my_course)>0) { posyl -= font_height/2; } if ( (!ghost || Select_.old_data) && temp_show_last_heard) { posyl -= font_height/2; } length=(int)strlen(my_distance); txt_width=get_text_width(w,my_distance); if ( (!ghost || Select_.old_data) && length>0) { x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width+9)); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,my_distance,0x08,0x0f,length); posyl += font_height; } length=(int)strlen(my_course); txt_width=get_text_width(w,my_course); if ( (!ghost || Select_.old_data) && length>0) { x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width+9)); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,my_course,0x08,0x0f,length); posyl += font_height; } if ( (!ghost || Select_.old_data) && temp_show_last_heard) { char age[20]; float minutes; float hours; int fgcolor; // Color code the time string based on // time since last heard: // Green: 0-29 minutes // Yellow: 30-59 minutes // Red: 60 minutes to 1 day // White: 1 day or later minutes = (float)( (sec_now() - sec_heard) / 60.0); hours = minutes / 60.0; // Heard from this station within the // last 30 minutes? if (minutes < 30.0) { xastir_snprintf(age, sizeof(age), "%d%s", (int)minutes, langcode("UNIOP00034")); // min fgcolor = 0x52; // green } // 30 to 59 minutes? else if (minutes < 60.0) { xastir_snprintf(age, sizeof(age), "%d%s", (int)minutes, langcode("UNIOP00034")); // min fgcolor = 0x40; // yellow } // 1 hour to 1 day old? else if (hours <= 24.0) { xastir_snprintf(age, sizeof(age), "%.1f%s", hours, langcode("UNIOP00035")); // hr fgcolor = 0x4a; // red } // More than a day old else { xastir_snprintf(age, sizeof(age), "%.1f%s", hours / 24.0, langcode("UNIOP00036")); // day fgcolor = 0x0f; // white } length = strlen(age); txt_width = get_text_width(w,age); x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width)-9); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,age,0x08,fgcolor,length); posyl += font_height; } // weather goes to the bottom, centered horizontally. // Start off making sure it's below the symbol posyr += 10; if (posyr < posyl) { posyr = posyl; } if (posyr < font_height) { posyr = font_height; } length=(int)strlen(wx_temp); txt_width = get_text_width(w,wx_temp); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,wx_temp,0x08,0x40,length); posyr += font_height; } length=(int)strlen(wx_wind); txt_width = get_text_width(w,wx_wind); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,wx_wind,0x08,0x40,length); } if (gauge_data != NULL) { // Gauge data goes on the bottom, centered // horizontally. White. if (posyr < posyl) { posyr = posyl; } if (posyr < font_width) { posyr = font_width; } length=(int)strlen(gauge_data); txt_width=get_text_width(w,gauge_data); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,gauge_data,0x08,0x0f,length); } } } } } /* * Looks at the style to determine what color to use. * KG4NBB */ static int getLineColor(char styleChar) { int color; switch (styleChar) { case 'a': case 'b': case 'c': color = colors[0x0c]; // red break; case 'd': case 'e': case 'f': color = colors[0x0e]; // yellow break; case 'g': case 'h': case 'i': color = colors[0x09]; // blue break; case 'j': case 'k': case 'l': color = colors[0x0a]; // green break; default: color = colors[0x0a]; // green break; } return color; } /* * Looks at the style to determine what line type to use. * KG4NBB */ static int getLineStyle(char styleChar) { int style; switch (styleChar) { case 'a': case 'd': case 'g': case 'j': style = LineSolid; break; case 'b': case 'e': case 'h': case 'k': style = LineOnOffDash; break; case 'c': case 'f': case 'i': case 'l': style = LineDoubleDash; break; default: style = LineSolid; break; } return style; } /* * Draw the other points associated with the station. * KG4NBB */ void draw_multipoints(long UNUSED(x_long), long UNUSED(y_lat), int numpoints, long mypoints[][2], char type, char style, time_t sec_heard, Pixmap where) { int ghost; int skip_duplicates; // See if we should draw multipoints for this station. This only happens // if there are points to draw and the object has not been cleared (or // we're supposed to show old data). // Per Dale Huguley in e-mail 07/10/2003, a good interval for // the severe weather polygons to disappear is 10 minutes. We // hard-code it here so the user can't mess it up too badly with // the ghosting interval. // ghost = (int)(((sec_old+sec_heard)) < sec_now()); ghost = (int)( ( sec_heard + (10 * 60) ) < sec_now() ); // We don't want to draw them if the ghost interval is up, no // matter whether Include Expired Data is checked. //if ( (!ghost || Select_.old_data) && (numpoints > 0) ) { if ( !ghost && (numpoints > 0) ) { //long x_offset, y_offset; int i; // XPoint xpoints[MAX_MULTIPOINTS + 1]; #if 0 long mostNorth, mostSouth, mostWest, mostEast; // Check to see if the object is onscreen. // Look for the coordinates that are farthest north, farthest south, // farthest west, and farthest east. Then check to see if any of that // box is onscreen. If so, proceed with drawing. This is all done in // Xastir coordinates. mostNorth = mostSouth = y_lat; mostWest = mostEast = x_long; for (i = 0; i < numpoints; ++i) { if (mypoints[i][0] < mostNorth) { mostNorth = mypoints[i][0]; } if (mypoints[i][0] > mostSouth) { mostSouth = mypoints[i][0]; } if (mypoints[i][1] < mostWest) { mostWest = mypoints[i][1]; } if (mypoints[i][1] > mostEast) { mostEast = mypoints[i][1]; } } if (onscreen(mostWest, mostEast, mostNorth, mostSouth)) #else // 0 // See if the station icon is on the screen. If so, draw the associated // points. The drawback to this approach is that if the station icon is // scrolled off the edge of the display the points aren't drawn even if // one or more of them is on the display. // if( (x_long > NW_corner_longitude) && (x_long < SE_corner_longitude) // && (y_lat > NW_corner_latitude) && (y_lat < SE_corner_latitude) ) #endif // 0 { //x_offset = (x_long - NW_corner_longitude) / scale_x; //y_offset = (y_lat - NW_corner_latitude) / scale_y; // Convert each of the points from Xastir coordinates to // screen coordinates and fill in the xpoints array. // for (i = 0; i < numpoints; ++i) { // xpoints[i].x = (mypoints[i][0] - NW_corner_longitude) / scale_x; // xpoints[i].y = (mypoints[i][1] - NW_corner_latitude) / scale_y; // // fprintf(stderr," %d: %d,%d\n", i, xpoints[i].x, xpoints[i].y); // } // The type parameter determines how the points will be used. // After determining the type, use the style parameter to // get the color and line style. switch (type) { case '0': // closed polygon default: // Repeat the first point so the polygon will be closed. // xpoints[numpoints].x = xpoints[0].x; // xpoints[numpoints].y = xpoints[0].y; // First draw a wider black line. (void)XSetForeground(XtDisplay(da), gc, colors[0x08]); // black (void)XSetLineAttributes(XtDisplay(da), gc, 4, LineSolid, CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints+1, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } // Close the polygon draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[0][0], mypoints[0][1], gc, where, skip_duplicates); // Then draw the appropriate colored line on top of it. (void)XSetForeground(XtDisplay(da), gc, getLineColor(style)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, getLineStyle(style), CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints+1, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } // Close the polygon draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[0][0], mypoints[0][1], gc, where, skip_duplicates); break; case '1': // line segments (void)XSetForeground(XtDisplay(da), gc, getLineColor(style)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, getLineStyle(style), CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } break; // Other types have yet to be implemented. } } } } void Select_symbol_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; int i; XtPopdown(shell); // Free all 188 symbol pixmaps for ( i = 0; i < (126-32)*2; i++ ) { (void)XFreePixmap(XtDisplay(appshell),select_icons[i]); } begin_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol_destroy_shell" ); XtDestroyWidget(shell); select_symbol_dialog = (Widget)NULL; end_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol_destroy_shell" ); } void Select_symbol_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char table[2]; char symbol[2]; int i = XTPOINTER_TO_INT(clientData); //fprintf(stderr,"Selected a symbol: %d\n", clientData); if ( i > 0) { //fprintf(stderr,"Symbol is from primary symbol table: /%c\n",(char)i); table[0] = '/'; symbol[0] = (char)i; } else { //fprintf(stderr,"Symbol is from secondary symbol table: \\%c\n",(char)(-i)); table[0] = '\\'; symbol[0] = (char)(-i); } table[1] = '\0'; symbol[1] = '\0'; if (symbol_change_requested_from == 1) // Configure->Station Dialog { symbol_change_requested_from = 0; //fprintf(stderr,"Updating Configure->Station Dialog\n"); XmTextFieldSetString(station_config_group_data,table); XmTextFieldSetString(station_config_symbol_data,symbol); updateSymbolPictureCallback(widget,clientData,callData); } else if (symbol_change_requested_from == 2) // Create->Object/Item Dialog { symbol_change_requested_from = 0; //fprintf(stderr,"Updating Create->Object/Item Dialog\n"); XmTextFieldSetString(object_group_data,table); XmTextFieldSetString(object_symbol_data,symbol); updateObjectPictureCallback(widget,clientData,callData); } else // Do nothing. We shouldn't be here. { symbol_change_requested_from = 0; } Select_symbol_destroy_shell(widget,select_symbol_dialog,callData); } void Select_symbol( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, my_form2, my_form3, button_cancel, frame, frame2, b1, scrollwindow; int i; Atom delw; if (!select_symbol_dialog) { begin_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol" ); select_symbol_dialog = XtVaCreatePopupShell(langcode("SYMSEL0001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Select_symbol pane", xmPanedWindowWidgetClass, select_symbol_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("Select_symbol scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Select_symbol my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); frame = XtVaCreateManagedWidget("Select_symbol frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Discard the return value of this function, we're not using it. // GCC 6.x *hates* when we assign to variables we never use. XtVaCreateManagedWidget(langcode("SYMSEL0002"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); frame2 = XtVaCreateManagedWidget("Select_symbol frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, frame, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Discard the return value of this function call, we're not using it. // GCC 6.x *hates* when we assign to variables we never use. XtVaCreateManagedWidget(langcode("SYMSEL0003"), xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); my_form2 = XtVaCreateWidget("Select_symbol my_form2", xmRowColumnWidgetClass, frame, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, XmNnumColumns, 10, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form3 = XtVaCreateWidget("Select_symbol my_form3", xmRowColumnWidgetClass, frame2, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, XmNnumColumns, 10, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Symbols: 33 to 126, for both '/' and '\' tables (94 * 2) // 33 = start of icons in ASCII table, 126 = end // Draw the primary symbol set for ( i = 33; i < 127; i++ ) { select_icons[i-33] = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); b1 = XtVaCreateManagedWidget("symbol button", xmPushButtonWidgetClass, my_form2, XmNlabelType, XmPIXMAP, XmNlabelPixmap, select_icons[i-33], XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); symbol(b1,0,'/',(char)i,' ',select_icons[i-33],0,0,0,' '); // create icon // Here we send back the ascii number of the symbol. We need to keep it within // the range of short int's. XtAddCallback(b1, XmNactivateCallback, Select_symbol_change_data, INT_TO_XTPOINTER(i) ); } // Draw the alternate symbol set for ( i = 33+94; i < 127+94; i++ ) { select_icons[i-33] = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); b1 = XtVaCreateManagedWidget("symbol button", xmPushButtonWidgetClass, my_form3, XmNlabelType, XmPIXMAP, XmNlabelPixmap, select_icons[i-33], XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); symbol(b1,0,'\\',(char)i-94,' ',select_icons[i-33],0,0,0,' '); // create icon // Here we send back the ascii number of the symbol negated. We need to keep it // within the range of short int's. XtAddCallback(b1, XmNactivateCallback, Select_symbol_change_data, INT_TO_XTPOINTER(-(i-94)) ); } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Select_symbol_destroy_shell, select_symbol_dialog); pos_dialog(select_symbol_dialog); delw = XmInternAtom(XtDisplay(select_symbol_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(select_symbol_dialog, delw, Select_symbol_destroy_shell, (XtPointer)select_symbol_dialog); XtManageChild(my_form3); XtManageChild(my_form2); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, select_symbol_dialog); XtPopup(select_symbol_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(select_symbol_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); end_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol" ); } else { (void)XRaiseWindow(XtDisplay(select_symbol_dialog), XtWindow(select_symbol_dialog)); } } // Function to draw dead-reckoning symbols. // void draw_deadreckoning_features(DataRow *p_station, Pixmap where, Widget w) { double my_course; long x_long, y_lat; long x_long2, y_lat2; long x, y; long x2, y2; double diameter; int color = trail_colors[p_station->trail_color]; // int symbol_on_screen = 0; int ghosted_symbol_on_screen = 0; // This function takes a bit of CPU if we are zoomed out. It'd be // best to check first whether the zoom level and the speed make it // worth computing DR at all for this station. As a first // approximation, we could turn off DR if we're at zoom 8000 or // higher: // // if (scale_y > 8000) // return; x_long = p_station->coord_lon; y_lat = p_station->coord_lat; // x/y are screen locations for start position x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; y_lat2 = y_lat; x_long2 = x_long; // Compute the latest DR'ed position for the object compute_current_DR_position(p_station, &x_long2, &y_lat2); // x2/y2 are screen location for ghost symbol (DR'ed position) x2 = (x_long2 - NW_corner_longitude)/scale_x; y2 = (y_lat2 - NW_corner_latitude)/scale_y; // Check DR'ed symbol position if ( (x_long2>NW_corner_longitude) && (x_long2NW_corner_latitude) && (y_lat2=0) && (x_long<=129600000l)) && ((y_lat>=0) && (y_lat<=64800000l))) { ghosted_symbol_on_screen++; } // Draw the DR arc // if (Display_.dr_arc && ghosted_symbol_on_screen) { double xdiff, ydiff; xdiff = (x2-x) * 1.0; ydiff = (y2-y) * 1.0; // a squared + b squared = c squared diameter = 2.0 * sqrt( (double)( (ydiff*ydiff) + (xdiff*xdiff) ) ); //fprintf(stderr,"Range:%f\tDiameter:%f\n",range,diameter); if (diameter > 10.0) { int arc_degrees = (sec_now() - p_station->sec_heard) * 90 / (5*60); if (arc_degrees > 360) { arc_degrees = 360; } (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineOnOffDash, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); // Compute angle from the two screen positions. // if (xdiff != 0) { //We should guard against divide-by-zero here! my_course = 57.29578 * atan(xdiff/ ydiff); } else { if (ydiff >= 0) { my_course = 180.0; } else { my_course = 0.0; } } //fprintf(stderr,"my_course:%f\n", my_course); // The arctan function returns values between -90 and +90. To // obtain the true course we apply the following rules: if (ydiff > 0 && xdiff > 0) { //fprintf(stderr,"1\n"); // Lower-right quadrant my_course = 360.0 - my_course; } else if (ydiff < 0.0 && xdiff > 0.0) { //fprintf(stderr,"2\n"); // Upper-right quadrant my_course = 180.0 - my_course; } else if (ydiff < 0.0 && xdiff < 0.0) { //fprintf(stderr,"3\n"); // Upper-left quadrant my_course = 180.0 - my_course; } else if (ydiff > 0.0 && xdiff < 0.0) { //fprintf(stderr,"4\n"); // Lower-left quadrant my_course = 360.0 - my_course; } else // 0/90/180/270 { //fprintf(stderr,"5\n"); my_course = 180.0 + my_course; } // Convert to screen angle for XDrawArc routines: my_course = my_course + 90.0; if (my_course > 360.0) { my_course = my_course - 360.0; } //fprintf(stderr,"\tmy_course2:%f\n", my_course); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(x-(diameter/2)), // int l16(y-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(-64*my_course), // int l16(64/2*arc_degrees)); // int // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(x-(diameter/2)), // int l16(y-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(-64*my_course), // int l16(-64/2*arc_degrees)); // int } } // Note that for the DR course, if we're in the middle of the symbol // and the DR'ed symbol (ghosted symbol), but neither of them are // on-screen, the DR'ed course won't display. // // Draw the DR'ed course if either the symbol or the DR'ed // symbol (ghosted symbol) are on-screen. // if (Display_.dr_course) { (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // red3 // This one changes the angle as the vector gets longer, by // about 10 degrees (A test at 133 degrees -> 143 degrees). // draw_vector() needs to truncate the line in this case, // maintaining the same slope. This behavior is _much_ // better than the XDrawLine above though! // draw_vector(w, x_long, y_lat, x_long2, y_lat2, gc, where, 0); } // Draw the DR'ed symbol (ghosted symbol) if enabled and if // on-screen. // if (Display_.dr_symbol && ghosted_symbol_on_screen) { draw_symbol(w, p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay, x_long2, y_lat2, "", "", "", "", "", "", "", "", p_station->sec_heard-sec_old, // Always draw it ghosted 0, where, symbol_orient(p_station->course), p_station->aprs_symbol.area_object.type, p_station->signpost, NULL, 0); // Don't bump the station count } } Xastir-Release-2.2.2/src/draw_symbols.h000066400000000000000000000105631501463444000200200ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_DRAW_SYMBOLS_H #define __XASTIR_DRAW_SYMBOLS_H #define SYMBOL_ACTIVE 'A' #define SYMBOL_NOTACTIVE 'N' #define MAX_SYMBOLS 400 typedef struct { char active; // ?? char table; // table character char symbol; // symbol character char orient; // orientation of the symbol, one of ' ', 'l','r','u','d' Pixmap pix; // icon picture Pixmap pix_mask; // mask for transparent background Pixmap pix_mask_old; // mask for ghost symbols, half transparent icons } SymbolData; extern SymbolData symbol_data[]; extern void draw_nice_string(Widget w, Pixmap where, int style, long x, long y, char *text, int bgcolor, int fgcolor, int length); extern void clear_symbol_data(void); extern void read_symbol_from_file(FILE *f, char *pixels, char table_char); extern void load_pixmap_symbol_file(char *filename, int reloading); extern void insert_symbol(char table, char symbol, char *pixel, int deg, char orient, int reloading); extern char symbol_orient(char *course); extern void symbol(Widget w, int ghost,char symbol_table, char symbol_id, char symbol_overlay, Pixmap where, int mask, long x_offset, long y_offset, char rotate); long get_text_width(Widget w,char *text); extern void draw_WP_line(DataRow *p_station, int ambiguity_flag, long ambiguity_coord_lon, long ambiguity_coord_lat, Pixmap where, Widget w); extern void draw_symbol(Widget w, char symbol_table, char symbol_id, char symbol_overlay, long x_lon, long y_lat,char *callsign_text, char *alt_text, char *course_text, char *speed_text, char *my_distance, char *my_course, char *wx_temp, char* wx_wind, time_t sec_heard, int temp_show_last_heard, Pixmap where, char rotate, char area_type, char *signpost, char *gauge_data, int bump_count ); extern void draw_pod_circle(long x_long, long y_lat, double range, int color, Pixmap where, int sec_heard); extern void draw_precision_rectangle(long x_long, long y_lat, double range, unsigned int lat_precision, unsigned int lon_precision, int color, Pixmap where); extern void draw_aloha_circle(long x_long, long y_lat, double range, int color, Pixmap where); extern void draw_phg_rng(long x_long, long y_lat, char *phg, time_t sec_heard, Pixmap where); extern void draw_DF_circle(long x_long, long y_lat, char *shgd, time_t sec_heard, Pixmap where); extern void draw_wind_barb(long x_long, long y_lat, char *speed, char *course, time_t sec_heard, Pixmap where); extern void draw_bearing(long x_long, long y_lat, char *course, char *bearing, char *NRQ, int color, int draw_beamwidth, int draw_bearing, time_t sec_heard, Pixmap where); extern void draw_ambiguity(long x_long, long y_lat, char amb, long *amb_x_long, long *amb_y_lat, time_t sec_heard, Pixmap where); extern void draw_area(long x_long, long y_lat, char type, char color, char sqrt_lat_off, char sqrt_lon_off, unsigned int width, time_t sec_heard, Pixmap where); extern void draw_multipoints(long x_long, long y_lat, int numpoints, long points[][2], char type, char style, time_t sec_heard, Pixmap where); // KG4NBB extern void Select_symbol( Widget w, XtPointer clientData, XtPointer callData); extern int symbol_change_requested_from; extern Widget select_symbol_dialog; extern void Select_symbol_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData); extern void draw_symbols_init(void); extern void draw_deadreckoning_features(DataRow *p_station, Pixmap where, Widget w); #endif // __XASTIR_DRAW_SYMBOLS_H Xastir-Release-2.2.2/src/fcc_data.c000066400000000000000000000415741501463444000170400ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include "xastir.h" #include "fcc_data.h" #include "xa_config.h" #include "main.h" // Must be last include file #include "leak_detection.h" char *call_only(char *callsign) { int i, len; len = strlen(callsign); for (i = 0; i < len; i++) { if (!isalnum((int)callsign[i])) { callsign[i]='\0'; i=len; } } return(callsign); } /* ==================================================================== */ /* build a new (or newer if I check the file date) index file */ /* check for current ic index file */ /* FG: added a date check in case the FCC file has been updated. */ /* appl.dat must have a time stamp newer than the index file time */ /* stamp. Use the touch command on the appl.dat file to make the */ /* time current if necessary. */ // How this works: The index file contains a few callsigns and their // offsets into the large database file. The code uses these as // jump-off points to look for a particular call, to speed things up. /* ******************************************************************** */ int build_fcc_index(int type) { FILE *fdb; FILE *fndx; unsigned long call_offset = 0; unsigned long x = 0; char fccdata[FCC_DATA_LEN+8]; char database_name[100]; int found,i,num; char appl_file_path[MAX_VALUE]; if (type==1) { xastir_snprintf(database_name, sizeof(database_name), "fcc/appl.dat"); } else { xastir_snprintf(database_name, sizeof(database_name), "fcc/EN.dat"); } /* ==================================================================== */ /* If the index file is there, exit */ /* */ get_user_base_dir("data/appl.ndx", appl_file_path, sizeof(appl_file_path)); if (filethere(appl_file_path)) { /* if file is there make sure the index date is newer */ if (file_time(get_data_base_dir(database_name))<=file_time(appl_file_path)) { return(1); } else { // FCC index old, rebuilding statusline(langcode("STIFCC0100"),1); fprintf(stderr,"FCC index is old. Rebuilding index.\n"); // XmTextFieldSetString(text,"FCC index old, rebuilding"); // XtManageChild(text); // XmUpdateDisplay(XtParent(text)); // DK7IN: do we need this ??? } } /* ==================================================================== */ /* Open the database and index file */ /* */ fdb=fopen(get_data_base_dir(database_name),"rb"); if (fdb==NULL) { fprintf(stderr,"Build:Could not open FCC data base: %s\n", get_data_base_dir(database_name) ); return(0); } fndx=fopen(appl_file_path,"w"); if (fndx==NULL) { fprintf(stderr,"Build:Could not open/create FCC data base index: %s\n", appl_file_path ); (void)fclose(fdb); return(0); } /* ==================================================================== */ /* write out the current callsign and RBA of the db file */ /* skip (index_skip) records and do it again until no more */ /* */ xastir_snprintf(fccdata,sizeof(fccdata)," "); while(!feof(fdb)) { call_offset = (unsigned long)ftell(fdb); if (fgets(fccdata, (int)sizeof(fccdata), fdb) == NULL) { // error occurred fprintf(stderr,"Build: Could not read fcc data base: %s \n", appl_file_path); (void)fclose(fdb); return(0); } found=0; num=0; if (type==2) { for(i=0; i<14 && !found; i++) { if(fccdata[i]=='|') { num++; if(num==4) { found=i+1; } } } } (void)call_only(fccdata+found); fprintf(fndx,"%-6.6s%li\n",fccdata+found,call_offset+found); for (x=0; x<=500 && !feof(fdb); x++) { if (fgets(fccdata, (int)sizeof(fccdata), fdb)==NULL) { break; } } } (void)fclose(fdb); (void)fclose(fndx); // XmTextFieldSetString(text,""); // XtManageChild(text); return(1); } /* ==================================================================== */ /* Check for ic data base file */ /* Check/build the index */ /* */ /* ******************************************************************** */ int check_fcc_data(void) { int fcc_data_available = 0; if (filethere(get_data_base_dir("fcc/EN.dat")) && filethere(get_data_base_dir("fcc/appl.dat"))) { if(file_time(get_data_base_dir("fcc/appl.dat"))<=file_time(get_data_base_dir("fcc/EN.dat"))) { /*fprintf(stderr,"NEW FORMAT FCC DATA FILE is NEWER THAN OLD FCC FORMAT\n");*/ if (build_fcc_index(2)) { fcc_data_available=2; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } else { /*fprintf(stderr,"OLD FORMAT FCC DATA FILE is NEWER THAN NEW FCC FORMAT\n");*/ if (build_fcc_index(1)) { fcc_data_available=1; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } } else { if (filethere(get_data_base_dir("fcc/EN.dat"))) { /*fprintf(stderr,"NO OLD FCC, BUT NEW FORMAT FCC DATA AVAILABLE\n");*/ if (build_fcc_index(2)) { fcc_data_available=2; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } else { if (filethere(get_data_base_dir("fcc/appl.dat"))) { /*fprintf(stderr,"NO NEW FCC, BUT OLD FORMAT FCC DATA AVAILABLE\n");*/ if (build_fcc_index(1)) { fcc_data_available=1; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } } } return(fcc_data_available); } int search_fcc_data_appl(char *callsign, FccAppl *data) { FILE *f; char line[200]; int line_pos; char data_in[16385]; int found, xx, bytes_read; char temp[15]; int len; int which; int i,ii; int pos_it; int llen; char calltemp[8]; int pos,ix,num; FILE *fndx; long call_offset = 0; char char_offset[16]; char index[32]; char appl_file_path[MAX_VALUE]; data->id_file_num[0] = '\0'; data->type_purpose[0] = '\0'; data->type_applicant=' '; data->name_licensee[0] = '\0'; data->text_street[0] = '\0'; data->text_pobox[0] = '\0'; data->city[0] = '\0'; data->state[0] = '\0'; data->zipcode[0] = '\0'; data->date_issue[0] = '\0'; data->date_expire[0] = '\0'; data->date_last_change[0] = '\0'; data->id_examiner[0] = '\0'; data->renewal_notice=' '; xastir_snprintf(temp, sizeof(temp), "%s", callsign); (void)call_only(temp); xastir_snprintf(calltemp, sizeof(calltemp), "%-6.6s", temp); // calltemp doesn't appear to get used anywhere... /* add end of field data */ strncat(temp, "|", sizeof(temp) - 1 - strlen(temp)); len=(int)strlen(temp); found=0; line_pos=0; /* check the database again */ which = check_fcc_data(); // Check for first letter of a U.S. callsign if (! (callsign[0] == 'A' || callsign[0] == 'K' || callsign[0] == 'N' || callsign[0] == 'W') ) { return(0); // Not found } // ==================================================================== // Search thru the index, get the RBA // // This gives us a jumping-off point to start looking in the right // neighborhood for the callsign of interest. // get_user_base_dir("data/appl.ndx", appl_file_path, sizeof(appl_file_path)); fndx=fopen(appl_file_path,"r"); if (fndx!=NULL) { if (fgets(index,(int)sizeof(index),fndx) == NULL) { // Error occurred fprintf(stderr,"Search:Could not read FCC database index(1): %s\n",appl_file_path); return(0); } memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string // Search through the indexes looking for a callsign which is // close to the callsign of interest. If callsign is later in // the alphabet than the current index, snag the next index. while (!feof(fndx) && strncmp(callsign,index,6) > 0) { memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string if (fgets(index,(int)sizeof(index),fndx) == NULL) { // Error occurred fprintf(stderr,"Search:Could not read FCC database index(2): %s\n", appl_file_path ); return(0); } } } else { fprintf(stderr,"Search:Could not open FCC data base index: %s\n", appl_file_path ); return (0); } call_offset = atol(char_offset); (void)fclose(fndx); /* ==================================================================== */ /* Continue with the original search */ /* */ f=NULL; switch (which) { case(1): f=fopen(get_data_base_dir("fcc/appl.dat"),"r"); break; case(2): f=fopen(get_data_base_dir("fcc/EN.dat"),"r"); break; default: break; } if (f!=NULL) { (void)fseek(f, call_offset,SEEK_SET); while (!feof(f) && !found) { bytes_read=(int)fread(data_in,1,16384,f); if (bytes_read>0) { for (xx=0; (xxid_file_num,sizeof(data->id_file_num),"%s",line+pos_it); break; case(1): xastir_snprintf(data->type_purpose,sizeof(data->type_purpose),"%s",line+pos_it); break; case(2): data->type_applicant=line[pos_it]; break; case(3): xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it); break; case(4): xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it); break; case(5): xastir_snprintf(data->text_pobox,sizeof(data->text_pobox),"%s",line+pos_it); break; case(6): xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it); break; case(7): xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it); break; case(8): xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it); break; case(9): xastir_snprintf(data->date_issue,sizeof(data->date_issue),"%s",line+pos_it); break; case(11): xastir_snprintf(data->date_expire,sizeof(data->date_expire),"%s",line+pos_it); break; case(12): xastir_snprintf(data->date_last_change,sizeof(data->date_last_change),"%s",line+pos_it); break; case(13): xastir_snprintf(data->id_examiner,sizeof(data->id_examiner),"%s",line+pos_it); break; case(14): data->renewal_notice=line[pos_it]; break; default: break; } break; case(2): switch (i) { case(0): xastir_snprintf(data->id_file_num,sizeof(data->id_file_num),"%s",line+pos_it); break; case(2): xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it); break; case(10): xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it); break; case(11): xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it); break; case(12): xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it); break; case(13): xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it); break; default: break; } break; default: break; } } } } else { // Check whether we passed the alphabetic // location for the callsign. Return if so. if ( (temp[0] < line[pos]) || ( (temp[0] == line[pos]) && (temp[1] < line[pos+1]) ) ) { // "Callsign Search", "Callsign Not Found!" popup_message_always(langcode("STIFCC0101"), langcode("STIFCC0102") ); //fprintf(stderr,"%c%c\t%c%c\n",temp[0],temp[1],line[pos],line[pos+1]); (void)fclose(f); return(0); } } } } } } (void)fclose(f); } else { fprintf(stderr,"Could not open FCC appl data base at: %s\n", get_data_base_dir("fcc/") ); } return(found); } Xastir-Release-2.2.2/src/fcc_data.h000066400000000000000000000044461501463444000170420ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * FCC Database structures * */ /* type_purpose - Indicates the reason why the application was filed. Multiple codes may occur. Codes are: A New license B Change existing class C Change name D Change mailing address E Change callsign F Renewal on Form 610 G Add record (internal) H Duplicate license request I Change Issue/Expiration Date J Supersede K Internal correction code L Delete N Renewal on form 610R O Renewal on form 610B P Modification on form 610B Q Restore both database and pending R Restore database S Special callsign change type_applicant - Indicates type of application. Codes are: A Alien C Club I Individual M Military recreation R RACES */ #ifndef XASTIR_FCC_DATA_H #define XASTIR_FCC_DATA_H #define FCC_DATA_LEN 200 typedef struct { char id_callsign[11]; char id_file_num[11]; char type_purpose[9]; char type_applicant; char name_licensee[41]; char text_street[36]; char text_pobox[21]; char city[30]; char state[3]; char zipcode[10]; char filler; char date_issue[7]; char date_expire[7]; char date_last_change[7]; char id_examiner[4]; char renewal_notice; } FccAppl; extern int check_fcc_data(void); extern int search_fcc_data_appl(char *callsign, FccAppl *data); #endif /* XASTIR_FCC_DATA_H */ Xastir-Release-2.2.2/src/festival.c000066400000000000000000000346011501463444000171220ustar00rootroot00000000000000// Modification for Xastir CVS purposes // // Portions Copyright (C) 2000-2023 The Xastir Group // // // End of modification /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API in C designed specifically for */ /* Galaxy Communicator use though might be of use for other things */ /* */ /* This is a standalone C client, no other Festival or Speech Tools */ /* libraries need be link with this. Thus is very small. */ /* */ /* Compile with (plus socket libraries if required) */ /* cc -o festival_client -DSTANDALONE festival_client.c */ /* */ /* Run as */ /* festival_client -text "hello there" -o hello.snd */ /* */ /* */ /* This is provided as an example, it is quite limited in what it does */ /* but is functional compiling without -DSTANDALONE gives you a simple */ /* API */ /* */ /*************************************************************************/ /* */ /* Heavily modified and Hacked together to provide a general purpose */ /* interface for use in XASTIR by: */ /* */ /* Ken Koster N7IPB 03/24/2001 */ /* */ /* */ /* More comments added and 'do' loop that waited for 'ok' response */ /* removed. Also cleaned up escape processing */ /* */ /* N7IPB 04/04/2001 */ /* Test for errno result from 'read' operation and re-opening of */ /* connection if it gets closed. */ /* N7IPB 04/08/2001 */ /* */ /*=======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "festival.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" FT_Info *info = NULL; static char last_speech_text[8000]; static time_t last_speech_time = (time_t)0; static time_t festival_connect_attempt_time = (time_t)0; // Set up default struct // void festival_default_info(void) { if (info == NULL) // First time through { // Malloc storage for the struct info = (FT_Info *)malloc(1 * sizeof(FT_Info)); // Fill in the struct if (info != NULL) { info->server_host = FESTIVAL_DEFAULT_SERVER_HOST; info->server_port = FESTIVAL_DEFAULT_SERVER_PORT; info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE; info->server_fd = -1; } else // Couldn't allocate memory { fprintf(stderr,"festival_default_info: Couldn't malloc\n"); } } return; } // Returns a FD to a remote server // static int festival_socket_open(const char *host, int port) { struct sockaddr_in serv_addr; struct hostent *serverhost; int fd; // Delay at least 60 seconds between each socket attempt if ( (festival_connect_attempt_time + 60) > sec_now() ) { //fprintf(stderr,"Not time yet\n"); return(-1); } festival_connect_attempt_time = sec_now(); if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { fprintf(stderr,"festival_client: can't get socket\n"); return(-1); } memset(&serv_addr, 0, sizeof(serv_addr)); if ((int)(serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) { /* its a name rather than an ipnum */ serverhost = gethostbyname(host); if (serverhost == (struct hostent *)0) { fprintf(stderr,"festival_client: gethostbyname failed\n"); return(-1); } memmove(&serv_addr.sin_addr,serverhost->h_addr, (size_t)serverhost->h_length); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { fprintf(stderr,"festival_client: connect to server failed\n"); (void)close(fd); // Close the socket return(-1); } return(fd); } /***********************************************************************/ /* Public Functions to this API */ /***********************************************************************/ // Close socket to server // int festivalClose(void) { //fprintf(stderr,"festivalClose()\n"); if (info != NULL) // We have a struct allocated { // Check whether we have a socket open if (info->server_fd != -1) { fprintf(stderr,"Closing Festival socket\n"); (void)close(info->server_fd); // Close the socket info->server_fd = -1; // Just to be safe } // Free the struct, zero the pointer. The struct will get // re-created/re-initialized later when we re-open the // festival connection. free(info); info = NULL; } return(0); } // Open socket to server. Close the connection if one is already // open. // int festivalOpen(void) { //fprintf(stderr,"festivalOpen()\n"); festival_default_info(); // Check whether we have a record to work with if (info == NULL) { return(-1); } // Check whether we already have a socket open (or think we do) if (info->server_fd != -1) // We have a socket open { (void)festivalClose(); // Close it, free struct usleep(50000); // 50ms wait } info->server_fd = festival_socket_open(info->server_host, info->server_port); if (info->server_fd == -1) // Error occurred opening socket { //fprintf(stderr,"festivalOpen: Error opening socket\n"); (void)festivalClose(); // Close, free struct usleep(50000); // 50ms wait return(-1); } return(0); } void festivalStringToSpeech(char *text) { FILE *fd; char *p; char ack[4]; int n; int tmp = 0; int ret; //fprintf(stderr,"festivalStringToSpeech()\n"); // If we don't have a struct allocated if (info == 0) { if (festivalOpen() == -1) // Allocate struct, open socket { //fprintf(stderr,"festivalStringToSpeech: Couldn't open socket to Festival\n"); return; } } if (info == 0) // If socket is still not open { return; } if (info->server_fd == -1) { fprintf(stderr,"festival_client: server connection unopened\n"); (void)festivalClose(); return; } fd = fdopen(dup(info->server_fd),"wb"); if (fd == NULL) { fprintf(stderr,"Couldn't create duplicate socket\n"); (void)festivalClose(); return; } /* ** Send the mode commands to festival */ ret = fprintf(fd,"(audio_mode `async)\n(SayText \"\n"); if (ret == 0 || ret == -1) { fprintf(stderr,"Couldn't send mode commands to festival\n"); (void)fclose(fd); (void)festivalClose(); return; } /* ** Copy text over to server, escaping any quotes */ for (p=text; p && (*p != '\0'); p++) { if ((*p == '"') || (*p == '\\')) { if (putc('\\',fd) == EOF) // Error writing to socket { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } else { /* ** Then convert any embedded '-' into the word 'dash' ** This could cause problems with spoken text from ** Weather alerts or messages. We'll deal with that ** later if necessary. Making this a separate function ** is probably the thing to do. */ if (*p == '-' ) { ret = fprintf(fd,",dash,"); if (ret == 0 || ret == -1) { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } else { if (putc(*p,fd) == EOF) // Error writing to socket { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } } } /* ** Complete the command to xastir, close the quotes and ** set the mode to 'fundamental' */ ret = fprintf(fd,"\" \"%s\")\n",info->text_mode); if (ret == 0 || ret == -1) { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } /* ** Close the duplicate port we used for writing */ (void)fclose(fd); /* ** Read back info from server ** ** We don't really care what we get back. If it's an error ** We're just going to continue on anyway so I've removed the ** check here for the 'OK' response. We still check for an ERror ** but we just print the fact we got it and continue on ** ** This could probably use some work, I need to study the ** festival docs a bit more, this could block and it could ** also have more than 3bytes that need to be read. It doesn't ** appear to matter but should be checked into. */ for (n=0; n < 3; ) { if ( ( tmp = read(info->server_fd,ack+n,3-n)) != -1 ) { n = n + tmp; } else { if (debug_level & 2) { fprintf(stderr,"Error reading festival ACK - %s\n",strerror(errno)); } n = 3; if (errno == ECONNRESET) { fprintf(stderr,"Connection reset\n"); info = 0; (void)festivalClose(); if (festivalOpen() == -1) { fprintf(stderr,"festivalStringToSpeech2: Couldn't open socket to Festival\n"); return; } } } } /* ** Null terminate the string */ ack[3] = '\0'; if (strcmp(ack,"ER\n") == 0) /* server got an error */ { fprintf(stderr,"festival_client: server returned error\n"); } return; } int SayText(char *text) { if (debug_level & 2) { fprintf(stderr,"SayText: %s\n",text); } // Check whether the last text was the same and it hasn't been // enough time between them (30 seconds). We include our speech // system test string here so that we don't have to wait 30 // seconds between Test button-presses. if ( (strcmp(last_speech_text,text) == 0) // Strings match && (strcmp(text,SPEECH_TEST_STRING) != 0) && (last_speech_time + 30 > sec_now()) ) { /* fprintf(stderr, "Same text, skipping speech: %d seconds, %s\n", (int)(sec_now() - last_speech_time), text); */ return(1); } //fprintf(stderr,"Speaking: %s\n",text); xastir_snprintf(last_speech_text, sizeof(last_speech_text), "%s", text); last_speech_time = sec_now(); festivalStringToSpeech(text); return(0); } int SayTextInit(void) { if (festivalOpen() == -1) { fprintf(stderr,"SayText: Couldn't open socket to Festival\n"); } last_speech_text[0] = '\0'; last_speech_time = (time_t)0; return(0); } Xastir-Release-2.2.2/src/festival.h000066400000000000000000000107221501463444000171250ustar00rootroot00000000000000// Modification for Xastir CVS purposes // // Portions Copyright (C) 2000-2023 The Xastir Group // // End of modification /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API (in C) designed specifically for */ /* Galaxy Communicator use, though might be of use for other things */ /* */ /*=======================================================================*/ #ifndef _FESTIVAL_CLIENT_H_ #define _FESTIVAL_CLIENT_H_ #define FESTIVAL_DEFAULT_SERVER_HOST "localhost" #define FESTIVAL_DEFAULT_SERVER_PORT 1314 #define FESTIVAL_DEFAULT_TEXT_MODE "fundamental" typedef struct FT_Info { int encoding; char *server_host; int server_port; char *text_mode; int server_fd; } FT_Info; typedef struct FT_Wave { int num_samples; int sample_rate; short *samples; } FT_Wave; void delete_FT_Wave(FT_Wave *wave); void delete_FT_Info(FT_Info *info); #define SWAPSHORT(x) ((((unsigned)x) & 0xff) << 8 | \ (((unsigned)x) & 0xff00) >> 8) #define SWAPINT(x) ((((unsigned)x) & 0xff) << 24 | \ (((unsigned)x) & 0xff00) << 8 | \ (((unsigned)x) & 0xff0000) >> 8 | \ (((unsigned)x) & 0xff000000) >> 24) /* Sun, HP, SGI Mips, M68000 */ #define FAPI_BIG_ENDIAN (((char *)&fapi_endian_loc)[0] == 0) /* Intel, Alpha, DEC Mips, Vax */ #define FAPI_LITTLE_ENDIAN (((char *)&fapi_endian_loc)[0] != 0) /*****************************************************************/ /* Public functions to interface */ /*****************************************************************/ /* If called with NULL will attempt to access using defaults */ int festivalOpen(void); void festivalStringToWave(char *text); int festivalClose(void); #endif // _FESTIVAL_CLIENT_H_ Xastir-Release-2.2.2/src/fetch_remote.c000066400000000000000000000147761501463444000177640ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL // Needed for size_t #include // Must be last include file #include "leak_detection.h" extern int debug_level; extern int net_map_timeout; /* curl routines */ #ifdef HAVE_LIBCURL struct FtpFile { char *filename; FILE *stream; }; size_t curl_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) { struct FtpFile *out = (struct FtpFile *)stream; if (out && !out->stream) { out->stream=fopen(out->filename, "wb"); if (!out->stream) { return -1; } } return fwrite(buffer, size, nmemb, out->stream); } /* * xastir_curl_init - create curl session with common options */ CURL *xastir_curl_init(char *errBuf) { CURL *mySession; char agent_string[15]; mySession = curl_easy_init(); if (mySession != NULL) { if (debug_level & 8192) { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 1); } else { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 0); } curl_easy_setopt(mySession, CURLOPT_ERRORBUFFER, errBuf); xastir_snprintf(agent_string, sizeof(agent_string),"Xastir"); curl_easy_setopt(mySession, CURLOPT_USERAGENT, agent_string); // write function curl_easy_setopt(mySession, CURLOPT_WRITEFUNCTION, curl_fwrite); curl_easy_setopt(mySession, CURLOPT_TIMEOUT, (long)net_map_timeout); curl_easy_setopt(mySession, CURLOPT_CONNECTTIMEOUT, (long)(net_map_timeout/2)); // Added in libcurl 7.9.8 #if (LIBCURL_VERSION_NUM >= 0x070908) curl_easy_setopt(mySession, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.6 #if (LIBCURL_VERSION_NUM >= 0x071006) curl_easy_setopt(mySession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.7 #if (LIBCURL_VERSION_NUM >= 0x071007) curl_easy_setopt(mySession, CURLOPT_PROXYAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10 #if (LIBCURL_VERSION_NUM >= 0x070a00) // This prevents a segfault for the case where we get a timeout on // domain name lookup. It has to do with the ALARM signal // and siglongjmp(), which we use in hostname.c already. // This URL talks about it a bit more, plus see the libcurl // docs: // // http://curl.haxx.se/mail/lib-2002-12/0103.html // curl_easy_setopt(mySession, CURLOPT_NOSIGNAL, 1); #endif // LIBCURL_VERSION_NUM } return(mySession); } // xastir_curl_init() /* * fetch_remote_tile - downloads file using an open curl session * Returns curl result code. */ int fetch_remote_tile(CURL *session, char *tileURL, char *tileFileName) { CURLcode res; struct FtpFile ftpfile; curl_easy_setopt(session, CURLOPT_URL, tileURL); ftpfile.filename = tileFileName; ftpfile.stream = NULL; curl_easy_setopt(session, CURLOPT_FILE, &ftpfile); res = curl_easy_perform(session); if (ftpfile.stream) { fclose(ftpfile.stream); } return(res); } // fetch_remote_tile() #endif // HAVE_LIBCURL /* * fetch_remote_file * Returns: 0 If file retrieved * 1 If there was a problem getting the file */ int fetch_remote_file(char *fileimg, char *local_filename) { #ifdef HAVE_LIBCURL CURL *curl; CURLcode res; char curlerr[CURL_ERROR_SIZE]; struct FtpFile ftpfile; //fprintf(stderr, "Fetching remote file: %s\n", fileimg); curl = xastir_curl_init(curlerr); if (curl) { // download from fileimg curl_easy_setopt(curl, CURLOPT_URL, fileimg); ftpfile.filename = local_filename; ftpfile.stream = NULL; curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (CURLE_OK != res) { fprintf(stderr, "curl told us %d\n", res); fprintf(stderr, "curlerr: %s\n", curlerr); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); } if (ftpfile.stream) { fclose(ftpfile.stream); } // Return error-code if we had trouble if (CURLE_OK != res) { return(1); } } else { fprintf(stderr,"Couldn't download the file %s\n", fileimg); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); return(1); } return(0); // Success! #else // HAVE_LIBCURL #ifdef HAVE_WGET char tempfile[500]; //"%s --server-response --timestamping --user-agent=Xastir --tries=1 --timeout=%d --output-document=%s \'%s\' 2> /dev/null\n", xastir_snprintf(tempfile, sizeof(tempfile), "%s --server-response --user-agent=Xastir --tries=1 --timeout=%d --output-document=%s \'%s\' 2> /dev/null\n", WGET_PATH, net_map_timeout, local_filename, fileimg); if (debug_level & 2) { fprintf(stderr,"%s",tempfile); } if ( system(tempfile) ) // Go get the file { fprintf(stderr,"Couldn't download the file\n"); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); return(1); } return(0); // Success! #else // HAVE_WGET fprintf(stderr,"libcurl or 'wget' not installed. Can't download file\n"); return(1); #endif // HAVE_WGET #endif // HAVE_LIBCURL } Xastir-Release-2.2.2/src/fetch_remote.h000066400000000000000000000024141501463444000177530ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_FETCH_REMOTE_H #define __XASTIR_FETCH_REMOTE_H #ifdef HAVE_LIBCURL #include CURL *xastir_curl_init(char *errBuf); int fetch_remote_tile(CURL *session, char *tileURL, char *tileFileName); #endif // HAVE_LIBCURL int fetch_remote_file(char *fileimg, char *local_filename); #endif // __XASTIR_FETCH_REMOTE_H Xastir-Release-2.2.2/src/forked_getaddrinfo.c000066400000000000000000000245571501463444000211360ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include //Needed for Solaris 2.5 #include #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "lang.h" // Must be last include file #include "leak_detection.h" #include "forked_getaddrinfo.h" #ifndef HAVE_SIGHANDLER_T #ifdef HAVE_SIG_T typedef sig_t sighandler_t; #else typedef void (*sighandler_t)(int); #endif #endif #ifndef __LCLINT__ #ifndef HAVE_SIGJMP_BUF jmp_buf ret_place; #else // HAVE_SIGJMP_BUF static sigjmp_buf ret_place; /* Jump address if alarm */ #endif // HAVE_SIGJMP_BUF #endif // __LCLINT__ /*************************************************************************/ /* Time out on connect */ /* In case there is a problem in getting the hostname or connecting */ /* (see setjmp below). */ /*************************************************************************/ static void host_time_out( int UNUSED(sig) ) { #ifndef __LCLINT__ siglongjmp(ret_place,0); #endif // __LCLINT__ } /*************************************************************************/ /* do a nice host lookup (don't thread!!) */ /* */ /* host: name to lookup */ /* ip: buffer for ip's must be 400 bytes at least */ /* time: time in seconds to wait */ /* */ /* return the ip or ip's of the host name */ /* or these strings: */ /* NOHOST for no host by that name found */ /* NOIP for host found but no ip address available */ /* TIMEOUT for time exceeded */ /*************************************************************************/ #define RETSIGTYPE void int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time) { RETSIGTYPE * previous_loc; pid_t host_pid; int status; int fp[2]; int tm; int i; int rc = EAI_FAIL; char ttemp[60]; int wait_host; struct addrinfo *res0; struct addrinfo *res; if (debug_level & 1024) { fprintf(stderr,"Start Host lookup\n"); } busy_cursor(appshell); if (debug_level & 1024) { fprintf(stderr,"Creating pipe\n"); } // Create a pipe for communication if (pipe(fp)!=0) { fprintf(stderr, "Error creating pipe for hostname lookup: %s\n", strerror(errno)); return rc; } host_pid = fork(); // Fork off a child process if (debug_level & 1024) { fprintf(stderr,"Host fork\n"); } if (host_pid!=-1) // If the fork was successful { //--------------------------------------------------------------------------------------- if (host_pid==0) // We're in the child process { // Go back to default signal handler instead of // calling restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So far // this only works for "ps" listings, not for "top". // This code only works on Linux. For BSD use // setproctitle(3), NetBSD can use setprogname(2). #ifdef __linux__ init_set_proc_title(my_argc, my_argv, my_envp); set_proc_title("%s", "hostname lookup (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); #endif // __linux__ // Close the end of the pipe we don't need here if (debug_level & 1024) { fprintf(stderr,"Child closing read end of pipe\n"); } close(fp[0]); // Read end of the pipe if (debug_level & 1024) { fprintf(stderr,"Set alarm \n"); } previous_loc = (RETSIGTYPE *)signal(SIGALRM, host_time_out); // Set up to jump here if we time out on SIGALRM if (sigsetjmp(ret_place,-1)!=0) { // Turn off the alarm (void)alarm(0); // Reset the SIGALRM handler to its previous value (void)signal(SIGALRM, (sighandler_t)previous_loc); // Return net connection time out rc = FAI_TIMEOUT; if (write(fp[1],&rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (debug_level & 1024) { fprintf(stderr,"Child closing write end of pipe\n"); } close(fp[1]); // All done writing to the pipe exit(EXIT_FAILURE); // Exit from child process } (void)alarm(time); // Start the timer // Make the call that may time out if no response from DNS /*hostinfo = gethostbyname2(host,AF_INET); some systems don't have this*/ rc = getaddrinfo(hostname, servname, hints, &res0); // If we get to here, we haven't timed out // and we have an answer to process. // Turn off the alarm (void)alarm(0); // Reset the SIGALRM handler to its previous value (void)signal(SIGALRM, (sighandler_t)previous_loc); if (write(fp[1], &rc, sizeof(int)) == -1) // Send status { // Write error. Do nothing as we did prior // to checking the return value. } for (res = res0; res; res = res->ai_next) { // Signal that an entry is coming. rc = 1; if (write(fp[1], &rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } // Send entry if (write(fp[1], res, sizeof(struct addrinfo)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (write(fp[1], res->ai_addr, res->ai_addrlen) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } } // Signal that there is nothing left rc = 0; if (write(fp[1], &rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (debug_level & 1024) { fprintf(stderr,"Child closing write end of pipe\n"); } freeaddrinfo(res0); close(fp[1]); // All done writing to the pipe exit(EXIT_FAILURE); // Exit from child process } // End of child process //--------------------------------------------------------------------------------------- else { // We're in the parent process at this point // Close the end of the pipe we don't need here if (debug_level & 1024) { fprintf(stderr,"Parent closing write end of pipe\n"); } close(fp[1]); // Write end of the pipe tm=1; wait_host=1; while (wait_host!=-1) { xastir_snprintf(ttemp, sizeof(ttemp), langcode("BBARSTA031"), tm++); statusline(ttemp,1); // Looking up hostname... for (i=0; i < 60 && wait_host!=-1; i++) { wait_host=waitpid(host_pid,&status,WNOHANG); /* update display while waiting */ // XmUpdateDisplay(XtParent(da)); //usleep(500); sched_yield(); } } // Get the return code if (read(fp[0],&rc,sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } if(rc!=0) { close(fp[0]); return rc; } if (read(fp[0], &status, sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } while(status) { *resout = (struct addrinfo*) malloc(sizeof(struct addrinfo)); res = *resout; if (read(fp[0], res, sizeof(struct addrinfo)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } res->ai_addr = (struct sockaddr*) malloc(res->ai_addrlen); if (read(fp[0], res->ai_addr, res->ai_addrlen) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } res->ai_canonname = NULL; resout = &res->ai_next; // See if there is another if (read(fp[0], &status, sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } } *resout = NULL; if (debug_level & 1024) { fprintf(stderr,"Parent closing read end of pipe\n"); } close(fp[0]); // Close the read end of the pipe } } else // We didn't fork { // Close both ends of the pipe to make // sure we've cleaned up properly close(fp[0]); close(fp[1]); } return rc; } void forked_freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next = ai; struct addrinfo *current = ai; while(next) { current = next; next = current->ai_next; free(current->ai_addr); free(current); } } Xastir-Release-2.2.2/src/forked_getaddrinfo.h000066400000000000000000000023441501463444000211310ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_GETAADDRINFO_H #define __XASTIR_GETAADDRINFO_H int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time); void forked_freeaddrinfo(struct addrinfo *ai); #define FAI_TIMEOUT -55 #endif // __XASTIR_GETAADDRINFO_H Xastir-Release-2.2.2/src/geo-client.c000066400000000000000000000027731501463444000173400ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group * * This program uses a "map file" produced by processing TIGER/Line data. * It accepts street addresses on standard input, attempts to resolve them * to a geographical location, and outputs the result. This is pretty much * just for testing. * * The actual work is all done in geo-find.c; this is just a command line * wrapper to its geo_find() function. */ #include "io.h" #include "geo.h" #include int main(int argc,char *argv[]) { struct io_file *index; char input[82]; if (2 != argc) { fprintf(stderr,"usage: %s map-file\n",argv[0]); return 2; } index = io_open(argv[1]); while (fgets(input,sizeof input,stdin)) { struct geo_location loc; if (!geo_find(index,input,strlen(input),&loc)) { printf("FAILURE: %s\n",input); } else { printf("SUCCESS: %d/%s/%s/%s/%d\n", loc.at.address, loc.street_name,loc.city_name,loc.state_name, loc.zip_code); printf(" Side = %c\n",loc.side); printf(" Start = %d @ %.8g, %.8g\n", loc.before.address, loc.before.longitude,loc.before.latitude); printf(" At = %d @ %.8g, %.8g\n", loc.at.address, loc.at.longitude,loc.at.latitude); printf(" End = %d @ %.8g, %.8g\n", loc.after.address, loc.after.longitude,loc.after.latitude); } } return 0; } Xastir-Release-2.2.2/src/geo-find.c000066400000000000000000000316251501463444000170000ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group * * The geo_find() function defined here uses an address map built by * geo-*-to-* to parse an address and convert it to geographical * coordinates. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "geo.h" #include "io.h" #include #include #include #include // Must be last include file #include "leak_detection.h" #define D(x) struct state { struct io_file *index; /* Text input */ int input_depth; const char *input_begin,*input_end; char buffer[100],*buffer_next,*buffer_end; const char *next; /* Working hypothesis */ int address; struct { int begin,end; } range[4]; int range_count; /* Answer */ struct geo_location *out; }; static int is_valid(struct state *s) { int i,pos[sizeof(s->range)/sizeof(*s->range)]; if (0 == s->range_count) { return 0; } for (i = 0; i < s->range_count; ++i) { D(printf(" Metarange #%d: %d entries\n",i,(s->range[i].end - s->range[i].begin) / 8)); pos[i] = s->range[i].begin; } for (;;) { int i_begin = 1,i_end = 1; int best_begin = 1,best_end = 1; char out_side = 'X'; int out_addr = 0,out_lat = 0,out_long = 0; D(printf("Searching ---\n")); for (i = 0; i != i_begin; i = (i + 1) % s->range_count) { int r_begin,r_end; for (;;) { int n; if (pos[i] >= s->range[i].end || pos[i] < 0) { D(printf(" Range #%d @ %d: End\n",i,(pos[i] - s->range[i].begin) / 8)); return 0; } n = io_in_i4(s->index, io_in_i4(s->index,pos[i],&r_begin),&r_end); if (n < 0) { return 0; } D(printf(" Range #%d @ %d: [%d,%d)\n",i,(pos[i] - s->range[i].begin) / 8,r_begin,r_end)); if (r_end > best_begin && r_begin < r_end) { break; } pos[i] = n; } if (r_begin > best_begin) { best_begin = r_begin; best_end = r_end; i_begin = i_end = i; D(printf(" Best -> [%d#%d,%d#%d)\n",best_begin,i_begin,best_end,i_end)); } else if (r_end < best_end) { best_end = r_end; i_end = i; D(printf(" Best -> [%d#%d,%d#%d)\n",best_begin,i_begin,best_end,i_end)); } } D(printf("Address range ---\n")); pos[i_end] += 8; /* hack... */ do { int next,lon,lat,addr; best_begin = io_in_i4(s->index,best_begin,&next); best_begin = io_in_i4(s->index,best_begin,&lon); best_begin = io_in_i4(s->index,best_begin,&lat); best_begin = io_in_i4(s->index,best_begin,&addr); /* PERF: This should be a binary search... */ while (best_begin >= 0 && best_begin < next) { short da; signed char dln,dlt; char side; best_begin = io_in_i2(s->index,best_begin,&da); best_begin = io_in_i1(s->index,best_begin,&dln); best_begin = io_in_i1(s->index,best_begin,&dlt); best_begin = io_in(s->index,best_begin,&side,1); D(printf(" %c: %d vs. %d\n",side,addr + da,s->address / 2)); if (addr + da <= s->address / 2) { out_side = side; out_addr = addr + da; out_lat = lat + dlt; out_long = lon + dln; } else if ('X' == out_side) { best_begin = next; D(printf(" Not this time.\n")); break; } else if (NULL != s->out) { const int parity = s->address % 2; s->out->before.address = 2 * out_addr + parity; s->out->before.latitude = out_lat / 100000.0; s->out->before.longitude = out_long / 100000.0; if ('X' == side) { --da; } s->out->after.address = 2 * (addr + da) + parity; s->out->after.latitude = (lat + dlt) / 100000.0; s->out->after.longitude = (lon + dln) / 100000.0; s->out->at.address = s->address; s->out->at.latitude = (out_lat + (lat + dlt - out_lat) * (s->address / 2 - out_addr) / (addr + da - out_addr)) / 100000.0; s->out->at.longitude = (out_long + (lon + dln - out_long) * (s->address / 2 - out_addr) / (addr + da - out_addr)) / 100000.0; s->out->side = out_side; D(printf(" Success!\n")); return 1; } else { D(printf(" Success...\n")); return 1; } } } while (best_begin > 0 && best_begin < best_end); } } static int find_name( struct io_file *index,int begin,int end, char type,const char *name, unsigned int name_len) { const int size = 45; const int count = (end - begin) / size; const int mid = begin + size * (count / 2); char test[41]; if (count <= 1) { return begin; } if (io_in(index,mid - size,test,sizeof test) < 0) { return -1; } if (name_len > sizeof test - 1) { name_len = sizeof test - 1; } if (type > test[0] || (type == test[0] && strncasecmp(name,test + 1,name_len) > 0)) { return find_name(index,mid,end,type,name,name_len); } else { return find_name(index,begin,mid,type,name,name_len); } } static const char *next_word(struct state *,const char *); static int get_name_at( struct state *s, char type, int (*f)(struct state *), const char *last) { char n[41]; const char *next,*save; unsigned int len = last - s->next; int begin,end,pos; if (io_in_i4(s->index, io_in_i4(s->index, io_in_i4(s->index,0,NULL),&begin),&end) < 0 || (pos = find_name(s->index,begin,end,type,s->next,len)) < 0 || pos == end || (pos = io_in_i4(s->index,io_in(s->index,pos,n,sizeof n),&begin)) < 0 || pos == end || (pos = io_in_i4(s->index,io_in(s->index,pos,NULL,sizeof n),&end)) < 0 || n[0] != type || strncasecmp(n + 1,s->next,len)) { D(printf(" '%c' \"%.*s\" not found\n",type,len,s->next)); return 0; } if ('=' == n[len + 1]) /* alias expansion */ { char * const replace = (s->next - s->buffer) + s->buffer; int delta; begin = len + 2; while (begin < (int)sizeof n && ' ' == n[begin]) { ++begin; } end = sizeof n; while (end > begin && ' ' == n[end - 1]) { --end; } if (end < (int)sizeof n) { ++end; } if (end - begin > (int)len) { end = begin + len; } D(printf(" Replacing '%.*s' with '%.*s'\n",len,n + 1,end - begin,&n[begin])); memcpy(replace,n + begin,end - begin); memmove(replace + (end - begin), replace + len, s->buffer_end - replace - len); delta = len - (end - begin); s->buffer_end -= delta; s->buffer_next -= delta; D(printf(" Buffer is now: '%.*s'\n",s->buffer_end - s->buffer,s->buffer)); return 1; } next = next_word(s,last); if (next != last && get_name_at(s,type,f,next)) { return 1; } pos = len; while (++pos < (int)sizeof n) if (' ' != n[pos]) { return 0; } s->range[s->range_count].begin = begin; s->range[s->range_count].end = end; ++s->range_count; save = s->next; s->next = last; D(printf(">>> '%c' \"%.*s\" found\n",type,len - 1,n + 1)); if (NULL != f && f(s)) { char *out = NULL; switch (type) { case 'E': case 'O': out = s->out ? s->out->street_name : NULL; break; case 'C': out = s->out ? s->out->city_name : NULL; break; case 'S': out = s->out ? s->out->state_name : NULL; break; } if (NULL != out) { // strncpy is dangerous as it can leave a string // unterminated if the destination isn't big enough to // hold the '\0' character. Must terminate the string // manually in all cases, as we do here. strncpy(out,n + 1,len - 1); out[len - 1] = '\0'; } s->next = save; return 1; } D(printf("<<< '%c' \"%.*s\"\n",type,len - 1,n + 1)); --s->range_count; s->next = save; return 0; } static const char *input_word(struct state *s,const char *pos) { assert(pos >= s->buffer && pos <= s->buffer_end); if (pos != s->buffer_end) { while (pos < s->buffer_end && *pos != ' ') { ++pos; } while (pos < s->buffer_end && *pos == ' ') { ++pos; } return pos; } while (s->input_begin != s->input_end && (s->input_depth > 0 || !isalnum((int)*s->input_begin))) { const char ch = *s->input_begin++; if ('(' == ch) { ++s->input_depth; } if (')' == ch && s->input_depth > 0) { --s->input_depth; } } while (s->input_begin != s->input_end && s->buffer_end != &s->buffer[sizeof s->buffer] && isalnum((int)*s->input_begin)) { if (s->buffer == s->buffer_end || !isdigit((int)s->buffer_end[-1]) || !isalpha((int)*s->input_begin)) { *s->buffer_end++ = *s->input_begin; } ++s->input_begin; } if (pos != s->buffer_end && s->buffer_end != &s->buffer[sizeof s->buffer]) { *s->buffer_end++ = ' '; } return s->buffer_end; } static const char *next_word(struct state *s,const char *pos) { const char * const next = input_word(s,pos); const char * const save = s->next; assert(pos >= s->buffer && pos <= s->buffer_next); if (pos != s->buffer_next || next == pos) { return next; } s->next = pos; s->buffer_next = s->buffer + (next - s->buffer); if (get_name_at(s,'A',NULL,s->buffer_next)) { s->buffer_next = s->buffer + (pos - s->buffer); s->next = save; return next_word(s,pos); /* NOTE! make sure aliases do not form a cycle */ } s->next = save; return next; } static int get_name(struct state *s,char type,int (*f)(struct state *)) { const char * const next = next_word(s,s->next); if (s->next == next) { return 0; } return get_name_at(s,type,f,next); } static int get_zip(struct state *s) { const char * const next = next_word(s,s->next); int zip,zip_offset; if (s->next == next) { return 0; } zip = io_strntoi(s->next,next - s->next); if (zip <= 0 || zip >= 100000 || io_in_i4(s->index,0,&zip_offset) < 0) { return 0; } s->range[s->range_count].begin = zip_offset + 4 * zip; s->range[s->range_count].end = zip_offset + 4 * zip + 8; ++s->range_count; D(printf(">>> %d\n",zip)); if (is_valid(s)) { if (NULL != s->out) { s->out->zip_code = zip; } return 1; } D(printf("<<< %d\n",zip)); --s->range_count; return 0; } static int optional_zip(struct state *s) { return get_zip(s) || is_valid(s); } static int get_state(struct state *s) { return get_name(s,'S',optional_zip) || optional_zip(s); } static int get_city(struct state *s) { return get_name(s,'C',get_state) || get_zip(s); } static int skip_stuff(struct state *s) { const char * const begin = s->next; int skipped; for (skipped = 0; skipped < 7; ++skipped) if (get_city(s)) { s->next = begin; return 1; } else { const char * const next = next_word(s,s->next); if (next == s->next) { break; } s->next = next; } s->next = begin; return 0; } static int get_street(struct state *s) { return get_name(s,(s->address % 2) ? 'O' : 'E',skip_stuff); } static int get_address(struct state *s) { const char * const begin = s->next; const char * const next = next_word(s,begin); //fprintf(stderr,"get_address\n"); if (begin == next) { return 0; } s->address = io_strntoi(begin,next - s->next); if (0 == s->address) { return 0; } s->next = next; if (get_street(s)) { s->next = begin; return 1; } s->next = next_word(s,s->next); if (get_street(s)) { s->next = begin; return 1; } s->next = next_word(s,s->next); if (get_street(s)) { s->next = begin; return 1; } s->next = begin; return 0; } int geo_find( struct io_file *index, const char *str, int len, struct geo_location *out) { struct state s; if (NULL == index) { return 0; } s.index = index; s.input_depth = 0; s.input_begin = str; s.input_end = str + len; s.next = s.buffer_end = s.buffer_next = s.buffer; s.address = s.range_count = 0; if (NULL != (s.out = out)) { out->zip_code = 0; out->street_name[0] = '\0'; out->city_name[0] = '\0'; out->state_name[0] = '\0'; } return get_address(&s); } Xastir-Release-2.2.2/src/geo.h000066400000000000000000000026231501463444000160630ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group * * The geo_find() function is the query interface for turning addressees * into geographical locations using an 'address map' built from TIGER/Line * and FIPS-55 data by the geo-*-to-* programs. */ #ifndef GEOCODER_GEO_H #define GEOCODER_GEO_H #include "io.h" extern long destination_coord_lat; extern long destination_coord_lon; extern int mark_destination; extern int show_destination_mark; extern char geocoder_map_filename[400]; struct geo_corner { int address; double latitude,longitude; }; /* Decoded address location. */ struct geo_location { /* "Before" and "after" are the previous and next "control point"; * these are the known locations, "at" is the interpolated point * corresponding to the supplied address. */ struct geo_corner before,after,at; int zip_code; /* 0 if none found in address */ char side; /* 'L' or 'R' */ char street_name[41],city_name[41],state_name[41]; /* Empty if none found in address */ }; /* Arguments: m = Address map file to use * a = Address string to parse * len = Length of address string (in characters) * out = Address of location to output * Returns: Nonzero iff an address was recognized and decoded. */ int geo_find(struct io_file *m,const char *a,int len,struct geo_location *out); #endif Xastir-Release-2.2.2/src/geocoder_gui.c000066400000000000000000000552571501463444000177520ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include "xastir.h" #include "main.h" #include "lang.h" //#include "maps.h" #include "io.h" #include "geo.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget geocoder_place_dialog = (Widget)NULL; Widget geocoder_zip_data = (Widget)NULL; Widget geocoder_state_data = (Widget)NULL; Widget geocoder_locality_data = (Widget)NULL; Widget geocoder_address_data = (Widget)NULL; Widget geocoder_map_file_data = (Widget)NULL; char geocoder_zip_name[50]; char geocoder_state_name[50]; char geocoder_locality_name[255]; char geocoder_address_name[255]; char geocoder_map_filename[400]; static xastir_mutex geocoder_place_dialog_lock; long destination_coord_lat = 0; long destination_coord_lon = 0; int mark_destination = 0; int show_destination_mark = 0; void geocoder_gui_init(void) { init_critical_section( &geocoder_place_dialog_lock ); geocoder_zip_name[0] = '\0'; geocoder_state_name[0] = '\0'; geocoder_locality_name[0] = '\0'; geocoder_address_name[0] = '\0'; } /**** GEOCODER FIND PLACE ******/ void Geocoder_place_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&geocoder_place_dialog_lock, "geocoder_gui.c:Geocoder_place_destroy_shell" ); XtDestroyWidget(shell); geocoder_place_dialog = (Widget)NULL; end_critical_section(&geocoder_place_dialog_lock, "geocoder_gui.c:Geocoder_place_destroy_shell" ); } /* * Geocoder a place by centering the map at its position */ void Geocoder_place_now(Widget w, XtPointer clientData, XtPointer callData) { struct io_file *index; struct geo_location loc; char input[1024]; char *temp_ptr; /* find place and go there */ temp_ptr = XmTextFieldGetString(geocoder_zip_data); xastir_snprintf(geocoder_zip_name, sizeof(geocoder_zip_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(geocoder_state_data); xastir_snprintf(geocoder_state_name, sizeof(geocoder_state_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(geocoder_locality_data); xastir_snprintf(geocoder_locality_name, sizeof(geocoder_locality_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(geocoder_address_data); xastir_snprintf(geocoder_address_name, sizeof(geocoder_address_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(geocoder_map_file_data); xastir_snprintf(geocoder_map_filename, sizeof(geocoder_map_filename), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(geocoder_zip_name); (void)remove_trailing_spaces(geocoder_state_name); (void)remove_trailing_spaces(geocoder_locality_name); (void)remove_trailing_spaces(geocoder_address_name); /* fprintf(stderr,"%s\n%s\n%s\n%s\n%s\n", geocoder_zip_name, geocoder_state_name, geocoder_locality_name, geocoder_address_name, geocoder_map_filename); */ index = io_open(geocoder_map_filename); xastir_snprintf(input, sizeof(input), "%s %s%s%s %s", geocoder_address_name, geocoder_locality_name, (strlen(geocoder_state_name) != 0)?",":"", geocoder_state_name, geocoder_zip_name); if (debug_level & 1) { fprintf(stderr,"Searching for: %s\n", input); } if (geo_find(index,input,strlen(input),&loc)) { long coord_lon, coord_lat; char lat_str[20]; char long_str[20]; int lon, lat, lons, lats, tmp1; char lond = 'E'; char latd = 'N'; double res, tmp; if (loc.at.longitude < 0) { loc.at.longitude = -loc.at.longitude; lond = 'W'; } if (loc.at.latitude < 0) { loc.at.latitude = -loc.at.latitude; latd = 'S'; } lon = loc.at.longitude; lat = loc.at.latitude; res = loc.at.longitude - lon; tmp = (res * 100); tmp = tmp * 60 / 100; tmp1 = tmp; lon = (lon * 100) + tmp1; lons = (tmp - tmp1) * 100; res = loc.at.latitude - lat; tmp = (res * 100); tmp = tmp * 60 / 100; tmp1 = tmp; lat = (lat * 100) + tmp1; lats = (tmp - tmp1) * 100; xastir_snprintf(lat_str, sizeof(lat_str), "%d.%02d%c", lat, lats, latd); coord_lat = convert_lat_s2l(lat_str); xastir_snprintf(long_str, sizeof(long_str), "%s%d.%02d%c", (lon < 10000)?"0":"", lon, lons, lond); coord_lon = convert_lon_s2l(long_str); destination_coord_lat = coord_lat; destination_coord_lon = coord_lon; mark_destination = 1; popup_message_always( langcode("POPEM00029"), geocoder_address_name ); set_map_position(w, coord_lat, coord_lon); } else { popup_message_always(langcode("POPEM00025"),geocoder_address_name); } Geocoder_place_destroy_shell(w, clientData, callData); } void Show_dest_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { show_destination_mark = atoi(which); } else { show_destination_mark = 0; } } void Geocoder_place(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_cancel, sep, zip, state, locality, address, map_file, show_dest_toggle; Atom delw; if (!geocoder_place_dialog) { begin_critical_section(&geocoder_place_dialog_lock, "geocoder_gui.c:Geocoder_place" ); // Find Address geocoder_place_dialog = XtVaCreatePopupShell(langcode("PULDNMP029"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Geocoder_place pane",xmPanedWindowWidgetClass, geocoder_place_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("Geocoder_place scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Geocoder_place form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Address: address = XtVaCreateManagedWidget(langcode("FEATURE007"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); geocoder_address_data = XtVaCreateManagedWidget("Geocoder_address_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 254, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, address, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // City: locality = XtVaCreateManagedWidget(langcode("FEATURE008"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, address, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); geocoder_locality_data = XtVaCreateManagedWidget("Geocoder_address_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 254, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, address, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, locality, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // State/Province: state = XtVaCreateManagedWidget(langcode("FEATURE002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locality, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); geocoder_state_data = XtVaCreateManagedWidget("Geocoder_state_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((4*7)+2), XmNmaxLength, 2, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, locality, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, state, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Mark Destination show_dest_toggle = XtVaCreateManagedWidget(langcode("FEATURE009"),xmToggleButtonGadgetClass, form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locality, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, geocoder_state_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(show_dest_toggle,XmNvalueChangedCallback,Show_dest_toggle,"1"); if (show_destination_mark) { XmToggleButtonSetState(show_dest_toggle,TRUE,FALSE); } // Zip Code: zip = XtVaCreateManagedWidget(langcode("FEATURE010"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); geocoder_zip_data = XtVaCreateManagedWidget("Geocoder_zip_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+2), XmNmaxLength, 10, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zip, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Geocoding File: map_file = XtVaCreateManagedWidget(langcode("FEATURE011"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zip, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); geocoder_map_file_data = XtVaCreateManagedWidget("geocoder_map_file_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 254, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, zip, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, map_file, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Geocoder_place sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,geocoder_map_file_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPLSP005"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Geocoder_place_now, geocoder_place_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Geocoder_place_destroy_shell, geocoder_place_dialog); XmTextFieldSetString(geocoder_zip_data,geocoder_zip_name); XmTextFieldSetString(geocoder_state_data,geocoder_state_name); XmTextFieldSetString(geocoder_locality_data,geocoder_locality_name); XmTextFieldSetString(geocoder_address_data,geocoder_address_name); XmTextFieldSetString(geocoder_map_file_data,geocoder_map_filename); pos_dialog(geocoder_place_dialog); delw = XmInternAtom(XtDisplay(geocoder_place_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(geocoder_place_dialog, delw, Geocoder_place_destroy_shell, (XtPointer)geocoder_place_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, geocoder_place_dialog); end_critical_section(&geocoder_place_dialog_lock, "geocoder_gui.c:Geocoder_place" ); XtPopup(geocoder_place_dialog,XtGrabNone); XmProcessTraversal(button_ok, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(geocoder_place_dialog), XtWindow(geocoder_place_dialog)); } } Xastir-Release-2.2.2/src/gps.c000066400000000000000000000561661501463444000161100ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include "gps.h" #include "main.h" #include "interface.h" #include "lang.h" #include "util.h" // Must be last include file #include "leak_detection.h" char gps_gprmc[MAX_GPS_STRING+1]; char gps_gpgga[MAX_GPS_STRING+1]; char gps_sats[4] = ""; char gps_alt[8] = ""; char gps_spd[10] = ""; char gps_sunit[2] = ""; char gps_cse[10] = ""; int gps_valid = 0; // 0=invalid, 1=valid, 2=2D Fix, 3=3D Fix int gps_stop_now; // This function is destructive to its first parameter // // GPRMC,UTC-Time,status(A/V),lat,N/S,lon,E/W,SOG,COG,UTC-Date,Mag-Var,E/W[*CHK] // GPRMC,hhmmss[.sss],{A|V},ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},[dd]d.d[ddddd],[dd]d.d[d],ddmmyy,[ddd.d],[{E|W}][,A|D|E|N|S][*CHK] // // The last field before the checksum is entirely optional, and in // fact first appeared in NMEA 2.3 (fairly recently). Most GPS's do // not currently put out that field. The field may be null or // nonexistent including the comma. Only "A" or "D" are considered // to be active and reliable fixes if this field is present. // Fix-Quality: // A: Autonomous // D: Differential // E: Estimated // N: Not Valid // S: Simulator // // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 // $GPRMC,104748.821,A,4301.1492,N,08803.0374,W,0.085048,102.36,010605,,*1A // $GPRMC,104749.821,A,4301.1492,N,08803.0377,W,0.054215,74.60,010605,,*2D // int decode_gps_rmc( char *data, char *long_pos, int long_pos_length, char *lat_pos, int lat_pos_length, char *spd, char *unit, int unit_length, char *cse, time_t *stim, int *status) { char *temp_ptr; char *temp_ptr2; char temp_data[MAX_LINE_SIZE+1]; // Big in case we get concatenated packets (it happens!) char sampletime[7]; // We ignore fractional seconds char long_pos_x[11]; char long_ew; char lat_pos_y[10]; char lat_ns; char speed[10]; char speed_unit; char course[8]; char sampledate[7]; #ifdef HAVE_STRPTIME char sampledatime[15]; char *tzp; char tzn[512]; struct tm stm; #endif // HAVE_STRPTIME // We should check for a minimum line length before parsing, // and check for end of input while tokenizing. if ( (data == NULL) || (strlen(data) < 37) ) { return(0); // Not enough data to parse position from. } if (!(isRMC(data))) // No GxRMC found { return(0); } if(strchr(data,',') == NULL) // No comma found { return(0); } (void)strtok(data,","); // get GxRMC and skip it temp_ptr=strtok(NULL,","); // get time if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(sampletime, sizeof(sampletime), "%s", temp_ptr); temp_ptr=strtok(NULL,","); // get fix status if (temp_ptr == NULL) // No comma found { return(0); } if (temp_ptr[0] == 'A') { *status = 1; } else { *status = 0; } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[2] = '\0'; if (temp_data[0] != 'A') // V is a warning but we can get good data still ? { return(0); // Didn't find 'A' in the proper spot } temp_ptr=strtok(NULL,","); // get latitude if (temp_ptr == NULL) { return(0); // Doesn't look like latitude } // Newer GPS'es appear not to zero-fill on the left. Check for // the decimal point in all the possible places. if (temp_ptr[1] != '.' && temp_ptr[2] != '.' && temp_ptr[3] != '.' && temp_ptr[4] != '.') { return(0); // Doesn't look like latitude } // Note: Starlink Invicta shows "lllll.ll" format for latitude in // the GPRMC sentence, which would mean we'd need another term in // the above, and would need to terminate at [10] below (making sure // we extended the field another char as well to handle it). I'm // hoping it was a typo in the Starlink Invicta spec, as latitude // never requires three digits for degrees. xastir_snprintf(lat_pos_y, sizeof(lat_pos_y), "%s", temp_ptr); lat_pos_y[9] = '\0'; // Note that some GPS's put out latitude with extra precision, such as 4801.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(lat_pos_y, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr=strtok(NULL,","); // get N-S if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; lat_ns=toupper((int)temp_data[0]); if(lat_ns != 'N' && lat_ns != 'S') { return(0); // Doesn't look like latitude } temp_ptr=strtok(NULL,","); // get long if (temp_ptr == NULL) { return(0); // Doesn't look like longitude } // Newer GPS'es appear not to zero-fill on the left. Check for // the decimal point in all the possible places. if (temp_ptr[1] != '.' && temp_ptr[2] != '.' && temp_ptr[3] != '.' && temp_ptr[4] != '.' && temp_ptr[5] != '.') { return(0); // Doesn't look like longitude } xastir_snprintf(long_pos_x, sizeof(long_pos_x), "%s", temp_ptr); long_pos_x[10] = '\0'; // Note that some GPS's put out longitude with extra precision, such as 12201.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(long_pos_x, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr=strtok(NULL,","); // get E-W if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; long_ew=toupper((int)temp_data[0]); if (long_ew != 'E' && long_ew != 'W') { return(0); // Doesn't look like longitude } temp_ptr=strtok(NULL,","); // Get speed if (temp_ptr == 0) // No comma found { return(0); } xastir_snprintf(speed, sizeof(speed), "%s", temp_ptr); speed[9] = '\0'; speed_unit='K'; temp_ptr=strtok(NULL,","); // Get course if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(course, sizeof(course), "%s", temp_ptr); course[7] = '\0'; temp_ptr=strtok(NULL,","); // get date of fix if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(sampledate, sizeof(sampledate), "%s", temp_ptr); sampledate[6] = '\0'; // Data is good xastir_snprintf(long_pos, long_pos_length, "%s%c", long_pos_x,long_ew); xastir_snprintf(lat_pos, lat_pos_length, "%s%c", lat_pos_y, lat_ns); xastir_snprintf(spd, 10, "%s", speed); xastir_snprintf(unit, unit_length, "%c", speed_unit); xastir_snprintf(cse, 10, "%s", course); #ifdef HAVE_STRPTIME // Translate date/time into time_t GPS time is in UTC. First, // save existing TZ Then set conversion to UTC, then set back to // existing TZ. tzp=getenv("TZ"); if ( tzp == NULL ) { tzp = ""; } xastir_snprintf(tzn, sizeof(tzn), "TZ=%s", tzp); putenv("TZ=UTC"); tzset(); xastir_snprintf(sampledatime, sizeof(sampledatime), "%s%s", sampledate, sampletime); (void)strptime(sampledatime, "%d%m%y%H%M%S", &stm); *stim=mktime(&stm); putenv(tzn); tzset(); #endif // HAVE_STRPTIME //fprintf(stderr,"Speed %s\n",spd); return(1); } // This function is destructive to its first parameter // // GPGGA,UTC-Time,lat,N/S,long,E/W,GPS-Quality,nsat,HDOP,MSL-Meters,M,Geoidal-Meters,M,DGPS-Data-Age(seconds),DGPS-Ref-Station-ID[*CHK] // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // // GPS-Quality: // 0: Invalid Fix // 1: GPS Fix // 2: DGPS Fix // 3: PPS Fix // 4: RTK Fix // 5: Float RTK Fix // 6: Estimated (dead-reckoning) Fix // 7: Manual Input Mode // 8: Simulation Mode // // $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75 // $GPGGA,104438.833,4301.1439,N,08803.0338,W,1,05,1.8,185.8,M,-34.2,M,0.0,0000*40 // NOTE: while the above specifically refers to $GP strings for the GPS // receivers, there are others such as GNSS, GLONASS, Beidou, and Gallileo // that differ only in the third character. We support those, too. // int decode_gps_gga( char *data, char *long_pos, int long_pos_length, char *lat_pos, int lat_pos_length, char *sats, char *alt, char *aunit, int *status ) { char *temp_ptr; char *temp_ptr2; char temp_data[MAX_LINE_SIZE+1]; // Big in case we get concatenated packets (it happens!) char long_pos_x[11]; char long_ew; char lat_pos_y[10]; char lat_ns; char sats_visible[4]; char altitude[8]; char alt_unit; // We should check for a minimum line length before parsing, // and check for end of input while tokenizing. if ( (data == NULL) || (strlen(data) < 35) ) // Not enough data to parse position from. { return(0); } if (!(isGGA(data))) { return(0); } if (strchr(data,',') == NULL) { return(0); } if (strtok(data,",") == NULL) // get GPGGA and skip it { return(0); } if(strtok(NULL,",") == NULL) // get time and skip it { return(0); } temp_ptr = strtok(NULL,","); // get latitude if (temp_ptr == NULL) { return(0); } xastir_snprintf(lat_pos_y, sizeof(lat_pos_y), "%s", temp_ptr); lat_pos_y[9] = '\0'; // Note that some GPS's put out latitude with extra precision, such as 4801.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(lat_pos_y, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr = strtok(NULL,","); // get N-S if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; lat_ns=toupper((int)temp_data[0]); if(lat_ns != 'N' && lat_ns != 'S') { return(0); } temp_ptr = strtok(NULL,","); // get long if(temp_ptr == NULL) { return(0); } xastir_snprintf(long_pos_x, sizeof(long_pos_x), "%s", temp_ptr); long_pos_x[10] = '\0'; // Note that some GPS's put out longitude with extra precision, such as 12201.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(long_pos_x, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr = strtok(NULL,","); // get E-W if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; long_ew=toupper((int)temp_data[0]); if (long_ew != 'E' && long_ew != 'W') { return(0); } temp_ptr = strtok(NULL,","); // get FIX Quality if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; // '0' = bad fix, positive numbers = ok if(temp_data[0] == '0') { return(0); } // Save the fix quality in "status" *status = atoi(temp_data); temp_ptr=strtok(NULL,","); // Get sats vis if (temp_ptr == NULL) { return(0); } xastir_snprintf(sats_visible, sizeof(sats_visible), "%s", temp_ptr); sats_visible[2] = '\0'; temp_ptr=strtok(NULL,","); // get hoz dil if (temp_ptr == NULL) { return(0); } temp_ptr=strtok(NULL,","); // Get altitude if (temp_ptr == NULL) { return(0); } // Get altitude xastir_snprintf(altitude, sizeof(altitude), "%s", temp_ptr); altitude[7] = '\0'; temp_ptr=strtok(NULL,","); // get UNIT if (temp_ptr == NULL) { return(0); } // get UNIT xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; alt_unit=temp_data[0]; // Data is good xastir_snprintf(long_pos, long_pos_length, "%s%c", long_pos_x, long_ew); xastir_snprintf(lat_pos, lat_pos_length, "%s%c", lat_pos_y, lat_ns); xastir_snprintf(sats, 4, "%s", sats_visible); xastir_snprintf(alt, 8, "%s", altitude); xastir_snprintf(aunit, 2, "%c", alt_unit); return(1); } // // Note that the length of "gps_line_data" can be up to // MAX_DEVICE_BUFFER, which is currently set to 4096. // int gps_data_find(char *gps_line_data, int port) { char long_pos[20],lat_pos[20],aunit[2]; time_t t; char temp_str[MAX_GPS_STRING+1]; int have_valid_string = 0; #ifndef __CYGWIN__ struct timeval tv; struct timezone tz; #endif // __CYGWIN__ if (isRMC(gps_line_data)) { if (debug_level & 128) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", gps_line_data); makePrintable(filtered_data); fprintf(stderr,"Got RMC %s\n", filtered_data); } if (debug_level & 128) { // Got GPS RMC String statusline(langcode("BBARSTA015"),0); } xastir_snprintf(gps_gprmc, sizeof(gps_gprmc), "%s", gps_line_data); xastir_snprintf(temp_str, sizeof(temp_str), "%s", gps_gprmc); // decode_gps_rmc is destructive to its first parameter if (decode_gps_rmc( temp_str, long_pos, sizeof(long_pos), lat_pos, sizeof(lat_pos), gps_spd, gps_sunit, sizeof(gps_sunit), gps_cse, &t, &gps_valid ) == 1) // mod station data { // got GPS data have_valid_string++; if (debug_level & 128) fprintf(stderr,"RMC <%s> <%s><%s> %c <%s>\n", long_pos,lat_pos,gps_spd,gps_sunit[0],gps_cse); if (debug_level & 128) { fprintf(stderr,"Checking for Time Set on %d (%d)\n", port, devices[port].set_time); } // Don't set the time if it's a Cygwin system. Causes problems with // date, plus time can be an hour off if daylight savings time is // enabled on Windows. // #ifndef __CYGWIN__ if (devices[port].set_time) { tv.tv_sec=t; tv.tv_usec=0; tz.tz_minuteswest=0; tz.tz_dsttime=0; if (debug_level & 128) { fprintf(stderr,"Setting Time %ld EUID: %d, RUID: %d\n", (long)t, (int)getuid(), (int)getuid()); } #ifdef HAVE_SETTIMEOFDAY ENABLE_SETUID_PRIVILEGE; settimeofday(&tv, &tz); DISABLE_SETUID_PRIVILEGE; #endif // HAVE_SETTIMEOFDAY } #endif // __CYGWIN__ } } else { if (debug_level & 128) { int i; fprintf(stderr,"Not $GxRMC: "); for (i = 0; i<7; i++) { fprintf(stderr,"%c", gps_line_data[i]); } fprintf(stderr,"\n"); } } if (isGGA(gps_line_data)) { if (debug_level & 128) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", gps_line_data); makePrintable(filtered_data); fprintf(stderr,"Got GGA %s\n", filtered_data); } if (debug_level & 128) { // Got GPS GGA String statusline(langcode("BBARSTA016"),0); } xastir_snprintf(gps_gpgga, sizeof(gps_gpgga), "%s", gps_line_data); xastir_snprintf(temp_str, sizeof(temp_str), "%s", gps_gpgga); // decode_gps_gga is destructive to its first parameter if ( decode_gps_gga( temp_str, long_pos, sizeof(long_pos), lat_pos, sizeof(lat_pos), gps_sats, gps_alt, aunit, &gps_valid ) == 1) // mod station data { // got GPS data have_valid_string++; if (debug_level & 128) fprintf(stderr,"GGA <%s> <%s> <%s> <%s> %c\n", long_pos,lat_pos,gps_sats,gps_alt,aunit[0]); } } else { if (debug_level & 128) { int i; fprintf(stderr,"Not $GPGGA: "); for (i = 0; i<7; i++) { fprintf(stderr,"%c",gps_line_data[i]); } fprintf(stderr,"\n"); } } if (have_valid_string) { if (debug_level & 128) { statusline(langcode("BBARSTA037"),0); } // Go update my screen position my_station_gps_change(long_pos,lat_pos,gps_cse,gps_spd, gps_sunit[0],gps_alt,gps_sats); // gps_stop_now is how we tell main.c that we've got a valid GPS string. // Only useful for HSP mode? if (!gps_stop_now) { gps_stop_now=1; } // If HSP port, shutdown gps for timed interval if (port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { // return dtr to normal port_dtr(port,0); } } return(have_valid_string); } static char checksum[3]; // Function to compute checksums for NMEA sentences // // Input: "$............*" // Output: Two character string containing the checksum // // Checksum is computed from the '$' to the '*', but not including // these two characters. It is an 8-bit Xor of the characters // specified, encoded in hexadecimal format. // char *nmea_checksum(char *nmea_sentence) { int i; int sum = 0; int right; int left; char convert[17] = "0123456789ABCDEF"; for (i = 1; i < ((int)strlen(nmea_sentence) - 1); i++) { sum = sum ^ nmea_sentence[i]; } right = sum % 16; left = (sum / 16) % 16; xastir_snprintf(checksum, sizeof(checksum), "%c%c", convert[left], convert[right]); return(checksum); } // Function which will send an NMEA sentence to a Garmin GPS which // will create a waypoint if the Garmin is set to NMEA-in/NMEA-out // mode. The sentence looks like this: // // $GPWPL,4807.038,N,01131.000,E,WPTNME*31 // // $GPWPL,4849.65,N,06428.53,W,0001*54 // $GPWPL,4849.70,N,06428.50,W,0002*50 // // 4807.038,N Latitude // 01131.000,E Longitude // WPTNME Waypoint Name (stick to 6 chars for compatibility?) // *31 Checksum, always begins with '*' // // // Future implementation ideas: // // Create linked list of waypoints/location. // Use the list to prevent multiple writes of the same waypoint if // nothing has changed. // // Use the list to check distance of previously-written waypoints. // If we're out of range, delete the waypoint and remove it from the // list. // // Perhaps write the list to disk also. As we shut down, delete the // waypoints (self-cleaning). As we come up, load them in again? // We could also just continue cleaning out waypoints that are // out-of-range since the last time we ran the program. That's // probably a better solution. // void create_garmin_waypoint(long latitude,long longitude,char *call_sign) { char short_callsign[10]; char lat_string[15]; char long_string[15]; char lat_char; char long_char; int i,j,len; char out_string[80]; char out_string2[80]; convert_lat_l2s(latitude, lat_string, sizeof(lat_string), CONVERT_HP_NOSP); lat_char = lat_string[strlen(lat_string) - 1]; lat_string[strlen(lat_string) - 1] = '\0'; convert_lon_l2s(longitude, long_string, sizeof(long_string), CONVERT_HP_NOSP); long_char = long_string[strlen(long_string) - 1]; long_string[strlen(long_string) - 1] = '\0'; len = strlen(call_sign); if (len > 9) { len = 9; } j = 0; for (i = 0; i <= len; i++) // Copy the '\0' as well { if (call_sign[i] != '-') // We don't want the dash { short_callsign[j++] = call_sign[i]; } } short_callsign[6] = '\0'; // Truncate at 6 chars // Convert to upper case. Garmin's don't seem to like lower // case waypoint names to_upper(short_callsign); //fprintf(stderr,"Creating waypoint for %s:%s\n",call_sign,short_callsign); xastir_snprintf(out_string, sizeof(out_string), "$GPWPL,%s,%c,%s,%c,%s*", lat_string, lat_char, long_string, long_char, short_callsign); nmea_checksum(out_string); strncpy(out_string2, out_string, sizeof(out_string2)); out_string2[sizeof(out_string2)-1] = '\0'; // Terminate string strcat(out_string2, checksum); output_waypoint_data(out_string2); //fprintf(stderr,"%s\n",out_string2); } // Test if this is a GGA string, irrespective of what talker produced // it. This should allow us to support GPS, GLONASS, Gallileo, // Beidou, or GNSS receivers, and multi-constellation receivers ($GP, // $GN, etc.), but also other talkers like Integrated Instrumentation // ($II). int isGGA(char *gps_line_data) { int retval; retval = (strncmp(gps_line_data,"$",1)==0); retval = retval && ((strlen(gps_line_data)>7) && strncmp(&(gps_line_data[3]),"GGA,",4)==0); return (retval); } // Test if this is an RMC string. See comments for isGGA. int isRMC(char *gps_line_data) { int retval; retval = (strncmp(gps_line_data,"$",1)==0); retval = retval && ((strlen(gps_line_data)>7) && strncmp(&(gps_line_data[3]),"RMC,",4)==0); return (retval); } Xastir-Release-2.2.2/src/gps.h000066400000000000000000000025051501463444000161010ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_GPS_H #define __XASTIR_GPS_H #include "xastir.h" #define MAX_GPS_STRING 300 extern char gps_sats[4]; extern int gps_valid; extern int gps_stop_now; extern int gps_data_find(char *gps_line_data, int port); extern void create_garmin_waypoint(long latitude,long longitude,char *call_sign); int isGGA(char *gps_line_data); int isRMC(char *gps_line_data); #endif // __XASTIR_GPS_H Xastir-Release-2.2.2/src/hashtable.c000066400000000000000000000202041501463444000172320ustar00rootroot00000000000000 /* Copyright (C) 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "hashtable.h" #include "hashtable_private.h" // Must be last include file #include "leak_detection.h" /* defines GC_MALLOC/GC_FREE */ /* Credit for primes table: Aaron Krowne http://br.endernet.org/~akrowne/ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html */ static const unsigned int primes[] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); const float max_load_factor = 0.65; /*****************************************************************************/ struct hashtable * create_hashtable(unsigned int minsize, unsigned int (*hashf) (void*), int (*eqf) (void*,void*)) { struct hashtable *h; unsigned int pindex, size = primes[0]; /* Check requested hashtable isn't too large */ if (minsize > (1u << 30)) { return NULL; } /* Enforce size as prime */ for (pindex=0; pindex < prime_table_length; pindex++) { if (primes[pindex] > minsize) { size = primes[pindex]; break; } } h = (struct hashtable *)malloc(sizeof(struct hashtable)); if (NULL == h) { return NULL; /*oom*/ } h->table = (struct entry **)malloc(sizeof(struct entry*) * size); if (NULL == h->table) { free(h); /*oom*/ return NULL; } memset(h->table, 0, size * sizeof(struct entry *)); h->tablelength = size; h->primeindex = pindex; h->entrycount = 0; h->hashfn = hashf; h->eqfn = eqf; h->loadlimit = ceil(size * max_load_factor); return h; } /*****************************************************************************/ unsigned int hash(struct hashtable *h, void *k) { /* Aim to protect against poor hash functions by adding logic here * - logic taken from java 1.4 hashtable source */ unsigned int i = h->hashfn(k); i += ~(i << 9); i ^= ((i >> 14) | (i << 18)); /* >>> */ i += (i << 4); i ^= ((i >> 10) | (i << 22)); /* >>> */ return i; } /*****************************************************************************/ static int hashtable_expand(struct hashtable *h) { /* Double the size of the table to accommodate more entries */ struct entry **newtable; struct entry *e; struct entry **pE; unsigned int newsize, i, index; /* Check we're not hitting max capacity */ if (h->primeindex == (prime_table_length - 1)) { return 0; } newsize = primes[++(h->primeindex)]; newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); if (NULL != newtable) { memset(newtable, 0, newsize * sizeof(struct entry *)); /* This algorithm is not 'stable'. ie. it reverses the list * when it transfers entries between the tables */ for (i = 0; i < h->tablelength; i++) { while (NULL != (e = h->table[i])) { h->table[i] = e->next; index = indexFor(newsize,e->h); e->next = newtable[index]; newtable[index] = e; } } free(h->table); h->table = newtable; } /* Plan B: realloc instead */ else { newtable = (struct entry **) realloc(h->table, newsize * sizeof(struct entry *)); if (NULL == newtable) { (h->primeindex)--; return 0; } h->table = newtable; memset(newtable[h->tablelength], 0, newsize - h->tablelength); for (i = 0; i < h->tablelength; i++) { for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { index = indexFor(newsize,e->h); if (index == i) { pE = &(e->next); } else { *pE = e->next; e->next = newtable[index]; newtable[index] = e; } } } } h->tablelength = newsize; h->loadlimit = ceil(newsize * max_load_factor); return -1; } /*****************************************************************************/ unsigned int hashtable_count(struct hashtable *h) { return h->entrycount; } /*****************************************************************************/ int hashtable_insert(struct hashtable *h, void *k, void *v) { /* This method allows duplicate keys - but they shouldn't be used */ unsigned int index; struct entry *e; if (++(h->entrycount) > h->loadlimit) { /* Ignore the return value. If expand fails, we should * still try cramming just this value into the existing table * -- we may not have memory for a larger table, but one more * element may be ok. Next time we insert, we'll try expanding again.*/ hashtable_expand(h); } e = (struct entry *)malloc(sizeof(struct entry)); if (NULL == e) { --(h->entrycount); /*oom*/ return 0; } e->h = hash(h,k); index = indexFor(h->tablelength,e->h); e->k = k; e->v = v; e->next = h->table[index]; h->table[index] = e; return -1; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_search(struct hashtable *h, void *k) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { return e->v; } e = e->next; } return NULL; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_remove(struct hashtable *h, void *k) { /* TODO: consider compacting the table when the load factor drops enough, * or provide a 'compact' method. */ struct entry *e; struct entry **pE; void *v; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hash(h,k)); pE = &(h->table[index]); e = *pE; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { *pE = e->next; h->entrycount--; v = e->v; freekey(e->k); free(e); return v; } pE = &(e->next); e = e->next; } return NULL; } /*****************************************************************************/ /* destroy */ void hashtable_destroy(struct hashtable *h, int free_values) { unsigned int i; struct entry *e, *f; struct entry **table = h->table; if (free_values) { for (i = 0; i < h->tablelength; i++) { e = table[i]; while (NULL != e) { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } } } else { for (i = 0; i < h->tablelength; i++) { e = table[i]; while (NULL != e) { f = e; e = e->next; freekey(f->k); free(f); } } } free(h->table); free(h); } /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.2/src/hashtable.h000066400000000000000000000153071501463444000172470ustar00rootroot00000000000000 /* Copyright (C) 2002 Christopher Clark */ // Portions Copyright (C) 2000-2023 The Xastir Group #ifndef __HASHTABLE_CWC22_H__ #define __HASHTABLE_CWC22_H__ struct hashtable; /* Example of use: * * struct hashtable *h; * struct some_key *k; * struct some_value *v; * * static unsigned int hash_from_key_fn( void *k ); * static int keys_equal_fn ( void *key1, void *key2 ); * * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); * k = (struct some_key *) malloc(sizeof(struct some_key)); * v = (struct some_value *) malloc(sizeof(struct some_value)); * * (initialise k and v to suitable values) * * if (! hashtable_insert(h,k,v) ) * { exit(-1); } * * if (NULL == (found = hashtable_search(h,k) )) * { printf("not found!"); } * * if (NULL == (found = hashtable_remove(h,k) )) * { printf("Not found\n"); } * */ /* Macros may be used to define type-safe(r) hashtable access functions, with * methods specialized to take known key and value types as parameters. * * Example: * * Insert this at the start of your file: * * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); * * This defines the functions 'insert_some', 'search_some' and 'remove_some'. * These operate just like hashtable_insert etc., with the same parameters, * but their function signatures have 'struct some_key *' rather than * 'void *', and hence can generate compile time errors if your program is * supplying incorrect data as a key (and similarly for value). * * Note that the hash and key equality functions passed to create_hashtable * still take 'void *' parameters instead of 'some key *'. This shouldn't be * a difficult issue as they're only defined and passed once, and the other * functions will ensure that only valid keys are supplied to them. * * The cost for this checking is increased code size and runtime overhead * - if performance is important, it may be worth switching back to the * unsafe methods once your program has been debugged with the safe methods. * This just requires switching to some simple alternative defines - eg: * #define insert_some hashtable_insert * */ /***************************************************************************** * create_hashtable * @name create_hashtable * @param minsize minimum initial size of hashtable * @param hashfunction function for hashing keys * @param key_eq_fn function for determining key equality * @return newly created hashtable or NULL on failure */ struct hashtable * create_hashtable(unsigned int minsize, unsigned int (*hashfunction) (void*), int (*key_eq_fn) (void*,void*)); /***************************************************************************** * hashtable_insert * @name hashtable_insert * @param h the hashtable to insert into * @param k the key - hashtable claims ownership and will free on removal * @param v the value - does not claim ownership * @return non-zero for successful insertion * * This function will cause the table to expand if the insertion would take * the ratio of entries to table size over the maximum load factor. * * This function does not check for repeated insertions with a duplicate key. * The value returned when using a duplicate key is undefined -- when * the hashtable changes size, the order of retrieval of duplicate key * entries is reversed. * If in doubt, remove before insert. */ int hashtable_insert(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_insert(h,k,v); \ } /***************************************************************************** * hashtable_search * @name hashtable_search * @param h the hashtable to search * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * hashtable_search(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_search(h,k)); \ } /***************************************************************************** * hashtable_remove * @name hashtable_remove * @param h the hashtable to remove the item from * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * /* returns value */ hashtable_remove(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_remove(h,k)); \ } /***************************************************************************** * hashtable_count * @name hashtable_count * @param h the hashtable * @return the number of items stored in the hashtable */ unsigned int hashtable_count(struct hashtable *h); /***************************************************************************** * hashtable_destroy * @name hashtable_destroy * @param h the hashtable * @param free_values whether to call 'free' on the remaining values */ void hashtable_destroy(struct hashtable *h, int free_values); #endif /* __HASHTABLE_CWC22_H__ */ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.2/src/hashtable_itr.c000066400000000000000000000125421501463444000201160ustar00rootroot00000000000000 /* Copyright (C) 2002, 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include /* defines NULL */ #include //#include //#include #include "hashtable.h" #include "hashtable_private.h" #include "hashtable_itr.h" // Must be last include file #include "leak_detection.h" /* defines GC_MALLOC/GC_FREE */ /*****************************************************************************/ /* hashtable_iterator - iterator constructor */ struct hashtable_itr * hashtable_iterator(struct hashtable *h) { unsigned int i, tablelength; struct hashtable_itr *itr = (struct hashtable_itr *) malloc(sizeof(struct hashtable_itr)); if (NULL == itr) { return NULL; } itr->h = h; itr->e = NULL; itr->parent = NULL; tablelength = h->tablelength; itr->index = tablelength; if (0 == h->entrycount) { return itr; } for (i = 0; i < tablelength; i++) { if (NULL != h->table[i]) { itr->e = h->table[i]; itr->index = i; break; } } return itr; } /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i) { if (!i) { return NULL; } if (i->e) { return i->e->k; } else { return NULL; } } void * hashtable_iterator_value(struct hashtable_itr *i) { if (!i) { return NULL; } if (i->e) { return i->e->v; } else { return NULL; } } /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr) { unsigned int j,tablelength; struct entry **table; struct entry *next; if (NULL == itr->e) { return 0; /* stupidity check */ } next = itr->e->next; if (NULL != next) { itr->parent = itr->e; itr->e = next; return -1; } tablelength = itr->h->tablelength; itr->parent = NULL; if (tablelength <= (j = ++(itr->index))) { itr->e = NULL; return 0; } table = itr->h->table; while (NULL == (next = table[j])) { if (++j >= tablelength) { itr->index = tablelength; itr->e = NULL; return 0; } } itr->index = j; itr->e = next; return -1; } /*****************************************************************************/ /* remove - remove the entry at the current iterator position * and advance the iterator, if there is a successive * element. * If you want the value, read it before you remove: * beware memory leaks if you don't. * Returns zero if end of iteration. */ int hashtable_iterator_remove(struct hashtable_itr *itr) { struct entry *remember_e, *remember_parent; int ret; /* Do the removal */ if (NULL == (itr->parent)) { /* element is head of a chain */ itr->h->table[itr->index] = itr->e->next; } else { /* element is mid-chain */ itr->parent->next = itr->e->next; } /* itr->e is now outside the hashtable */ remember_e = itr->e; itr->h->entrycount--; freekey(remember_e->k); /* Advance the iterator, correcting the parent */ remember_parent = itr->parent; ret = hashtable_iterator_advance(itr); if (itr->parent == remember_e) { itr->parent = remember_parent; } free(remember_e); return ret; } /*****************************************************************************/ int /* returns zero if not found */ hashtable_iterator_search(struct hashtable_itr *itr, struct hashtable *h, void *k) { struct entry *e, *parent; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; parent = NULL; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { itr->index = index; itr->e = e; itr->parent = parent; itr->h = h; return -1; } parent = e; e = e->next; } return 0; } /* * Copyright (C) 2002, 2004 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.2/src/hashtable_itr.h000066400000000000000000000106551501463444000201260ustar00rootroot00000000000000 /* Copyright (C) 2002, 2004 Christopher Clark */ // Portions Copyright (C) 2000-2023 The Xastir Group #ifndef __HASHTABLE_ITR_CWC22__ #define __HASHTABLE_ITR_CWC22__ #include "hashtable.h" #include "hashtable_private.h" /* needed to enable inlining */ /*****************************************************************************/ /* This struct is only concrete here to allow the inlining of two of the * accessor functions. */ struct hashtable_itr { struct hashtable *h; struct entry *e; struct entry *parent; unsigned int index; }; /*****************************************************************************/ /* hashtable_iterator */ struct hashtable_itr * hashtable_iterator(struct hashtable *h); #if 0 // BZZZZT! it is very, very wrong to be inlining this this way. // If one calls hashtable_iterator on a hash table from which everything // has been deleted, the iterator has a null for i->e. // It is not good to require the caller to check the internals of the iterator // structure just to be sure there are no null pointers inside. // For whatever reason, these are defined again in the hashtable_iterator.c // file, not inlined. I have modified the ones in hashtable_iterator so they // actually check for nulls and don't try to dereference them. /*****************************************************************************/ /* hashtable_iterator_key * - return the value of the (key,value) pair at the current position */ extern inline void * hashtable_iterator_key(struct hashtable_itr *i) { return i->e->k; } /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ extern inline void * hashtable_iterator_value(struct hashtable_itr *i) { return i->e->v; } #else // SO instead of inlining, just declare. No need to be "extern" // The ones in the .c file check their arguments and return nulls if they // can't comply with the request. Much nicer for the calling routine to // check a return value than to monkey with the internals of the struct. void * hashtable_iterator_key(struct hashtable_itr *i); void * hashtable_iterator_value(struct hashtable_itr *i); #endif /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr); /*****************************************************************************/ /* remove - remove current element and advance the iterator to the next element * NB: if you need the value to free it, read it before * removing. ie: beware memory leaks! * returns zero if advanced to end of table */ int hashtable_iterator_remove(struct hashtable_itr *itr); /*****************************************************************************/ /* search - overwrite the supplied iterator, to point to the entry * matching the supplied key. h points to the hashtable to be searched. * returns zero if not found. */ int hashtable_iterator_search(struct hashtable_itr *itr, struct hashtable *h, void *k); #define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \ { \ return (hashtable_iterator_search(i,h,k)); \ } #endif /* __HASHTABLE_ITR_CWC22__*/ /* * Copyright (C) 2002, 2004 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.2/src/hashtable_private.h000066400000000000000000000045601501463444000210000ustar00rootroot00000000000000 /* Copyright (C) 2002, 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2023 The Xastir Group */ #ifndef __HASHTABLE_PRIVATE_CWC22_H__ #define __HASHTABLE_PRIVATE_CWC22_H__ #include "hashtable.h" /*****************************************************************************/ struct entry { void *k, *v; unsigned int h; struct entry *next; }; struct hashtable { unsigned int tablelength; struct entry **table; unsigned int entrycount; unsigned int loadlimit; unsigned int primeindex; unsigned int (*hashfn) (void *k); int (*eqfn) (void *k1, void *k2); }; /*****************************************************************************/ unsigned int hash(struct hashtable *h, void *k); /*****************************************************************************/ /* indexFor */ static inline unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { return (hashvalue % tablelength); } /* Only works if tablelength == 2^N */ /*static inline unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { return (hashvalue & (tablelength - 1u)); } */ /*****************************************************************************/ #define freekey(X) free(X) /*define freekey(X) ; */ /*****************************************************************************/ #endif /* __HASHTABLE_PRIVATE_CWC22_H__*/ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.2/src/icon.xbm000066400000000000000000000024661501463444000166050ustar00rootroot00000000000000#define icon_width 40 #define icon_height 40 static unsigned char icon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x1f, 0x00, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x10, 0x20, 0x10, 0x00, 0x00, 0x08, 0x20, 0x20, 0x00, 0x00, 0x04, 0x20, 0x20, 0x00, 0x00, 0x02, 0x28, 0x60, 0x00, 0x00, 0x27, 0x28, 0x60, 0xfc, 0xff, 0x3f, 0x28, 0x60, 0xfe, 0xff, 0x3f, 0xe8, 0x7f, 0xfe, 0xff, 0x27, 0xef, 0x7f, 0xfe, 0xff, 0x07, 0xef, 0x7f, 0xfe, 0xff, 0x07, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0x00, 0xfc, 0x0f, 0xfc, 0x0f, 0x00, 0xfc, 0x0f, 0xf8, 0x07, 0x00, 0xf8, 0x07, 0xf0, 0x03, 0x00, 0xf0, 0x03, 0xe0, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; Xastir-Release-2.2.2/src/igate.c000066400000000000000000001271411501463444000164000ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "igate.h" #include "main.h" #include "interface.h" #include "xa_config.h" #include "util.h" // Must be last include file #include "leak_detection.h" time_t last_nws_stations_file_time = 0; int NWS_stations = 0; int max_NWS_stations = 0; NWS_Data *NWS_station_data; void load_NWS_stations(char *file); int check_NWS_stations(char *call); // Struct for holding packet data. We use dynamically-allocated // singly-linked lists. The last record should have its "next" // pointer set to NULL. // typedef struct _DupeRecord { char data[MAX_LINE_SIZE+15]; // Packet data time_t time; // The time the record was inserted struct _DupeRecord *next; // pointer to next record in list } DupeRecord; // Sent and Heard queue pointers. These are used for the dupe-checking // we do in the below routines. We have one Sent and one Heard queue // for each interface device. These pointers will point to the head of // each queue. We really only need these queues for each TNC interface, // but the user might destroy a NET interface and create a TNC interface // during a single runtime, so we need to populate all of the pointers // just in case. If people switch types, the old queue will empty out // (effectively anyway) within XX seconds, so we don't have to worry // about cleaning out the queues in this case. // DupeRecord *heard_queue[MAX_IFACE_DEVICES]; DupeRecord *sent_queue[MAX_IFACE_DEVICES]; // Types of queues for each interface #define HEARD 0 #define SENT 1 // Insert mode for the queues #define NO_FORCED_INSERT 0 #define FORCED_INSERT 1 // Initialization routine for this module which sets up the queue // pointers when Xastir first starts. Called from main.c:main() // void igate_init(void) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { heard_queue[i] = NULL; sent_queue[i] = NULL; } } // // not_a_dupe: Function which checks for duplicate packets. // // Returns: 1 if it's _not_ a duplicate record or we have an error // 0 if it _is_ a duplicate record // // Since we need to run through every record checking for dupes anyway, // we check the timestamp on each one as we go through. If too old, we // delete it from the head of the chain. We add new records to the end. // This makes it easy to keep it as a singly-linked list, and only have // to deal with one record at a time. // // The way this is set up we keep a thirty second queue for each // interface. Any records older than this are at the head of the chain // and are deleted one by one whenever this routine is called again due // to a new packet coming through. It's ok if these records sit around // on the queue for a long time due to no igate activity. It doesn't // take long to delete them! // int not_a_dupe(int queue_type, int port, char *line, int insert_mode) { DupeRecord *ptr; DupeRecord *ptr_last; int insert_new; time_t time_cutoff; int found_dupe = 0; char match_line[MAX_LINE_SIZE*2]; char line2[MAX_LINE_SIZE+1]; char *c0, *c1, *c2; if ( (line == NULL) || (line[0] == '\0') ) { return(1); } // Figure out what's "old" time_cutoff = sec_now() - (time_t)29; // 29 seconds ago // Fill the destination string with zeroes. This is a nice // segfault-prevention technique. Whatever strings we throw in here // will be automatically terminated. memset(match_line, 0, MAX_LINE_SIZE*2); switch (queue_type) { case HEARD: ptr_last = ptr = heard_queue[port]; // May be NULL! // The insert_into_heard_queue() function below (called by // db.c decode routines in turn) will call this function // with FORCED_INSERT. Other routines in igate.c will call // it with NO_FORCED_INSERT. For the Heard queue we only // want the db.c decode routines inserting records. if (insert_mode == FORCED_INSERT) { insert_new = 1; // Insert new records. } else { insert_new = 0; // Don't insert new records. } // RF packets will have third-party headers and regular // headers that must be stripped off. We only want to store // 3rd party RF strings in the Heard queue as the others // aren't going to be igated anyway. For matching and // storage purposes the 3rd party packets should look // identical to how they were originally passed on the 'net, // so that we can try to find duplicates before transmitting // them again. // NOTE: Below is the parsing code for an internet packet for the Sent // queue. Modify it to parse 3rd party packets for the Heard queue. // VE7VFM-12>APD214,VE7VAN-3*,WIDE3*:}WA7JAK>APK002,TCPIP*,VE7VFM-12*::N7WGR-7 :does{2 // Changes needed before parsing code: Get rid of first // part of packet up to the '}' symbol. After this the // generic parsing code will work. // Note that the REPLY-ACK algorithm also uses the '}' symbol. c0 = strstr(line, ":}"); // Find start of 3rd party packet if (c0 == NULL) // Not 3rd party packet { if (debug_level & 1024) { fprintf(stderr," Not 3rd party HeardQ: %s\n",line); } return(1); } // Copy original packet into line2 for later parsing. We // want to keep the '}' character because our own // transmissions out RF have that character as well. // Note that the REPLY-ACK algorithm also uses the '}' symbol. if (debug_level & 1024) { fprintf(stderr,"3rd party HeardQ: %s\n",line); } xastir_snprintf(line2, sizeof(line2), "%s", c0+1); break; case SENT: // For this queue we always want to insert records. Only // igate.c functions call this. ptr_last = ptr = sent_queue[port]; // May be NULL! insert_new = 1; // Insert new records // No extra changes needed before parsing code, Example: // }VE7VFM-11>APW251,TCPIP,WE7U-14*::VE7VFM-9 :OK GOT EMAIL OK{058 xastir_snprintf(line2, sizeof(line2), "%s", line); if (debug_level & 1024) { fprintf(stderr," COMPLETE SENT PACKET: %s\n",line2); } break; default: // We shouldn't be here. return(1); break; } // Create the string we're going to compare against and that we // might store in the queue. Knock off the path info and just check // source/destination/info portions of the packet for a match. c1 = strstr(line2, ","); // Find comma after destination c2 = strstr(line2, ":"); // Find end of path if ( (c1 != NULL) && (c2 != NULL) ) // Found both separators { // Copy source/destination portion xastir_snprintf(match_line, sizeof(match_line), "%s", line2); match_line[(int)(c1-line2)] = '\0'; // Terminate the substring strncat(match_line, // Copy info portion c2+1, sizeof(match_line) - 1 - strlen(match_line)); } else // At least one separator was not found, copy entire string { xastir_snprintf(match_line, sizeof(match_line), "%s", line2); } // Run through the selected queue from beginning to end. If the // pointer is NULL, the queue is empty and we're already done. while (ptr != NULL && !found_dupe) { // Check the timestamp to determine whether to delete this // record if (ptr->time < time_cutoff) // Old record, delete it { DupeRecord *temp; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD Deleting record: %s\n",ptr->data); break; case SENT: fprintf(stderr," SENT Deleting record: %s\n",ptr->data); break; default: break; } } // Delete record and free up the space temp = ptr; ptr = ptr->next; // May be NULL! free(temp); // Point master queue pointer to new head of queue. // Make sure to carry along ptr_last as well, as this is // our possible insertion point later. switch (queue_type) { case HEARD: heard_queue[port] = ptr_last = ptr; // May be NULL! break; case SENT: sent_queue[port] = ptr_last = ptr; // May be NULL! default: break; } } else // Record is current. Check for a match. { //fprintf(stderr,"\n\t\t%s\n\t\t%s\n",ptr->data,match_line); if (strcmp(ptr->data,match_line) == 0) { // We found a dupe! We're done with the loop. found_dupe++; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD* Found dupe: %s\n",match_line); break; case SENT: fprintf(stderr,"SENT* Found dupe: %s\n",match_line); default: break; } } } else // Not a dupe, skip to the next record in the { // queue. Keep a pointer to the last record // compared so that we have a possible insertion // point later. Once we hit the end (NULL), we // can't back up one. ptr_last = ptr; // Save pointer to last record ptr = ptr->next; // Advance one. May be NULL! } } } // End of while loop if (found_dupe) { if (debug_level & 1024) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_NET_AGWPE: fprintf(stderr," Found RF dupe: %s\n",match_line); break; default: fprintf(stderr," Found NET dupe: %s\n",match_line); break; } } return(0); // Found a dupe, return } else { // If insert_new == 1, insert each non-dupe record into the // queue and give it a timestamp. ptr_next is currently // either NULL or points to the last record in the chain. if (insert_new) { DupeRecord *temp; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD Adding record: %s\n",match_line); break; case SENT: fprintf(stderr," SENT Adding record: %s\n",match_line); break; default: break; } } // Allocate a new storage space for the record and fill // it in. temp = (DupeRecord *)malloc(sizeof(DupeRecord)); if (!temp) { fprintf(stderr,"Couldn't allocate memory in not_a_dupe()\n"); return(1); // Send back "not a dupe" } temp->time = (time_t)sec_now(); memcpy(temp->data, match_line, sizeof(temp->data)); temp->data[sizeof(temp->data)-1] = '\0'; // Terminate string temp->next = NULL; // Will be the end of the linked list if (ptr_last == NULL) // Queue is currently empty { // Add record to empty list. Point master queue pointer // to new head of queue. switch (queue_type) { case HEARD: heard_queue[port] = temp; break; case SENT: sent_queue[port] = temp; default: break; } } else // Queue is not empty, add the record to the end of { // the list. ptr_last->next = temp; } } } return(1); // Nope, not a dupe } // Function which the receive routines call to insert a received // packet into the HEARD queue for an interface. The packet will // get added to the end of the linked list if it's not a duplicate // record. // // Check to make sure it's an RF interface, else return // void insert_into_heard_queue(int port, char *line) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_NET_AGWPE: // We're not using the dupe check function, but merely the // expiration and insert functions of not_a_dupe() // Don't insert the "Tickle" lines that keep the internet // sockets alive if ( (strncasecmp(line,"# Tickle",8) != 0) && (strncasecmp(line,"#Tickle",7) != 0) ) { (void)not_a_dupe(HEARD, port, line, FORCED_INSERT); } break; default: // Get out if not an RF interface return; break; } } /****************************************************************/ /* output data to inet interfaces */ /* line: data to send out */ /* port: port data came from */ /****************************************************************/ void output_igate_net(char *line, int port, int third_party) { char data_txt[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char *call_sign; char *path; char *message; int len,i,x,first; int igate_options; char log_file_path[MAX_VALUE]; call_sign = NULL; path = NULL; message = NULL; first = 1; if (line == NULL) { return; } if (line[0] == '\0') { return; } // Don't igate packets read in from a log file (port -1). // Packets from x_spider (port -2) are ok to igate. if (port == -1) { return; } //fprintf(stderr,"Igating: %s\n", line); // Should we Igate from RF->NET? if (operate_as_an_igate <= 0) { return; } xastir_snprintf(temp, sizeof(temp), "%s", line); // Check for null call_sign field call_sign = strtok(temp,">"); if (call_sign == NULL) { return; } // Check for null path field path = strtok(NULL,":"); if (path == NULL) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); // Check for "TCPIP" or "TCPXX" in the path. If found, don't // gate this into the internet again, it's already been gated to // RF, which means it's already been on the 'net. No looping // allowed here... // // We also now support NOGATE and RFONLY options. If these are // seen in the path, do _not_ gate those packets into the // internet. // // Don't gate OpenTrac expanded packets to the 'net. // if ( (strstr(path,"TCPXX") != NULL) || (strstr(path,"TCPIP") != NULL && port >= 0) // x_spider ok || (strstr(path,"NOGATE") != NULL) || (strstr(path,"RFONLY") != NULL) || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Packet was gated before or shouldn't be gated!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Check for null message field message = strtok(NULL,""); if (message == NULL) { return; } // Check for third party messages. We don't want to gate these // back onto the internet feeds // Note that the REPLY-ACK algorithm also uses the '}' symbol. if (message[0] == '}') { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Third party traffic!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Check for "general" queries. We don't wish to gate these in // either direction. There are exactly three general query // types defined in the spec. // if ( ( strstr(message,"?APRS?" ) != NULL) || (strstr(message,"?IGATE?") != NULL) || (strstr(message,"?WX?" ) != NULL) ) { // We found a general query, don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: General Query!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } len = (int)strlen(call_sign); for (i=0; iNET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: From my call!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Should I filter out more here.. get rid of all data // or Look in the path for things line "AP" "GPS" "ID" etc..? begin_critical_section(&devices_lock, "igate.c:output_igate_net" ); // If received from x_spider port or it's our own tactical call. // Here are the special port numbers we might see: // -1: We're reading in from a log file // -2: Packet came from x_spider server port (therefore it's // already authenticated) // -3: We're reading in tactical calls from file // if (port == -1) // Packet came from a log file. { igate_options = 0; // Don't igate it. } else if (port == -2) // Packet came from x_spider server port { igate_options = 1; // Ok to igate. } else if (port == -3) // We're reading tactical call from file. { igate_options = 0; // Don't igate it. } else if (port < -2) // Errant port number. { igate_options = 0; // Don't igate it. } else // Port number is 0 or positive number. A real port. // Decide whether to igate it based on the port's // configuration. { igate_options = devices[port].igate_options; } end_critical_section(&devices_lock, "igate.c:output_igate_net" ); if (igate_options <= 0 ) { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No RF->NET from input port [%d]!\n", port); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } xastir_snprintf(data_txt, sizeof(data_txt), "%s%c%c", line, '\r', '\n'); // write data out to net interfaces for (x = 0; x < MAX_IFACE_DEVICES; x++) { // Find all internet interfaces that are "up" if (port_data[x].device_type == DEVICE_NET_STREAM && x!=port && port_data[x].status == DEVICE_UP) { int pcode; // Check whether we have a valid callsign/password // combination for this interface. If not, don't gate // packets to it. pcode = atoi(port_data[x].device_host_pswd); if (checkHash(my_callsign, pcode)) { // The pcode checks out. Allow sending the // packet out to the internet. // log traffic for the first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } // Now log the interface that each bit of traffic // goes out on. xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate RF->NET packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr,"%s\n",temp); } // Write this data out to the Inet port The "1" // means raw format, the last digit says to _not_ // use the unproto_igate path output_my_data(data_txt,x,1,0,0,NULL); //fprintf(stderr,"Sending: %s\n", data_txt); } } } } /****************************************************************/ /* output data to tnc interfaces */ /* from: type of port heard from (No! It's the source call!) */ /* call: call sign heard from (No! It's the destination call!) */ /* line: data to gate to rf */ /* port: port data came from */ /****************************************************************/ void output_igate_rf(char *from, char *call, char *path, char *line, int port, int third_party, char *object_name) { char temp[MAX_LINE_SIZE+20]; int x; int first = 1; int found_in_nws_file = 0; char log_file_path[MAX_VALUE]; char nws_file_path[MAX_VALUE]; if ( (from == NULL) || (call == NULL) || (path == NULL) || (line == NULL) ) { return; } if ( (from[0] == '\0') || (call[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') ) { return; } // Should we Igate from NET->RF? if (operate_as_an_igate <= 1) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); // Don't gate anything with NOGATE in it, in either direction. // Same for OpenTrac packets. if ( (strstr(path,"NOGATE") != NULL) || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet { // "NOGATE" was found in the header. Don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NOGATE found in path or shouldn't be gated!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Don't gate "general" queries in any direction. There are // exactly three general query types defined in the spec. // if ( (strstr(line,"?APRS?" ) != NULL) || (strstr(line,"?IGATE?") != NULL) || (strstr(line,"?WX?" ) != NULL) ) { // We found a general query, don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: General Query!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // check to see if the nws-stations file is newer than last read get_user_base_dir("data/nws-stations.txt",nws_file_path, sizeof(nws_file_path)); if (last_nws_stations_file_time < file_time(nws_file_path)) { last_nws_stations_file_time = file_time(nws_file_path); load_NWS_stations(nws_file_path); //fprintf(stderr,"NWS Station file time is old\n"); } // Check whether gating of packets from this station/object/item // has been specifically authorized via the nws-stations.txt // mechanism. // if (object_name) // It's an object or item name { if ( check_NWS_stations( object_name ) || group_active(object_name)) { found_in_nws_file++; // Object/Item is in nws-stations.txt } } else // It's a station callsign { if ( check_NWS_stations( from ) || group_active(from)) { found_in_nws_file++; // Source callsign is in nws-stations.txt } } // The above is really the same as the following code, but less // confusing: // if (check_NWS_stations( (object_name) ? object_name : from ) ) { // found_in_nws_file++; // } // Check for TCPXX in string only if station wasn't found in the // nws-stations.txt file. If TCPXX found, we have an // unregistered net user and the packet shouldn't normally head // to RF. // // I removed the trailing asterisk -we7u // // Note that we CAN now gate stations to RF that have TCPXX in // the string if they are authorized via the nws-stations.txt // mechanism. // if (!found_in_nws_file) // Skip this check if they're always authorized via the file { if (strstr(path,"TCPXX") != NULL) { // "TCPXX" was found in the header. We have an // unregistered user. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Unregistered net user!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } } // If we made it to this point, the packet is from an authorized net // user (no TCPXX found in the path), or the callsign has been // authorized via the nws-stations.txt file (whether or not TCPXX // was found in the path). // // Found in file: Gate always // // Not found: Gate if TCPXX not in path -AND- if destination // station was heard in last hour on RF -AND- if // source station was NOT heard in last hour on RF. // Check whether the source and destination calls have been // heard on local RF. if ( !found_in_nws_file // Skip this check if they're always authorized via the file && ( !heard_via_tnc_in_past_hour(call) // Haven't heard destination call in previous hour || heard_via_tnc_in_past_hour(from)) ) // Have heard source call in previous hour { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); // heard(call), heard(from) : RF-to-RF talk // !heard(call), heard(from) : Destination not heard on TNC // !heard(call), !heard(from) : Destination/source not heard on TNC if (!heard_via_tnc_in_past_hour(call)) xastir_snprintf(temp, sizeof(temp), "REJECT: Destination not heard on TNC within an hour %s!\n", call ); else xastir_snprintf(temp, sizeof(temp), "REJECT: RF->RF talk!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Station we are going to is heard via tnc but station sending // shouldn't be heard via TNC. Write data out to interfaces. for (x=0; x1 && port_data[x].status==DEVICE_UP) { // log traffic for first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate NET->RF packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr, "%s", temp); } // ok write this data out to the RF port end_critical_section(&devices_lock, "igate.c:output_igate_rf" ); // First "0" means "cooked" // format, last digit: use // unproto_igate path output_my_data(line,x,0,0,1,NULL); //fprintf(stderr, "Igating->RF: %s\n", line); begin_critical_section(&devices_lock, "igate.c:output_igate_rf" ); } else { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NET->RF on port [%d]!\n", x); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } } end_critical_section(&devices_lock, "igate.c:output_igate_rf" ); break; default: break; } // End of switch } // End of if } // End of for } void add_NWS_stations(void) { void *tmp_ptr; if (NWS_stations>=max_NWS_stations) { if ((tmp_ptr = realloc(NWS_station_data, sizeof(NWS_Data)*(max_NWS_stations+11)))) { NWS_station_data = tmp_ptr; max_NWS_stations += 10; } else { fprintf(stderr,"Unable to allocate more space for NWS_station_data\n"); } } } /****************************************************************/ /* Load NWS stations file */ /* file: file to read */ /****************************************************************/ void load_NWS_stations(char *file) { FILE *f; char line[40]; if (file == NULL) { return; } if (file[0] == '\0') { return; } if (NWS_station_data) { free(NWS_station_data); NWS_station_data = NULL; } NWS_stations = 0; max_NWS_stations = 0; f = fopen(file,"r"); if (f!=NULL) { while (!feof(f)) { if (strlen(get_line(f,line,40))>0) { // look for comment if (line[0] != '#' ) { NWS_stations++; add_NWS_stations(); if (NWS_station_data != NULL) { // add data // Note: Size of string variable is 12 // bytes, defined in igate.h if (1 != sscanf(line,"%11s",NWS_station_data[NWS_stations-1].call)) { fprintf(stderr,"load_NWS_stations: sscanf parsing error\n"); } if (debug_level & 1024) { fprintf(stderr,"LINE:%s\n",line); } } else { fprintf(stderr,"Can't allocate data space for NWS station\n"); } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open NWS stations file: %s\n", file); } } // check NWS stations file // // call: call to check // returns 1 for found // // Both the incoming call and the stored call we're matching against // have to be >= 3 characters long. This routine will match only up // to the length of the stored string, so we now allow partial // matches. // int check_NWS_stations(char *call) { int ok, i, length, length_incoming; if (call == NULL) { return(0); } if (call[0] == '\0') { return(0); } if (NWS_station_data == NULL) { return(0); } if (debug_level & 1024) { fprintf(stderr,"igate.c::check_NWS_stations %s\n", call); } // Make sure that the incoming call is longer than three // characters. If not, skip it. length_incoming = strlen(call); if (length_incoming < 3) { return(0); } ok=0; for (i=0; i= 3) { // Compare the incoming call only up to the length of the // stored call. This allows partial matches. The // stored call could be significantly shorter than the // incoming call, but at least three characters. if (strncasecmp(call, NWS_station_data[i].call, length)==0) { ok=1; // match found if (debug_level & 1024) { fprintf(stderr,"NWS-MATCH:(%s) (%s)\n",NWS_station_data[i].call,call); } } } else { // Do nothing. Stored call is too short. } } return(ok); } /****************************************************************/ /* output NWS data to tnc interfaces */ /* from: type of port heard from */ /* call: call sign heard from */ /* line: data to gate to rf */ /* port: port data came from */ /****************************************************************/ void output_nws_igate_rf(char *from, char *path, char *line, int port, int third_party) { char temp[MAX_LINE_SIZE+20]; int x; int first = 1; char log_file_path[MAX_VALUE]; char nws_file_path[MAX_VALUE]; if ( (from == NULL) || (path == NULL) || (line == NULL) ) { return; } if ( (from[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') ) { return; } // Should we Igate from NET->RF? if (operate_as_an_igate <= 1) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); get_user_base_dir("data/nws-stations.txt",nws_file_path, sizeof(nws_file_path)); // Check for TCPXX in string! If found, we have an // unregistered net user. // I removed the trailing asterisk --we7u if (strstr(path,"TCPXX") != NULL) { // "TCPXX" was found in the header. We have an // unregistered user. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Unregistered net user!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // no unregistered net user found in string. Look for NOGATE // next. if ( strstr(path,"NOGATE") != NULL ) { // "NOGATE" was found in the header. Don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NOGATE found in path!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // see if we can gate NWS messages if (!filethere(nws_file_path)) { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No nws-stations.txt file!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // check to see if the nws-stations file is newer than last read if (last_nws_stations_file_time < file_time(nws_file_path)) { last_nws_stations_file_time = file_time(nws_file_path); load_NWS_stations(nws_file_path); //fprintf(stderr,"NWS Station file time is old\n"); } // Look for NWS station in file data if (!check_NWS_stations(from) || !group_active(from)) // Couldn't find the station { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No matching station in nws-stations.txt file!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; // Match for station not found in file } //fprintf(stderr,"SENDING NWS VIA TNC!!!!\n"); // write data out to interfaces for (x=0; x1 && port_data[x].status==DEVICE_UP) { // log traffic for first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate NET->RF packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr, "%s", temp); } // ok write this data out to the RF port end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); // First "0" means "cooked" // format, last digit: use // unproto_igate path output_my_data(line,x,0,0,1,NULL); begin_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); } else { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NET->RF on port [%d]!\n", x); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } } end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); break; default: break; } } } } Xastir-Release-2.2.2/src/igate.h000066400000000000000000000026521501463444000164040ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_IGATE_H #define __XASTIR_IGATE_H typedef struct { char call[12]; } NWS_Data; extern void igate_init(void); extern void insert_into_heard_queue(int port, char *line); extern void output_igate_net(char *line, int port, int third_party); extern void output_igate_rf(char *from, char *call, char *path, char *line, int port, int third_party, char *object_name); extern void output_nws_igate_rf(char *from, char *path, char *line, int port, int third_party); #endif // __XASTIR_IGATE_H Xastir-Release-2.2.2/src/interface.c000066400000000000000000007674531501463444000172670ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* AX.25 Parts adopted from: aprs_tty.c by Henk de Groot - PE1DNN */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include #include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include "xastir.h" #include "symbols.h" #include "main.h" #include "xa_config.h" //#include "maps.h" #include "interface.h" #include "util.h" #include "wx.h" #include "forked_getaddrinfo.h" #include "x_spider.h" #include "db_gis.h" #include "gps.h" #ifdef HAVE_LIBAX25 #include #include #include #include #endif // HAVE_LIBAX25 // Must be last include file #include "leak_detection.h" #ifndef SIGRET #define SIGRET void #endif // SIGRET // Older versions of glibc <= 2.3.0 and <= OS X 10.5 do not have this // constant defined #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0 #endif //extern pid_t getpgid(pid_t pid); extern void port_write_binary(int port, unsigned char *data, int length); iodevices dtype[MAX_IFACE_DEVICE_TYPES]; // device names iface port_data[MAX_IFACE_DEVICES]; // shared port data int port_id[MAX_IFACE_DEVICES]; // shared port id data xastir_mutex port_data_lock; // Protects the port_data[] array of structs xastir_mutex data_lock; // Protects incoming_data_queue xastir_mutex output_data_lock; // Protects interface.c:channel_data() function only xastir_mutex connect_lock; // Protects port_data[].thread_status and port_data[].connect_status void port_write_string(int port, char *data); int ax25_ports_loaded = 0; // Incoming data queue typedef struct _incoming_data_record { int length; // Used for binary strings such as KISS int port; unsigned char data[MAX_LINE_SIZE]; } incoming_data_record; #define MAX_INPUT_QUEUE 1000 static incoming_data_record incoming_data_queue[MAX_INPUT_QUEUE]; unsigned char incoming_data_copy[MAX_LINE_SIZE]; // Used for debug unsigned char incoming_data_copy_previous[MAX_LINE_SIZE]; // Used for debug // interface wait time out int NETWORK_WAITTIME; // Read/write pointers for the circular input queue static int incoming_read_ptr = 0; static int incoming_write_ptr = 0; static int queue_depth = 0; static int push_count = 0; static int pop_count = 0; /* prototype for function that is only used in this file, need not be in the associated header */ void output_fixed_position(char *data_txt_save, size_t data_txt_save_size, char *my_pos, char * output_phg, char * output_alt, char *my_comment_tx, char *data_txt, size_t data_txt_size, char *output_net); // Fetch a record from the circular queue. // Returns 0 if no records available // Else returns length of string, data_string and port // data_string variable should be of size MAX_LINE_SIZE // int pop_incoming_data(unsigned char *data_string, int *port) { int length; int jj; if (begin_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } // Check for queue empty if (incoming_read_ptr == incoming_write_ptr) { // Yep, it's empty queue_depth = 0; if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(0); } // Bump the read pointer incoming_read_ptr = (incoming_read_ptr + 1) % MAX_INPUT_QUEUE; *port = incoming_data_queue[incoming_read_ptr].port; length = incoming_data_queue[incoming_read_ptr].length; // Yes, this is a string, but it may have zeros embedded. We can't // use string manipulation functions because of that: for (jj = 0; jj < length; jj++) { data_string[jj] = incoming_data_queue[incoming_read_ptr].data[jj]; } // Add terminator, just in case data_string[length+1] = '\0'; queue_depth--; pop_count++; if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(length); } // Add one record to the circular queue. Returns 1 if queue is // full, 0 if successful. // int push_incoming_data(unsigned char *data_string, int length, int port) { int next_write_ptr = (incoming_write_ptr + 1) % MAX_INPUT_QUEUE; int jj; if (begin_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } // Check whether queue is full if (incoming_read_ptr == next_write_ptr) { // Yep, it's full! if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(1); } // Advance the write pointer incoming_write_ptr = next_write_ptr; incoming_data_queue[incoming_write_ptr].length = length; incoming_data_queue[incoming_write_ptr].port = port; // Binary safe copy in case there are embedded zeros for (jj = 0; jj < length; jj++) { incoming_data_queue[incoming_write_ptr].data[jj] = data_string[jj]; } queue_depth++; push_count++; if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(0); } // Returns 1 if a local interface, 0 otherwise // int is_local_interface(int port) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: case DEVICE_AX25_TNC: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: return(1); // Found a local interface break; // Could be port -1 which signifies a spider port or port // -99 which signifies "All Ports" and is used for // transmitting out all ports at once. default: return(0); // Unknown or network interface break; } } // Returns 1 if a network interface, 0 otherwise // int is_network_interface(int port) { switch (port_data[port].device_type) { case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: return(1); // Found a network interface break; // Could be port -1 which signifies a spider port or port // -99 which signifies "All Ports" and is used for // transmitting out all ports at once. default: return(0); // Unknown or local interface break; } } // Create a packet and send to AGWPE for transmission. // Format is as follows: // // RadioPort 4 bytes (0-3) // DataType 4 bytes (4-7) // FromCall 10 bytes (8-17) // ToCall 10 bytes (18-27) // DataLength 4 bytes (28-31) // UserField 4 bytes (32-35) // Data DataLength bytes (36-?) // // Callsigns are null-terminated at end of string, but callsign // field width is specified to be 10 bytes in all cases. // // Path is split up into the various ViaCalls. Path may also be a // NULL pointer. // // If type != '\0', then we'll create the specified type of packet. // // Else if Path is not empty, we'll use packet format "V" with // Viacalls prepended to the Data portion of the packet, 10 chars // per digi, with the number of digis as the first character. The // packet data then follows after the last via callsign. // // Else if no Path, then put the Data directly into the Data // field and use "M" format packets. // // We currently use the base portion of my_callsign as the username // portion of the AGWPE login. This must be upper-case when you're // setting up the account in AGWPE, as that's what we send to // authenticate. // void send_agwpe_packet(int xastir_interface,// Xastir interface port int RadioPort, // AGWPE RadioPort unsigned char type, unsigned char *FromCall, unsigned char *ToCall, unsigned char *Path, unsigned char *Data, int length) { int ii; #define agwpe_header_size 36 unsigned char output_string[512+agwpe_header_size]; unsigned char path_string[200]; int full_length; int data_length; // Check size of data if (length > 512) { return; } // Clear the output_string (set to binary zeroes) for (ii = 0; ii < (int)sizeof(output_string); ii++) { output_string[ii] = '\0'; } if (type != 'P') { // Write the port number into the frame. Note that AGWPE // uses 1 for the first port in its GUI, but the programming // interface starts at 0. output_string[0] = (unsigned char)RadioPort; if (FromCall) // Write the FromCall string into the frame xastir_snprintf((char *)&output_string[8], sizeof(output_string) - 8, "%s", FromCall); if (ToCall) // Write the ToCall string into the frame xastir_snprintf((char *)&output_string[18], sizeof(output_string) - 18, "%s", ToCall); } if ( (type != '\0') && (type != 'P') ) { // Type was specified, not a data frame or login frame // Write the type character into the frame output_string[4] = type; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, agwpe_header_size); } else if (Path == NULL) // No ViaCalls, Data or login packet { if (type == 'P') { // Login/Password frame char callsign_base[15]; int new_length; // Write the type character into the frame output_string[4] = type; // Compute the callsign base string // (callsign minus SSID) xastir_snprintf(callsign_base, sizeof(callsign_base), "%s", my_callsign); // Change '-' into end of string strtok(callsign_base, "-"); // Length = length of each string plus the two // terminating zeroes. //new_length = strlen(callsign_base) + length + 2; new_length = 255+255; output_string[28] = (unsigned char)(new_length % 256); output_string[29] = (unsigned char)((new_length >> 8) % 256); // Write login/password out as 255-byte strings each // Put the login string into the buffer xastir_snprintf((char *)&output_string[agwpe_header_size], sizeof(output_string) - agwpe_header_size, "%s", callsign_base); // Put the password string into the buffer xastir_snprintf((char *)&output_string[agwpe_header_size+255], sizeof(output_string) - agwpe_header_size - 255, "%s", Data); // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, 255+255+agwpe_header_size); } else // Data frame { // Write the type character into the frame output_string[4] = 'M'; // Unproto, no via calls // Write the PID type into the frame output_string[6] = 0xF0; // UI Frame output_string[28] = (unsigned char)(length % 256); output_string[29] = (unsigned char)((length >> 8) % 256); // Copy Data onto the end of the string. This one // doesn't have to be null-terminated, so strncpy() is // ok to use here. strncpy stops at the first null byte // though. Proper for a binary output routine? NOPE! strncpy((char *)(&output_string[agwpe_header_size]),(char *)Data, length); full_length = length + agwpe_header_size; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, full_length); } } else // We have ViaCalls. Data packet. { char *ViaCall[10]; // Doesn't need to be null-terminated, so strncpy is ok to // use here. strncpy stops at the first null byte though. // Proper for a binary output routine? NOPE! strncpy((char *)path_string, (char *)Path, sizeof(path_string)); // Convert path_string to upper-case to_upper((char *)path_string); split_string((char *)path_string, ViaCall, 10, ','); // Write the type character into the frame output_string[4] = 'V'; // Unproto, via calls present // Write the PID type into the frame output_string[6] = 0xF0; // UI Frame // Write the number of ViaCalls into the first byte if (ViaCall[7]) { output_string[agwpe_header_size] = 0x08; } else if (ViaCall[6]) { output_string[agwpe_header_size] = 0x07; } else if (ViaCall[5]) { output_string[agwpe_header_size] = 0x06; } else if (ViaCall[4]) { output_string[agwpe_header_size] = 0x05; } else if (ViaCall[3]) { output_string[agwpe_header_size] = 0x04; } else if (ViaCall[2]) { output_string[agwpe_header_size] = 0x03; } else if (ViaCall[1]) { output_string[agwpe_header_size] = 0x02; } else { output_string[agwpe_header_size] = 0x01; } // Write the ViaCalls into the Data field switch (output_string[agwpe_header_size]) { case 8: if (ViaCall[7]) { strncpy((char *)(&output_string[agwpe_header_size+1+70]), ViaCall[7], 10); } else { return; } /* Falls through. */ case 7: if (ViaCall[6]) { strncpy((char *)(&output_string[agwpe_header_size+1+60]), ViaCall[6], 10); } else { return; } /* Falls through. */ case 6: if (ViaCall[5]) { strncpy((char *)(&output_string[agwpe_header_size+1+50]), ViaCall[5], 10); } else { return; } /* Falls through. */ case 5: if (ViaCall[4]) { strncpy((char *)(&output_string[agwpe_header_size+1+40]), ViaCall[4], 10); } else { return; } /* Falls through. */ case 4: if (ViaCall[3]) { strncpy((char *)(&output_string[agwpe_header_size+1+30]), ViaCall[3], 10); } else { return; } /* Falls through. */ case 3: if (ViaCall[2]) { strncpy((char *)(&output_string[agwpe_header_size+1+20]), ViaCall[2], 10); } else { return; } /* Falls through. */ case 2: if (ViaCall[1]) { strncpy((char *)(&output_string[agwpe_header_size+1+10]), ViaCall[1], 10); } else { return; } /* Falls through. */ case 1: default: if (ViaCall[0]) { strncpy((char *)(&output_string[agwpe_header_size+1+0]), ViaCall[0], 10); } else { return; } break; } // Write the Data onto the end. // Doesn't need to be null-terminated, so strncpy is ok to // use here. strncpy stops at the first null byte though. // Proper for a binary output routine? strncpy((char *)(&output_string[((int)(output_string[agwpe_header_size]) * 10) + agwpe_header_size + 1]), (char *)Data, length); //Fill in the data length field. We're assuming the total //is less than 512 + 37. data_length = length + ((int)(output_string[agwpe_header_size]) * 10) + 1; if ( data_length > 512 ) { return; } output_string[28] = (unsigned char)(data_length % 256); output_string[29] = (unsigned char)((data_length >> 8) % 256); full_length = data_length + agwpe_header_size; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, full_length); } } /* // Here is a "monitor" UI packet // Total Length = 150 HEX:00 00 00 00 55 00 00 00 4b 4b 31 57 00 ed 12 00 96 ed 41 50 54 57 30 31 00 00 00 00 72 00 00 00 00 00 00 00 20 31 3a 46 6d 20 4b 4b 31 57 20 54 6f 20 41 50 54 57 30 31 20 56 69 61 20 57 49 44 45 33 20 3c 55 49 20 70 69 64 3d 46 30 20 4c 65 6e 3d 35 30 20 3e 5b 31 30 3a 34 33 3a 34 33 5d 0d 5f 30 38 30 36 31 30 33 39 63 33 35 39 73 30 30 30 67 30 30 30 74 30 36 32 72 30 30 30 70 30 30 33 50 30 39 36 68 30 30 62 31 30 30 39 33 74 55 32 6b 0d 0d 00 ASC:....U...KK1W......APTW01....r....... 1:Fm KK1W To APTW01 Via WIDE3 [10:43:43]._08061039c359s000g000t062r000p003P096h00b10093tU2k... */ /* // And here are some "raw" UI packets // AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 135 HEX:00 00 00 00 4b 00 00 00 4e 32 4c 42 54 2d 37 00 01 00 41 50 58 31 33 33 00 00 00 00 63 00 00 00 00 00 00 00 c0 82 a0 b0 62 66 66 60 9c 64 98 84 a8 40 6e 96 82 64 a2 b2 8a f4 ae 92 88 8a 40 40 61 03 f0 40 30 37 30 30 32 37 7a 34 32 33 39 2e 30 34 4e 5c 30 37 33 34 38 2e 31 30 57 5f 30 30 30 2f 30 30 30 67 30 30 30 74 30 36 34 72 30 30 30 50 30 30 30 70 30 30 30 68 35 33 62 31 30 31 32 37 58 55 32 6b 0d ASC:....K...N2LBT-7...APX133....c...........bff`.d...@n..d........@@a..@070027z4239.04N\07348.10W_000/000g000t064r000P000p000h53b10127XU2k. AGWPE: Got raw frame packet 3:23 Bad KISS packet. Dropping it. Total Length = 104 HEX:00 00 00 00 4b 00 00 00 4e 31 45 44 5a 2d 37 00 01 00 54 52 31 55 37 58 00 00 00 00 44 00 00 00 00 00 00 00 c0 a8 a4 62 aa 6e b0 60 9c 62 8a 88 b4 40 ee 96 82 62 a2 8c 8a fe ae 62 a8 9e 9a 40 fe 96 82 64 a2 b2 8a f5 03 f0 60 64 2a 39 6c 23 22 3e 2f 3e 22 35 6b 7d 6e 31 65 64 7a 40 61 6d 73 61 74 2e 6f 72 67 0d ASC:....K...N1EDZ-7...TR1U7X....D..........b.n.`.b...@...b.....b...@...d......`d*9l#">/>"5k}n1edz@amsat.org. AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 ae 92 88 8a 40 40 61 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d........@@a..!4319.79N/07340.87W>268/020/A=000485 AGWPE: Got raw frame packet 3:74 Bad KISS packet. Dropping it. Total Length = 82 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 ae 82 64 aa 9a b0 e5 03 f0 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r.d...@...d......!4319.79N/07340.87W>268/020/A=000485 AGWPE: Got raw frame packet 3:74 Bad KISS packet. Dropping it. Total Length = 82 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 96 82 64 a2 b2 8a f5 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d......d......!4319.79N/07340.87W>268/020/A=000485 */ // Parse an AGWPE header. Create a TAPR-2 style header out of the // data for feeding into the Xastir parsing code. Input format is // as follows: // // RadioPort 4 bytes (0-3) // DataType 4 bytes (4-7) // FromCall 10 bytes (8-17) // ToCall 10 bytes (18-27) // DataLength 4 bytes (28-31) // UserField 4 bytes (32-35) // Data xx bytes (36-??) // // Callsigns are null-terminated at end of string, but field width // is specified to be 10 bytes in all cases. // // output_string variable should be quite long, perhaps 1000 // characters. // // Someday it would be nice to turn on raw packet format in AGWPE // which gives us the AX.25 packet format directly. We should be // able to use our normal KISS decoding functions to parse those // types of packets, instead of the mess we have below which is // parsing a few things out of the header, a few things out of the // text that AGWPE puts after the header, and then snagging the info // field of the packet from the tail-end. // unsigned char *parse_agwpe_packet(unsigned char *input_string, int output_string_length, unsigned char *output_string, int *new_length) { int ii, jj, kk; char *info_ptr; char *via_ptr; char temp_str[512]; int special_debug = 0; int data_length; // Fetch the length of the data portion of the packet data_length = (unsigned char)(input_string[31]); data_length = (data_length << 8) + (unsigned char)(input_string[30]); data_length = (data_length << 8) + (unsigned char)(input_string[29]); data_length = (data_length << 8) + (unsigned char)(input_string[28]); // Implementing some special debugging output for the case of // third-party NWS messages, which so far haven't been parsed // properly by this function. // // Check for NWS string past the header part of the AGWPE // packet. // // Make sure we have a terminating '\0' at the end. // Note that this doesn't help for binary packets (like OpenTrac), // but doesn't really hurt either. input_string[38+data_length] = '\0'; // Check what sort of AGWPE packet it is. switch (input_string[4]) { case 'R': if (data_length == 8) { fprintf(stderr, "\nConnected to AGWPE server, version: %d.%d\n", (input_string[37] << 8) + input_string[36], (input_string[41] << 8) + input_string[40]); } return(NULL); // All done! break; case 'G': // Print out the data, changing all ';' characters to // and a bunch of spaces to format it nicely. fprintf(stderr, " Port Info, total ports = "); ii = 36; while (ii < data_length + 36 && input_string[ii] != '\0') { if (input_string[ii] == ';') { fprintf(stderr, "\n "); } else { fprintf(stderr, "%c", input_string[ii]); } ii++; } fprintf(stderr,"\n"); return(NULL); // All done! break; case 'g': return(NULL); // All done! break; case 'X': return(NULL); // All done! break; case 'y': return(NULL); // All done! break; case 'Y': return(NULL); // All done! break; case 'H': return(NULL); // All done! break; case 'C': return(NULL); // All done! break; case 'v': return(NULL); // All done! break; case 'c': return(NULL); // All done! break; case 'D': return(NULL); // All done! break; case 'd': return(NULL); // All done! break; case 'U': // We can decode this one ok in the below code (after // this switch statement), but we no longer use // "monitor" mode packets in AGWPE, switching to the // "raw" mode instead. return(NULL); // All done! break; case 'I': return(NULL); // All done! break; case 'S': return(NULL); // All done! break; case 'T': // We should decode this one ok in the below code (after // this switch statement), but we no longer use // "monitor" mode packets in AGWPE, switching to the // "raw" mode instead. return(NULL); // All done! break; case 'K': // Code here processes the packet for handing to our // KISS decoding routines. Chop off the header, add // anything to the beginning/end that we need, then send // it to decode_ax25_header(). // Try to decode header and checksum. If bad, break, // else continue through to ASCII logging & decode // routines. We skip the first byte as it's not part of // the AX.25 packet. // // Note that the packet length often increases here in // decode_ax25_header, as we add '*' characters and such // to the header as it's decoded. // This string already has a terminator on the end, // added by the code in port_read(). If we didn't have // one here, we could end up with portions of strings // concatenated on the end of our string by the time // we're done processing the data here. // // input_string[data_length+36] = '\0'; // WE7U: // We may need to extend input_string by a few characters before it // is fed to us. Something like max_callsigns * 3 or 4 characters, // to account for '*' and SSID characters that we might add. This // keeps the string from getting truncated as we add bytes to the // header in decode_ax25_header. if ( !decode_ax25_header( (unsigned char *)&input_string[37], &data_length ) ) { // int zz; // Had a problem decoding it. Drop it on the floor. fprintf(stderr, "AGWPE: Bad KISS packet. Dropping it.\n"); special_debug++; // for (zz = 0; zz < data_length; zz++) { // fprintf(stderr, "%02x ", input_string[zz+36]); // } // fprintf(stderr,"\n"); return(NULL); } // Good header. Compute the new length, again skipping // the first byte. data_length = strlen((const char *)&input_string[37]); // The above strlen() requires it to be printable ascii in the KISS // packet, so won't work for OpenTrac protocol or other binary // protocols. The decode_ax25_header() function also looks for // PID=0xF0, which again won't work for OpenTrac. It would be // better to have the decode_ax25_header routine return the new // length of the packet so that decoding of binary packets is still // possible. // Check for OpenTrac packets. If found, dump them into // OpenTrac-specific decode and skip the other decode below. Must // tweak the above stuff to allow binary-format packets to get // through to this point. // Do more stuff with the packet here. The actual // packet itself starts at offset 37. We can end up // with 0x0d, 0x0d 0x0d, or 0x0d 0x00 0x0d on the end of // it (or none of the above). Best method should be to // just search for any 0x0d's or 0x0a's starting at the // beginning of the string and overwrite them with // 0x00's. That's what we do here. // for (ii = 0; ii < data_length; ii++) { if (input_string[ii+37] == 0x0d || input_string[ii+37] == 0x0a) { input_string[ii+37] = '\0'; } } // Compute data_length again. data_length = strlen((const char *)&input_string[37]); // Send the processed string back for decoding xastir_snprintf((char *)output_string, output_string_length, "%s", &input_string[37]); // Send back the new length. *new_length = data_length; return(output_string); break; default: fprintf(stderr,"AGWPE: Got unrecognized '%c' packet\n",input_string[4]); return(NULL); // All done! break; } // NOTE: All of the code below gets used in "monitor" mode, which // we no longer use. We might keep this code around for a bit and // then delete it, as we've probably switched to "raw" mode for // good. "raw" mode allows us to use our KISS processing routines, // plus allows us to support digipeating and OpenTrac (binary) // protocol in the future. if (special_debug) { // Dump the hex & ascii representation of the whole packet kk = data_length + 36; // Add the header length fprintf(stderr, "Total Length = %d\n", kk); fprintf(stderr, "HEX:"); for (ii = 0; ii < kk; ii++) { fprintf(stderr, "%02x ", input_string[ii]); } fprintf(stderr, "\n"); fprintf(stderr, "ASC:"); for (ii = 0; ii < kk; ii++) { if (input_string[ii] < ' ' || input_string[ii] > '~') { fprintf(stderr, "."); } else { fprintf(stderr, "%c", input_string[ii]); } } fprintf(stderr, "\n"); } // Clear the output_string (set to binary zeroes) for (ii = 0; ii < output_string_length; ii++) { output_string[ii] = '\0'; } jj = 0; // Copy the source callsign ii = 8; while (input_string[ii] != '\0') { output_string[jj++] = input_string[ii++]; } // Add a '>' character output_string[jj++] = '>'; // Copy the destination callsign ii = 18; while (input_string[ii] != '\0') { output_string[jj++] = input_string[ii++]; } // Search for "]" (0x5d) which is the end of the header string, // beginning of the AX.25 information field. info_ptr = strstr((const char *)&input_string[36], "]"); // If not found, we can't process anymore if (!info_ptr) { output_string[0] = '\0'; new_length = 0; return(NULL); } // Copy the first part of the string into a variable. We'll // look for Via calls in this string, if present. ii = 36; temp_str[0] = '\0'; while (input_string[ii] != ']') { strncat(temp_str, (char *)(&input_string[ii++]), 1); } // Make sure that the protocol ID is "F0". If not, return. if (strstr(temp_str, "pid=F0") == NULL) { char *pid_ptr; // Look for the "pid=" string and print out what we can // figure out about the protocol ID. pid_ptr = strstr(temp_str, "pid="); if (pid_ptr) { pid_ptr +=4; fprintf(stderr, "parse_agwpe_packet: Non-APRS protocol was seen: PID=%2s. Dropping the packet.\n", pid_ptr); } else { fprintf(stderr, "parse_agwpe_packet: Non-APRS protocol was seen. Dropping the packet.\n"); } output_string[0] = '\0'; new_length = 0; return(NULL); } // Search for "Via" in temp_str via_ptr = strstr(temp_str, "Via"); if (via_ptr) { // Found some Via calls. Copy them into our output string. // Add a comma first output_string[jj++] = ','; // Skip past "Via " portion of string via_ptr += 4; // Copy the string across until we hit a space while (via_ptr[0] != ' ') { output_string[jj++] = via_ptr[0]; via_ptr++; } } // Add a ':' character output_string[jj++] = ':'; // Move the pointer past the "]" to the real info part of the // packet. info_ptr++; info_ptr++; // Copy the info field to the output string while (info_ptr[0] != '\0') { strncat((char *)output_string, &info_ptr[0], 1); info_ptr++; } // We end up with 0x0d characters on the end. Get rid of them. // The strtok() function will overwrite the first one found with // a '\0' character. (void)strtok((char *)output_string, "\n"); (void)strtok((char *)output_string, "\r"); *new_length = strlen((const char *)output_string); if (special_debug) { // Print out the resulting string fprintf(stderr,"AGWPE RX: %s\n", output_string); fprintf(stderr,"new_length: %d\n",*new_length); for (ii = 0; ii < (int)strlen((const char *)output_string); ii++) { fprintf(stderr,"%02x ",output_string[ii]); } fprintf(stderr,"\n"); } return(output_string); } /* Found complete AGWPE packet, 93 bytes total in frame: 00 00 00 00 55 00 00 00 'U' Packet 57 45 37 55 2d 33 00 00 ff ff WE7U-3 41 50 52 53 00 20 ec e9 6c 00 APRS 39 00 00 00 Length 00 00 00 00 20 31 .1 (36-37) 3a 46 6d 20 :Fm (38-41) 57 45 37 55 2d 33 WE7U-3 (42-space) 20 54 6f .To 20 41 50 52 53 .APRS 20 3c 55 49 .[23:13:20]. 54 65 73 74 0d 0d 00 Test. ....U...WE7U-3....APRS. ..l.9....... 1:Fm WE7U-3 To APRS [23:13:20].Test... 1:Fm WE7U-3 To APRS Via RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1 [23:51:46].Testing this darned thing!... */ //**************************************************************** // get device name only (the portion at the end of the full path) // device_name current full name of device //**************************************************************** char *get_device_name_only(char *device_name) { int i,len,done; if (device_name == NULL) { return(NULL); } done = 0; len = (int)strlen(device_name); for(i = len; i > 0 && !done; i--) { if(device_name[i] == '/') { device_name += (i+1); done = 1; } } return(device_name); } //*********************************************************** // Get Open Device // // if device is available this will return the port # // otherwise a -1 will be returned in error. //*********************************************************** int get_open_device(void) { int i, found; begin_critical_section(&devices_lock, "interface.c:get_open_device" ); found = -1; for(i = 0; i < MAX_IFACE_DEVICES && found == -1; i++) { if (devices[i].device_type == DEVICE_NONE) { found = i; break; } } end_critical_section(&devices_lock, "interface.c:get_open_device" ); if (found == -1) { popup_message(langcode("POPEM00004"),langcode("POPEM00017")); } return(found); } //*********************************************************** // Get Device Status // // this will return the device status for the port specified //*********************************************************** int get_device_status(int port) { int stat; if (begin_critical_section(&port_data_lock, "interface.c:get_device_status(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } stat = port_data[port].status; if (end_critical_section(&port_data_lock, "interface.c:get_device_status(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(stat); } //*********************************************************** // channel_data() // // Takes data read in from a port and adds it to the // incoming_data_queue. If queue is full, waits for queue to have // space before continuing. // // port # // string is the string of data // length is the length of the string. If 0 then use strlen() // on the string itself to determine the length. // // Note that decode_ax25_header() and perhaps other routines may // increase the length of the string while processing. We need to // send a COPY of our input string off to the decoding routines for // this reason, and the size of the buffer must be MAX_LINE_SIZE // for this reason also. //*********************************************************** void channel_data(int port, unsigned char *string, volatile int length) { volatile int max; struct timeval tmv; // Some messiness necessary because we're using xastir_mutex's // instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex1; pthread_mutex_t *cleanup_mutex2; // This variable defined as volatile to quash a GCC warning on some // platforms that "process_it" might be "clobbered" by a longjmp or // vfork. There is a longjmp in forked_getaddrinfo, and somehow this // function gets involved somewhere. If the compiler optimizes this // function just right, putting process_it into a register, that fouls // things up. Declaring volatile silences the warning by removing // the possibility of clobbering by longjmp. volatile int process_it = 0; // Save backup copies of the incoming string and the previous // string. Used for debugging purposes. If we get a segfault, // we can print out the last two messages received. xastir_snprintf((char *)incoming_data_copy_previous, sizeof(incoming_data_copy_previous), "%s", incoming_data_copy); xastir_snprintf((char *)incoming_data_copy, sizeof(incoming_data_copy), "Port%d:%s", port, string); max = 0; if (string == NULL) { return; } if (string[0] == '\0') { return; } if (length == 0) { // Compute length of string including terminator length = strlen((const char *)string) + 1; } // Check for excessively long packets. These might be TCP/IP // packets or concatenated APRS packets. In any case it's some // kind of garbage that we don't want to try to parse. // Note that for binary data (WX stations and KISS packets), the // strlen() function may not work correctly. if (length > MAX_LINE_SIZE) // Too long! { if (debug_level & 1) { fprintf(stderr,"\nchannel_data: LONG packet:%d, Dumping it:\n%s\n", length, string); } string[0] = '\0'; // Truncate it to zero length return; } // Install the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. We must first get the pthread_mutex_t address: cleanup_mutex1 = &output_data_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex1); // pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex1); // This protects channel_data from being run by more than one // thread at the same time. if (begin_critical_section(&output_data_lock, "interface.c:channel_data(1)" ) > 0) { fprintf(stderr,"output_data_lock, Port = %d\n", port); } if (length > 0) { // Install the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for the // thread to have this work properly. We must first get the // pthread_mutex_t address. cleanup_mutex2 = &data_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex2); // pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex2); // if (begin_critical_section(&data_lock, "interface.c:channel_data(2)" ) > 0) // fprintf(stderr,"data_lock, Port = %d\n", port); // If it's any of three types of GPS ports and is a GPRMC or // GPGGA string, just stick it in one of two global // variables for holding such strings. UpdateTime() can // come along and process/clear-out those strings at the // gps_time interval. // switch(port_data[port].device_type) { case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_NET_GPSD: // One of the three types of interfaces that might // send in a lot of GPS data constantly. Save only // GPRMC and GPGGA strings into global variables. // Drop other GPS strings on the floor. // if ( (length > 7) && (isRMC((char *)string))) { xastir_snprintf(gprmc_save_string, sizeof(gprmc_save_string), "%s", string); gps_port_save = port; process_it = 0; } else if ( (length > 7) && (isGGA((char *)string))) { xastir_snprintf(gpgga_save_string, sizeof(gpgga_save_string), "%s", string); gps_port_save = port; process_it = 0; } else { // It's not one of the GPS strings we're looking // for. It could be another GPS string, a // partial GPS string, or a full/partial TNC // string. Drop the string on the floor unless // it's an HSP interface. // if (port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { // Decode the string normally. process_it++; } } break; // We need to make sure that the variables stating that a string is // available are reset in any case. Look at how/where data_avail is // reset. We may not care if we just wait for data_avail to be // cleared before writing to the string again. default: // Not one of the above three types, decode // the string normally. process_it++; break; } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup // routine initiates an unlock before the thread dies. We // must be in deferred cancellation mode for the thread to // have this work properly. // pthread_cleanup_pop(0); if (debug_level & 1) { fprintf(stderr,"Channel data on Port %d [%s]\n",port,(char *)string); } if (process_it) { // Wait for empty space in queue while (push_incoming_data(string, length, port) && max < 5400) { sched_yield(); // Yield to other threads tmv.tv_sec = 0; tmv.tv_usec = 2; // 2 usec (void)select(0,NULL,NULL,NULL,&tmv); max++; } } } if (end_critical_section(&output_data_lock, "interface.c:channel_data(4)" ) > 0) { fprintf(stderr,"output_data_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. // pthread_cleanup_pop(0); } //********************************* START AX.25 ******************************** #ifdef HAVE_LIBAX25 // stolen from libax25-0.0.9 and modified to set digipeated bit based on '*' int my_ax25_aton_arglist(char *call[], struct full_sockaddr_ax25 *sax) { char *bp; char *addrp; int n = 0; int argp = 0; int len = 0; int star = 0; addrp = sax->fsa_ax25.sax25_call.ax25_call; do { /* Fetch one callsign token */ if ((bp = call[argp++]) == NULL) { break; } /* Check for the optional 'via' syntax */ if (n == 1 && (strcasecmp(bp, "V") == 0 || strcasecmp(bp, "VIA") == 0)) { continue; } /* Process the token (Removes the star before the ax25_aton_entry call because it would call it a bad callsign.) */ len = strlen(bp); if (len > 1 && bp[len-1] == '*') { star = 1; bp[len-1] = '\0'; } else { star = 0; } if (ax25_aton_entry(bp, addrp) == -1) { popup_message("Bad callsign!", bp); return -1; } if (n >= 1 && star) { addrp[6] |= 0x80; // set digipeated bit if we had found a star } n++; if (n == 1) { addrp = sax->fsa_digipeater[0].ax25_call; /* First digipeater address */ } else { addrp += sizeof(ax25_address); } } while (n < AX25_MAX_DIGIS && call[argp] != NULL); /* Tidy up */ sax->fsa_ax25.sax25_ndigis = n - 1; sax->fsa_ax25.sax25_family = AF_AX25; return sizeof(struct full_sockaddr_ax25); } #endif // HAVE_LIBAX25 //*********************************************************** // ui connect: change call and proto paths and reconnect net // port device to work with //*********************************************************** int ui_connect( int port, char *to[]) { int s = -1; #ifdef HAVE_LIBAX25 int sockopt; int addrlen = sizeof(struct full_sockaddr_ax25); struct full_sockaddr_ax25 axbind, axconnect; /* char *arg[2]; */ char *portcall; char temp[200]; if (to == NULL) { return(-1); } if (*to[0] == '\0') { return(-1); } /* * Handle incoming data * * Parse the passed values for correctness. */ axconnect.fsa_ax25.sax25_family = AF_AX25; axbind.fsa_ax25.sax25_family = AF_AX25; axbind.fsa_ax25.sax25_ndigis = 1; if ((portcall = ax25_config_get_addr(port_data[port].device_name)) == NULL) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00005"), port_data[port].device_name); popup_message(langcode("POPEM00004"),temp); return -1; } if (ax25_aton_entry(portcall, axbind.fsa_digipeater[0].ax25_call) == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00006"), port_data[port].device_name); popup_message(langcode("POPEM00004"), temp); return -1; } if (ax25_aton_entry(port_data[port].ui_call, axbind.fsa_ax25.sax25_call.ax25_call) == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00007"), port_data[port].ui_call); popup_message(langcode("POPEM00004"),temp); return -1; } if (my_ax25_aton_arglist(to, &axconnect) == -1) { popup_message(langcode("POPEM00004"),langcode("POPEM00008")); return -1; } /* * Open the socket into the kernel. */ if ((s = socket(AF_AX25, SOCK_DGRAM, 0)) < 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00009"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } /* * Set our AX.25 callsign and AX.25 port callsign accordingly. */ ENABLE_SETUID_PRIVILEGE; if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) { DISABLE_SETUID_PRIVILEGE; xastir_snprintf(temp, sizeof(temp), langcode("POPEM00010"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } DISABLE_SETUID_PRIVILEGE; if (devices[port].relay_digipeat) { sockopt = 1; } else { sockopt = 0; } if (setsockopt(s, SOL_AX25, AX25_IAMDIGI, &sockopt, sizeof(int))) { fprintf(stderr,"AX25 IAMDIGI setsockopt FAILED"); return -1; } if (debug_level & 2) { fprintf(stderr,"*** Connecting to UNPROTO port for transmission...\n"); } /* * Lets try and connect to the far end. */ if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00011"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } /* * We got there. */ #endif /* HAVE_LIBAX25 */ return s; } //************************************************************ // data_out_ax25() // // Send string data out ax25 port //************************************************************ static void data_out_ax25(int port, unsigned char *string) { static char ui_mycall[10]; char *temp; char *to[10]; int quantity; if (string == NULL) { return; } if (string[0] == '\0') { return; } if (begin_critical_section(&port_data_lock, "interface.c:data_out_ax25(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // Check for commands (start with Control-C) if (string[0] == (unsigned char)3) // Yes, process TNC type commands { // Look for MYCALL command if (strncmp((char *)&string[1],"MYCALL", 6) == 0) { // Found MYCALL. Snag the callsign and put it into the // structure for the port // Look for whitespace/CR/LF (end of "MYCALL") temp = strtok((char *)&string[1]," \t\r\n"); if (temp != NULL) { // Look for whitespace/CR/LF (after callsign) temp = strtok(NULL," \t\r\n"); if (temp != NULL) { substr(ui_mycall, temp, 9); xastir_snprintf(port_data[port].ui_call, sizeof(port_data[port].ui_call), "%s", ui_mycall); if (debug_level & 2) { fprintf(stderr,"*** MYCALL %s\n",port_data[port].ui_call); } } } } // Look for UNPROTO command else if (strncmp((char *)&string[1],"UNPROTO", 6) == 0) { quantity = 0; // Number of callsigns found // Look for whitespace/CR/LF (end of "UNPROTO") temp = strtok((char *)&string[1]," \t\r\n"); if (temp != NULL) // Found end of "UNPROTO" { // Find first callsign (destination call) temp = strtok(NULL," \t\r\n"); if (temp != NULL) { to[quantity++] = temp; // Store it // Look for "via" or "v" temp = strtok(NULL," \t\r\n"); while (temp != NULL) // Found it { // Look for the rest of the callsigns (up to // eight of them) temp = strtok(NULL," ,\t\r\n"); if (temp != NULL) { if (quantity < 9) { to[quantity++] = temp; } } } to[quantity] = NULL; if (debug_level & 2) { int i = 1; fprintf(stderr,"UNPROTO %s VIA ",*to); while (to[i] != NULL) { fprintf(stderr,"%s,",to[i++]); } fprintf(stderr,"\n"); } if (port_data[port].channel2 != -1) { if (debug_level & 2) { fprintf(stderr,"Write DEVICE is UP! Taking it down to reconfigure UI path.\n"); } (void)close(port_data[port].channel2); port_data[port].channel2 = -1; } if ((port_data[port].channel2 = ui_connect(port,to)) < 0) { popup_message(langcode("POPEM00004"),langcode("POPEM00012")); port_data[port].errors++; } else // Port re-opened and re-configured { if (debug_level & 2) { fprintf(stderr,"WRITE port re-opened after UI path change\n"); } } } } } } // Else not a command, write the data directly out to the port else { if (debug_level & 2) { fprintf(stderr,"*** DATA: %s\n",(char *)string); } if (port_data[port].channel2 != -1) { if (write(port_data[port].channel2, string, strlen((char *)string)) != -1) { /* we don't actually care if this returns -1 or not but newer linux systems hate when we ignore the return value of write() */ } } else if (debug_level & 2) { fprintf(stderr,"\nPort down for writing!\n\n"); } } if (end_critical_section(&port_data_lock, "interface.c:data_out_ax25(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } // fetch16bits // // Modifies: Nothing. // int fetch16bits(unsigned char *str) { int i; i = *str++; i = i << 8; i = i | *str++; return(i); } // fetch32bits // // Modifies: Nothing. // int fetch32bits(unsigned char *str) { int i; i = *str++; i = i << 8; i = i | *str++; i = i << 8; i = i | *str++; i = i << 8; i = i | *str; return(i); } //*********************************************************** // process_ax25_packet() // // bp raw packet data // len length of raw packet data // buffer buffer to write readable packet data to // buffer_size max length of buffer // // Note that db.c:decode_ax25_header does much the same thing for // Serial KISS interface packets. Consider combining the two // functions. process_ax25_packet() would be the earlier and more // thought-out function. //*********************************************************** char *process_ax25_packet(unsigned char *bp, unsigned int len, char *buffer, int buffer_size) { int i,j; unsigned int l; unsigned int digis; unsigned char source[10]; unsigned char dest[10]; unsigned char digi[10][10]; unsigned char digi_h[10]; unsigned int ssid; unsigned char message[513]; if ( (bp == NULL) || (buffer == NULL) ) { return(NULL); } /* clear buffer */ buffer[0] = '\0'; if (*bp != (unsigned char)0) { return(NULL); /* not a DATA packet */ } // We have a KISS packet here, so we know that the first // character is a flag character. Skip over it. bp++; len--; // Check the length to make sure that we don't have an empty // packet. if (!bp || !len) { return(NULL); } // Check for minimum KISS frame bytes. if (len < 15) { return(NULL); } if (bp[1] & 1) /* Compressed FlexNet Header */ { return(NULL); } /* Destination of frame */ j = 0; for(i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { dest[j++] = bp[i] >> 1; } } ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { dest[j++] = '-'; if ((ssid / 10) != 0) { dest[j++] = '1'; } ssid = (ssid % 10); dest[j++] = (unsigned char)ssid + (unsigned char)'0'; } dest[j] = '\0'; bp += 7; len -= 7; /* Source of frame */ j = 0; for(i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { source[j++] = bp[i] >> 1; } } ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { source[j++] = '-'; if ((ssid / 10) != 0) { source[j++] = '1'; } source[j++] = (unsigned char)(ssid % 10) + (unsigned char)'0'; // source[j++] = (unsigned char)ssid + (unsigned char)'0'; } source[j] = '\0'; bp += 7; len -= 7; // by KJ5O - test for proper extraction of source call and ssid // fprintf(stderr, "|KJ5O-test| %s-%d\n", source, ssid); /* Digipeaters */ digis = 0; while ((!(bp[-1] & 1)) && (len >= 7)) { /* Digi of frame */ if (digis != 10) { j = 0; for (i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { digi[digis][j++] = bp[i] >> 1; } } digi_h[digis] = (bp[6] & 0x80); ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { digi[digis][j++] = '-'; if ((ssid / 10) != 0) { digi[digis][j++] = '1'; } ssid = (ssid % 10); digi[digis][j++] = (unsigned char)ssid + (unsigned char)'0'; } digi[digis][j] = '\0'; digis++; } bp += 7; len -= 7; } if (!len) { return(NULL); } /* We are now at the primitive bit */ i = (int)(*bp++); len--; /* strip the poll-bit from the primitive */ i = i & (~0x10); /* return if this is not an UI frame (= 0x03) */ if(i != 0x03) { return(NULL); } /* no data left */ if (!len) { return(NULL); } if(*bp != (unsigned char)0xF0) // APRS PID { // We _don't_ have an APRS packet return(NULL); } // We have what looks like a valid KISS-frame containing APRS // protocol data. bp++; len--; l = 0; while (len) { i = (int)(*bp++); if ((i != (int)'\n') && (i != (int)'\r')) { if (l < 512) { message[l++] = (unsigned char)i; } } len--; } /* add terminating '\0' to allow handling as a string */ message[l] = '\0'; xastir_snprintf(buffer, buffer_size, "%s", source); /* * if there are no digis or the first digi has not handled the * packet then this is directly from the source, mark it with * a "*" in that case */ strncat(buffer, ">", buffer_size - 1 - strlen(buffer)); /* destination is at the beginning of the chain, because it is */ /* needed so MIC-E packets can be decoded correctly. */ /* this may be changed in the future but for now leave it here -FG */ strncat(buffer, (char *)dest, buffer_size - 1 - strlen(buffer)); for(i = 0; i < (int)digis; i++) { strncat(buffer, ",", buffer_size - 1 - strlen(buffer)); strncat(buffer, (char *)digi[i], buffer_size - 1 - strlen(buffer)); /* at the last digi always put a '*' when h_bit is set */ if (i == (int)(digis - 1)) { if (digi_h[i] == (unsigned char)0x80) { /* this digi must have transmitted the packet */ strncat(buffer, "*", buffer_size - 1 - strlen(buffer)); } } else { if (digi_h[i] == (unsigned char)0x80) { /* only put a '*' when the next digi has no h_bit */ if (digi_h[i + 1] != (unsigned char)0x80) { /* this digi must have transmitted the packet */ strncat(buffer, "*", buffer_size - 1 - strlen(buffer)); } } } } strncat(buffer, ":", buffer_size - 1 - strlen(buffer)); //Copy into only the free space in buffer. strncat( buffer, (char *)message, MAX_DEVICE_BUFFER - 1 - strlen(buffer)); // And null-terminate it to make sure. buffer[MAX_DEVICE_BUFFER - 1] = '\0'; return(buffer); } //********************************************************* // AX25 port INIT // // port is port# used //********************************************************* int ax25_init(int port) { /* COMMENT:tested this Seems to work fine as ETH_P_AX25 on newer linux kernels (and you see your own transmissions but it is not good for older linux kernels and FreeBSD -FG */ #ifdef HAVE_LIBAX25 int proto = PF_AX25; char temp[200]; char *dev = NULL; #endif // HAVE_LIBAX25 if (begin_critical_section(&port_data_lock, "interface.c:ax25_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } /* clear port active */ port_data[port].active = DEVICE_NOT_IN_USE; /* clear port status */ port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); #ifdef HAVE_LIBAX25 if (ax25_ports_loaded == 0) { /* port file has not been loaded before now */ if (ax25_config_load_ports() == 0) { fprintf(stderr, "ERROR: problem with axports file\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00013")); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } /* we can only load the port file once!!! so do not load again */ ax25_ports_loaded = 1; } if (port_data[port].device_name != NULL) { if ((dev = ax25_config_get_dev(port_data[port].device_name)) == NULL) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00014"), port_data[port].device_name); popup_message(langcode("POPEM00004"),temp); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } } /* COMMENT: tested this AF_INET is CORRECT -FG */ // We keep the old socket number // around now, so have to start a new socket in all cases to make it work. ENABLE_SETUID_PRIVILEGE; #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 port_data[port].channel = socket(PF_INET, SOCK_DGRAM, htons(proto)); // proto = AF_AX25 #else // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 port_data[port].channel = socket(PF_INET, SOCK_PACKET, htons(proto)); #endif // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 DISABLE_SETUID_PRIVILEGE; if (port_data[port].channel == -1) { perror("socket"); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } /* port active */ port_data[port].active = DEVICE_IN_USE; /* port status */ port_data[port].status = DEVICE_UP; // Show the latest status in the interface control dialog update_interface_list(); #else /* HAVE_LIBAX25 */ fprintf(stderr,"AX.25 support not compiled into Xastir!\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00021")); #endif /* HAVE_LIBAX25 */ if (end_critical_section(&port_data_lock, "interface.c:ax25_init(5)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(1); } //********************************* STOP AX.25 ******************************** //*************************** START SERIAL PORT FUNCTIONS ******************************** //****************************************************** // command file to tnc port // port to send config data to // Filename containing the config data //****************************************************** int command_file_to_tnc_port(int port, char *filename) { FILE *f; char line[MAX_LINE_SIZE+1]; char command[MAX_LINE_SIZE+5]; int i; char cin; int error; struct stat file_status; if (filename == NULL) { return(-1); } // Check file status if (stat(filename, &file_status) < 0) { fprintf(stderr, "Couldn't stat file: %s\n", filename); fprintf(stderr, "Skipping send to TNC\n"); return(-1); } // Check that it is a regular file if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "File is not a regular file: %s\n", filename); fprintf(stderr, "Skipping send to TNC\n"); return(-1); } error = 0; i = 0; f = fopen(filename,"r"); if (f != NULL) { int send_ctrl_C = 1; line[0] = (char)0; while (!feof(f) && error != -1) { if (fread(&cin,1,1,f) == 1) { // Check for / if (cin != (char)10 && cin != (char)13) { // If NOT or if (i < MAX_LINE_SIZE) { // Add to buffer line[i++] = cin; line[i] = (char)0; } } else // Found a or , process line { i = 0; // Check whether comment or zero-length line if (line[0] != '#' && strlen(line) > 0) { // Line looks good. Send it to the TNC. if (send_ctrl_C) { // Control-C desired xastir_snprintf(command, sizeof(command), "%c%s\r", (char)03, // Control-C line); } else { // No Control-C desired xastir_snprintf(command, sizeof(command), "%s\r", line); } if (debug_level & 2) { fprintf(stderr,"CMD:%s\n",command); } port_write_string(port,command); line[0] = (char)0; // Set flag to default condition send_ctrl_C = 1; } else // Check comment to see if it is a META { // command // Should we make these ignore white-space? if (strncasecmp(line, "##META <", 8) == 0) { // Found a META command, process it if (strncasecmp(line+8, "delay", 5) == 0) { usleep(500000); // Sleep 500ms } else if (strncasecmp(line+8, "no-ctrl-c", 9) == 0) { // Reset the flag send_ctrl_C = 0; } else { fprintf(stderr, "Unrecognized ##META command: %s\n", line); } } } } } } (void)fclose(f); } else { if (debug_level & 2) { fprintf(stderr,"Could not open TNC command file: %s\n",filename); } } return(error); } //*********************************************************** // port_dtr INIT // port is port# used // dtr 1 is down, 0 is normal(up) //*********************************************************** void port_dtr(int port, int dtr) { // It looks like we have two methods of getting this to compile on // CYGWIN, getting rid of the entire procedure contents, and getting // rid of the TIO* code. One method or the other should work to get // it compiled. We shouldn't need both. int sg; /* check for 1 or 0 */ dtr = (dtr & 0x1); if (begin_critical_section(&port_data_lock, "interface.c:port_dtr(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP && port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { port_data[port].dtr = dtr; if (debug_level & 2) { fprintf(stderr,"DTR %d\n",port_data[port].dtr); } #ifdef TIOCMGET ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMGET, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMGET sg &= 0xff; #ifdef TIOCM_DTR // ugly HPUX hack - n8ysz 20041206 #ifndef MDTR #define MDTR 99999 #if (TIOCM_DTR == 99999) #include #endif #endif // end ugly hack sg = TIOCM_DTR; #endif // TIOCM_DIR if (dtr) { dtr &= ~sg; #ifdef TIOCMBIC ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMBIC, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMBIC if (debug_level & 2) { fprintf(stderr,"Down\n"); } // statusline(langcode("BBARSTA026"),1); } else { dtr |= sg; #ifdef TIOCMBIS ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMBIS, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMBIS if (debug_level & 2) { fprintf(stderr,"UP\n"); } // statusline(langcode("BBARSTA027"),1); } } if (end_critical_section(&port_data_lock, "interface.c:port_dtr(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } //*********************************************************** // port_dtr INIT // port is port# used // dtr 1 is down, 0 is normal(up) //*********************************************************** void dtr_all_set(int dtr) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS && port_data[i].status == DEVICE_UP) { port_dtr(i,dtr); } } } //*********************************************************** // Serial port close. Remove the lockfile as well. // port is port# used //*********************************************************** int serial_detach(int port) { char fn[600]; int ok; ok = -1; if (begin_critical_section(&port_data_lock, "interface.c:serial_detach(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP) { // Close port first (void)tcsetattr(port_data[port].channel, TCSANOW, &port_data[port].t_old); if (close(port_data[port].channel) == 0) { port_data[port].status = DEVICE_DOWN; usleep(200); port_data[port].active = DEVICE_NOT_IN_USE; ok = 1; // Show the latest status in the interface control dialog update_interface_list(); } else { if (debug_level & 2) { fprintf(stderr,"Could not close port %s\n",port_data[port].device_name); } port_data[port].status = DEVICE_DOWN; usleep(200); port_data[port].active = DEVICE_NOT_IN_USE; // Show the latest status in the interface control dialog update_interface_list(); } // Delete lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (debug_level & 2) { fprintf(stderr,"Delete lock file %s\n",fn); } ENABLE_SETUID_PRIVILEGE; (void)unlink(fn); DISABLE_SETUID_PRIVILEGE; } else { // If we didn't have the port in use, for instance we // weren't able to open it, we should check whether a // lockfile exists for the port and see if another running // process owns the lockfile (the PID of the owner is inside // the lockfile). If not, remove the lockfile 'cuz it may // have been ours from this or a previous run. Note that we // can now run multiple Xastir sessions from a single user, // and the lockfiles must be kept straight between them. If // a lockfile doesn't contain a PID from a running process, // it's fair game to delete the lockfile and/or take over // the port with a new lockfile. // // if (lockfile exists) { // PID = read contents of lockfile // if (PID is running) { // Do nothing, leave the file alone // } // else { // Delete the lockfile // } // } } if (end_critical_section(&port_data_lock, "interface.c:serial_detach(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(ok); } //*********************************************************** // Serial port INIT // port is port# used //*********************************************************** int serial_init (int port) { FILE *lock; int speed; pid_t mypid = 0; pid_t lockfile_pid = 0; int lockfile_intpid; char fn[600]; uid_t user_id; struct passwd *user_info; char temp[100]; char temp1[100]; pid_t status; int ii; int myerrno; status = -9999; if (begin_critical_section(&port_data_lock, "interface.c:serial_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // clear port_channel port_data[port].channel = -1; // clear port active port_data[port].active = DEVICE_NOT_IN_USE; // clear port status port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); // Check whether we have a port with the same device already // open. Check all ports except this one and check for // DEVICE_IN_USE. If found, check whether the device_name // matches. If a match, skip initializing this port. // for (ii = 0; ii < MAX_IFACE_DEVICES; ii++) { if (ii != port) { if (port_data[ii].active == DEVICE_IN_USE) { if (strcmp(port_data[ii].device_name, port_data[port].device_name) == 0) { // Found a port with the same device_name which // is already active. Skip bringing up another // interface on the same port. return(-1); } } } } // check for lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (filethere(fn) == 1) { // Also look for pid of other process and see if it is a valid lock fprintf(stderr,"Found an existing lockfile %s for this port!\n",fn); lock = fopen(fn,"r"); if (lock != NULL) // We could open it so it must have { // been created by this userid if (fscanf(lock,"%d %99s %99s",&lockfile_intpid,temp,temp1) == 3) { lockfile_pid = (pid_t)lockfile_intpid; #ifdef HAVE_GETPGRP #ifdef GETPGRP_VOID // Won't this one get our process group instead of // the process group for the lockfile? Not of that // much use to us here. status = getpgrp(); #else // GETPGRP_VOID status = getpgrp(lockfile_pid); #endif // GETPGRP_VOID #else // HAVE_GETPGRP status = getpgid(lockfile_pid); #endif // HAVE_GETPGRP } else { // fscanf parsed the wrong number of items. // lockfile is different, perhaps created by some // other program. } (void)fclose(lock); // See whether the existing lockfile is stale. Remove // the file if it belongs to our process group or if the // PID in the file is no longer running. // // The only time we _shouldn't_ delete the file and // claim the port for our own is when the process that // created the lockfile is still running. // Get my process id mypid = getpid(); // If status = -1, the process that created the lockfile // is no longer running and of course will not match // "lockfile_pid", so we can delete it. // // If "lockfile_pid == mypid", then this currently // running instance of Xastir was the one that created // the lockfile and it is again ok to delete it. // if (status != lockfile_pid || lockfile_pid == mypid) { fprintf(stderr,"Lock is stale! Removing it.\n"); ENABLE_SETUID_PRIVILEGE; (void)unlink(fn); DISABLE_SETUID_PRIVILEGE; } else { fprintf(stderr,"Cannot open port: Another program has the lock!\n"); if (end_critical_section(&port_data_lock, "interface.c:serial_init(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return (-1); } } else // Couldn't open it, so the lock must have been { // created by another userid fprintf(stderr,"Cannot open port: Lockfile cannot be opened!\n"); if (end_critical_section(&port_data_lock, "interface.c:serial_init(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return (-1); } } // Try to open the serial port now ENABLE_SETUID_PRIVILEGE; port_data[port].channel = open(port_data[port].device_name, O_RDWR|O_NOCTTY); myerrno = errno; DISABLE_SETUID_PRIVILEGE; if (port_data[port].channel == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not open channel on port %d!\n",port); } switch (myerrno) { case EACCES: fprintf(stderr,"\tEACCESS ERROR\n"); break; case EEXIST: fprintf(stderr,"\tEEXIST ERROR\n"); break; case EFAULT: fprintf(stderr,"\tEFAULT ERROR\n"); break; case EISDIR: fprintf(stderr,"\tEISDIR ERROR\n"); break; case ELOOP: fprintf(stderr,"\tELOOP ERROR\n"); break; case EMFILE: fprintf(stderr,"\tEMFILE ERROR\n"); break; case ENAMETOOLONG: fprintf(stderr,"\tENAMETOOLONG ERROR\n"); break; case ENFILE: fprintf(stderr,"\tEMFILE ERROR\n"); break; case ENODEV: fprintf(stderr,"\tENODEV ERROR\n"); break; case ENOENT: fprintf(stderr,"\tENOENT ERROR\n"); break; case ENOMEM: fprintf(stderr,"\tENOMEM ERROR\n"); break; case ENOSPC: fprintf(stderr,"\tENOSPC ERROR\n"); break; case ENOTDIR: fprintf(stderr,"\tENOTDIR ERROR\n"); break; case ENXIO: fprintf(stderr,"\tENXIO ERROR\n"); break; case EOVERFLOW: fprintf(stderr,"\tEOVERFLOW ERROR\n"); break; case EPERM: fprintf(stderr,"\tEPERM ERROR\n"); break; case EROFS: fprintf(stderr,"\tEROFS ERROR\n"); break; case ETXTBSY: fprintf(stderr,"\tETXTBSY ERROR\n"); break; default: fprintf(stderr,"\tOTHER ERROR\n"); break; } return (-1); } // Attempt to create the lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (debug_level & 2) { fprintf(stderr,"Create lock file %s\n",fn); } ENABLE_SETUID_PRIVILEGE; lock = fopen(fn,"w"); DISABLE_SETUID_PRIVILEGE; if (lock != NULL) { // get my process id for lockfile mypid = getpid(); // get user info user_id = getuid(); user_info = getpwuid(user_id); xastir_snprintf(temp, sizeof(temp), "%s", user_info->pw_name); fprintf(lock,"%9d %s %s",(int)mypid,"xastir",temp); (void)fclose(lock); // We've successfully created our own lockfile } else { // lock failed if (debug_level & 2) { fprintf(stderr,"Warning: Failed opening LCK file! Continuing on...\n"); } /* if we can't create lockfile don't fail! if (end_critical_section(&port_data_lock, "interface.c:serial_init(5)" ) > 0) fprintf(stderr,"port_data_lock, Port = %d\n", port); return (-1);*/ } // get port attributes for new and old if (tcgetattr(port_data[port].channel, &port_data[port].t) != 0) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(6)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not get t port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcgetattr(port_data[port].channel, &port_data[port].t_old) != 0) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(7)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not get t_old port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } // set time outs port_data[port].t.c_cc[VMIN] = (cc_t)1; port_data[port].t.c_cc[VTIME] = (cc_t)2; // set port flags port_data[port].t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); port_data[port].t.c_iflag = (tcflag_t)(IGNBRK | IGNPAR); port_data[port].t.c_oflag = (0); port_data[port].t.c_lflag = (0); #ifdef CBAUD speed = (int)(port_data[port].t.c_cflag & CBAUD); #else // CBAUD speed = 0; #endif // CBAUD port_data[port].t.c_cflag = (tcflag_t)(HUPCL|CLOCAL|CREAD); port_data[port].t.c_cflag &= ~PARENB; switch (port_data[port].style) { case(0): // No parity (8N1) port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS8; break; case(1): // Even parity (7E1) port_data[port].t.c_cflag &= ~PARODD; port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS7; break; case(2): // Odd parity (7O1): port_data[port].t.c_cflag |= PARODD; port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS7; break; default: break; } port_data[port].t.c_cflag |= speed; // set input and out put speed if (cfsetispeed(&port_data[port].t, port_data[port].sp) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(8)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port input speed for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (cfsetospeed(&port_data[port].t, port_data[port].sp) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(9)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port output speed for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcflush(port_data[port].channel, TCIFLUSH) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(10)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not flush data for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcsetattr(port_data[port].channel,TCSANOW, &port_data[port].t) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(11)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } // clear port active port_data[port].active = DEVICE_IN_USE; // clear port status port_data[port].status = DEVICE_UP; // Show the latest status in the interface control dialog update_interface_list(); if (end_critical_section(&port_data_lock, "interface.c:serial_init(12)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // return good condition return (1); } //*************************** STOP SERIAL PORT FUNCTIONS ******************************** //***************************** START NETWORK FUNCTIONS ********************************* //************************************************************** // net_connect_thread() // Temporary thread used to start up a socket. //************************************************************** static void* net_connect_thread(void *arg) { int port; volatile int ok = -1; int result=-1; int flag; //int stat; struct addrinfo *res; // Some messiness necessary because we're using // xastir_mutex's instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex; if (debug_level & 2) { fprintf(stderr,"net_connect_thread start\n"); } port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); for (res = port_data[port].addr_list; res; res = res->ai_next) { pthread_testcancel(); // Check for thread termination request port_data[port].channel = socket(res->ai_family, res->ai_socktype, res->ai_protocol); pthread_testcancel(); // Check for thread termination request if (port_data[port].channel == -1) { fprintf(stderr, "Socket creation for type (%d, %d, %d) failed: %s\n", res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) ); fprintf(stderr, "This may be OK if we have more to try.\n"); continue; } if (debug_level & 2) { fprintf(stderr,"We have a socket to use\n"); } flag = 1; // Turn on the socket keepalive option (void)setsockopt(port_data[port].channel, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)); // Disable the Nagle algorithm (speeds things up) (void)setsockopt(port_data[port].channel, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); if (debug_level & 2) { fprintf(stderr,"after setsockopt\n"); } pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"calling connect(), port: %d\n", port_data[port].socket_port); } result = connect(port_data[port].channel, res->ai_addr, res->ai_addrlen); if (debug_level & 2) { fprintf(stderr,"connect result was: %d\n", result); } if(result == 0 ) { break; } if(result == -1) { fprintf(stderr, "Socket connection for interface %d type (%d, %d, %d) failed: %s\n", port, res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) ); if(res->ai_next) { fprintf(stderr, "This is OK since we have more to try.\n"); } close(port_data[port].channel); port_data[port].channel = -1; continue; } } ok = 0; pthread_testcancel(); // Check for thread termination request if (result != -1) { /* connection up */ if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net up, port %d\n",port); } port_data[port].status = DEVICE_UP; ok = 1; // Show the latest status in the interface control dialog update_interface_list(); } else /* net connection failed */ { ok = 0; if (debug_level & 2) { fprintf(stderr,"net_connect_thread():net connection failed, port %d, DEVICE_ERROR ***\n",port); } port_data[port].status = DEVICE_ERROR; // Show the latest status in the interface control dialog update_interface_list(); usleep(100000); // 100ms // Note: Old comments note that it is essential not to shut down // the socket here, because the connection didn't actually happen, // and multithreading could lead to the socket number having // already been reused elsewhere. } // Install the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. We must first get the pthread_mutex_t address: cleanup_mutex = &connect_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex); if (begin_critical_section(&connect_lock, "interface.c:net_connect_thread(2)" ) > 0) { fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port); } port_data[port].connect_status = ok; port_data[port].thread_status = 0; if (end_critical_section(&connect_lock, "interface.c:net_connect_thread(3)" ) > 0) { fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. // pthread_cleanup_pop(0); if (debug_level & 2) { fprintf(stderr,"net_connect_thread terminating itself\n"); } return(NULL); // This should kill the thread } //************************************************************** // net_init() // // This brings up a network connection // // returns -1 on hard error, 0 on time out, 1 if ok //************************************************************** int net_init(int port) { int ok; char st[200]; pthread_t connect_thread; int stat; int wait_on_connect; time_t wait_time; int gai_rc; // Return code from get address info char port_num[16]; struct addrinfo hints; if (begin_critical_section(&port_data_lock, "interface.c:net_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } /* set port active */ port_data[port].active = DEVICE_IN_USE; /* clear port status */ port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); ok = -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG; xastir_snprintf(port_num, sizeof(port_num), "%d", port_data[port].socket_port); xastir_snprintf(st, sizeof(st), langcode("BBARSTA019"), port_data[port].device_host_name); statusline(st,1); // Looking up host if(port_data[port].addr_list) { forked_freeaddrinfo(port_data[port].addr_list); port_data[port].addr_list = NULL; } gai_rc = forked_getaddrinfo(port_data[port].device_host_name, port_num, &hints, &port_data[port].addr_list, 13); if(gai_rc == 0) { /* ok try to connect */ if (begin_critical_section(&connect_lock, "interface.c:net_init(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].thread_status = 1; port_data[port].connect_status = -1; // If channel is != -1, we have a socket remaining from a previous // connect attempt. Shutdown and close that socket, then create // a new one. if (port_data[port].channel != -1) // We have a socket already { // Shut down and close the socket pthread_testcancel(); // Check for thread termination request stat = shutdown(port_data[port].channel,2); pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net Shutdown 1 Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms pthread_testcancel(); // Check for thread termination request stat = close(port_data[port].channel); pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net Close 1 Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms port_data[port].channel = -1; } if (end_critical_section(&connect_lock, "interface.c:net_init(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Creating new thread\n"); } if (pthread_create(&connect_thread, NULL, net_connect_thread, &port)) { /* error starting thread*/ ok = -1; fprintf(stderr,"Error creating net_connect thread, port %d\n",port); } busy_cursor(appshell); wait_time = sec_now() + NETWORK_WAITTIME; // Set ending time for wait wait_on_connect = 1; while (wait_on_connect && (sec_now() < wait_time)) { if (begin_critical_section(&connect_lock, "interface.c:net_init(4)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } wait_on_connect = port_data[port].thread_status; if (end_critical_section(&connect_lock, "interface.c:net_init(5)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } xastir_snprintf(st, sizeof(st), langcode("BBARSTA025"), wait_time - sec_now() ); statusline(st,1); // Host found, connecting n if (debug_level & 2) { fprintf(stderr,"%d\n", (int)(wait_time - sec_now()) ); } usleep(250000); // 250mS } ok = port_data[port].connect_status; /* thread did not return! kill it */ if ( (sec_now() >= wait_time) // Timed out || (ok != 1) ) // or connection failure of another type { if (debug_level & 2) { fprintf(stderr,"Thread exceeded it's time limit or failed to connect! Port %d\n",port); } if (begin_critical_section(&connect_lock, "interface.c:net_init(6)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Killing thread\n"); } if (pthread_cancel(connect_thread)) { // The only error code we can get here is ESRCH, which means // that the thread number wasn't found. The thread is already // dead, so let's not print out an error code. } if (sec_now() >= wait_time) // Timed out { port_data[port].connect_status = -2; if (debug_level & 2) { fprintf(stderr,"It was a timeout.\n"); } } if (end_critical_section(&connect_lock, "interface.c:net_init(7)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Thread did not return, port %d, DEVICE_ERROR ***\n",port); } // Show the latest status in the interface control dialog update_interface_list(); } if (begin_critical_section(&connect_lock, "interface.c:net_init(8)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } ok = port_data[port].connect_status; if (end_critical_section(&connect_lock, "interface.c:net_init(9)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Net ok: %d, port %d\n", ok, port); } switch (ok) { case 1: /* connection up */ xastir_snprintf(st, sizeof(st), langcode("BBARSTA020"), port_data[port].device_host_name); statusline(st,1); // Connected to ... break; case 0: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA021")); statusline(st,1); // Net Connection Failed! ok = -1; break; case -1: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA022")); statusline(st,1); // Could not bind socket break; case -2: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018")); statusline(st,1); // Net Connection timed out ok = 0; break; default: break; /*break;*/ } } else if (gai_rc == FAI_TIMEOUT) /* host lookup time out */ { xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018")); statusline(st,1); // Net Connection timed out port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Host lookup timeout, port %d, DEVICE_ERROR ***\n",port); } // Show the latest status in the interface control dialog update_interface_list(); ok = 0; } else /* Host ip look up failure (no ip address for that host) */ { xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA023")); statusline(st,1); // No IP for Host port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Host IP lookup failure, port %d, rc %d, DEVICE_ERROR ***\n",port, gai_rc); } // Show the latest status in the interface control dialog update_interface_list(); } if (end_critical_section(&port_data_lock, "interface.c:net_init(10)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"*** net_init is returning a %d ***\n",ok); } return(ok); } //************************************************************** // This shuts down a network connection // //************************************************************** int net_detach(int port) { int ok; int max; int stat; char quiti[2]; if (debug_level & 2) { fprintf(stderr,"Net detach Start, port %d\n",port); } ok = -1; max = 0; if (begin_critical_section(&port_data_lock, "interface.c:net_detach(1)" ) > 0) { fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP && port_data[port].device_type == DEVICE_NET_STREAM) { if (debug_level & 2) { fprintf(stderr,"net_detach():Found port %d up, shutting it down\n",port); } quiti[0] = (char)4; quiti[1] = (char)0; if (port_data[port].status == DEVICE_UP) { port_write_string(port,quiti); usleep(100000); // 100ms } /* wait to write */ while (port_data[port].status == DEVICE_UP && port_data[port].write_in_pos != port_data[port].write_out_pos && max < 25) { if (debug_level & 2) { fprintf(stderr,"net_detach():Waiting to finish writing data to port %d\n",port); } usleep(100000); // 100ms max++; } } /* Shut down and Close were separated but this would cause sockets to just float around */ /* we don't need to do a shut down on AX_25 devices */ if ( (port_data[port].status == DEVICE_UP) && (port_data[port].device_type != DEVICE_AX25_TNC) ) { stat = shutdown(port_data[port].channel,2); if (debug_level & 2) { fprintf(stderr,"net_detach():Net Shutdown Returned %d, port %d\n",stat,port); } } usleep(100000); // 100ms // We wish to close down the socket (so both ends of the darn thing // go away), but we want to keep the number on those systems that // re-assign the same file descriptor again. This is to prevent // cross-connects from one interface to another in Xastir (big pain!). // Close it stat = close(port_data[port].channel); if (debug_level & 2) { fprintf(stderr,"net_detach():Net Close Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms // Snag a socket again. We'll use it next time around. port_data[port].channel = socket(PF_INET, SOCK_STREAM, 0); ok = 1; } /* close down no matter what */ port_data[port].status = DEVICE_DOWN; //usleep(300); port_data[port].active = DEVICE_NOT_IN_USE; // Show the latest status in the interface control dialog update_interface_list(); if (end_critical_section(&port_data_lock, "interface.c:net_detach(2)" ) > 0) { fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Net detach stop, port %d\n",port); } return(ok); } //***************************** STOP NETWORK FUNCTIONS ********************************** // This routine changes callsign chars to proper uppercase chars or // numerals, fixes the callsign to six bytes, shifts the letters left by // one bit, and puts the SSID number into the proper bits in the seventh // byte. The callsign as processed is ready for inclusion in an // AX.25 header. // void fix_up_callsign(unsigned char *data, int data_size) { unsigned char new_call[8] = " "; // Start with seven spaces int ssid = 0; int i; int j = 0; int digipeated_flag = 0; // Check whether we've digipeated through this callsign yet. if (strstr((const char *)data,"*") != 0) { digipeated_flag++; } // Change callsign to upper-case and pad out to six places with // space characters. for (i = 0; i < (int)strlen((const char *)data); i++) { data[i] = toupper(data[i]); if (data[i] == '-') // Stop at '-' { break; } else if (data[i] == '*') { } else { new_call[j++] = data[i]; } } new_call[7] = '\0'; // Handle SSID. 'i' should now be pointing at a dash or at the // terminating zero character. if ( (i < (int)strlen((const char *)data)) && (data[i++] == '-') ) // We might have an SSID { if (data[i] != '\0') { ssid = atoi((const char *)&data[i]); } } if (ssid >= 0 && ssid <= 15) { new_call[6] = ssid | 0x30; // Set 2 reserved bits } else // Whacko SSID. Set it to zero { new_call[6] = 0x30; // Set 2 reserved bits } if (digipeated_flag) { new_call[6] = new_call[6] | 0x40; // Set the 'H' bit } // Shift each byte one bit to the left for (i = 0; i < 7; i++) { new_call[i] = new_call[i] << 1; new_call[i] = new_call[i] & 0xfe; } // Write over the top of the input string with the newly // formatted callsign xastir_snprintf((char *)data, data_size, "%s", new_call); } //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- // //WE7U // Modify the other routines that needed binary output so that they // use this routine. // void port_write_binary(int port, unsigned char *data, int length) { int ii,erd; int write_in_pos_hold; erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } // Save the current position, just in case we have trouble write_in_pos_hold = port_data[port].write_in_pos; for (ii = 0; ii < length && !erd; ii++) { // Put character into write buffer and advance pointer port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[ii]; // Check whether we need to wrap back to the start of the // circular buffer if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } // Check whether we just filled our buffer (read/write // pointers are equal). If so, exit gracefully, dumping // this string and resetting the write pointer. if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } // Restore original write_in pos and dump this string port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } // Create an AX25 frame and then turn it into a KISS packet. Dump // it into the transmit queue. // void send_ax25_frame(int port, char *source, char *destination, char *path, char *data) { unsigned char temp_source[15]; unsigned char temp_dest[15]; unsigned char temp[15]; unsigned char control[2], pid[2]; unsigned char transmit_txt[MAX_LINE_SIZE*2]; unsigned char transmit_txt2[MAX_LINE_SIZE*2]; unsigned char c; int i, j; int erd; int write_in_pos_hold; // Check whether transmits are disabled globally if (transmit_disable) { return; } // Check whether transmit has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].transmit_data != 1) { return; } transmit_txt[0] = '\0'; // Format the destination callsign xastir_snprintf((char *)temp_dest, sizeof(temp_dest), "%s", destination); fix_up_callsign(temp_dest, sizeof(temp_dest)); xastir_snprintf((char *)transmit_txt, sizeof(transmit_txt), "%s", temp_dest); // Format the source callsign xastir_snprintf((char *)temp_source, sizeof(temp_source), "%s", source); fix_up_callsign(temp_source, sizeof(temp_source)); strncat((char *)transmit_txt, (char *)temp_source, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Break up the path into individual callsigns and send them one // by one to fix_up_callsign(). If we get passed an empty path, // we merely skip this section and no path gets added to // "transmit_txt". j = 0; temp[0] = '\0'; // Start with empty path if ( (path != NULL) && (strlen(path) != 0) ) { while (path[j] != '\0') { i = 0; while ( (path[j] != ',') && (path[j] != '\0') ) { temp[i++] = path[j++]; } temp[i] = '\0'; if (path[j] == ',') // Skip over comma { j++; } fix_up_callsign(temp, sizeof(temp)); strncat((char *)transmit_txt, (char *)temp, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); } } // Set the end-of-address bit on the last callsign in the // address field transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01; // Add the Control byte control[0] = 0x03; control[1] = '\0'; strncat((char *)transmit_txt, (char *)control, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Add the PID byte pid[0] = 0xf0; pid[1] = '\0'; strncat((char *)transmit_txt, (char *)pid, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Append the information chars strncat((char *)transmit_txt, data, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Add the KISS framing characters and do the proper escapes. j = 0; transmit_txt2[j++] = KISS_FEND; // Note: This byte is where different interfaces would be // specified: transmit_txt2[j++] = 0x00; for (i = 0; i < (int)strlen((const char *)transmit_txt); i++) { c = transmit_txt[i]; if (c == KISS_FEND) { transmit_txt2[j++] = KISS_FESC; transmit_txt2[j++] = KISS_TFEND; } else if (c == KISS_FESC) { transmit_txt2[j++] = KISS_FESC; transmit_txt2[j++] = KISS_TFESC; } else { transmit_txt2[j++] = c; } } transmit_txt2[j++] = KISS_FEND; // Terminate the string, but don't increment the 'j' counter. // We don't want to send the NULL byte out the KISS interface, // just make sure the string is terminated in all cases. // transmit_txt2[j] = '\0'; //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; for (i = 0; i < j && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt2[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } // Send a KISS configuration command to the selected port. // The KISS spec allows up to 16 devices to be configured. We // support that here with the "device" input, which should be // between 0 and 15. The commands accepted are integer values: // // 0x01 TXDELAY // 0x02 P-Persistence // 0x03 SlotTime // 0x04 TxTail // 0x05 FullDuplex // 0x06 SetHardware // 0xff Exit from KISS mode (not implemented yet) // void send_kiss_config(int port, int device, int command, int value) { unsigned char transmit_txt[MAX_LINE_SIZE+1]; int i, j; int erd; int write_in_pos_hold; if (device < 0 || device > 15) { fprintf(stderr,"send_kiss_config: out-of-range value for device\n"); return; } if (command < 1 || command > 6) { fprintf(stderr,"send_kiss_config: out-of-range value for command\n"); return; } if (value < 0 || value > 255) { fprintf(stderr,"send_kiss_config: out-of-range value for value\n"); return; } // Add the KISS framing characters and do the proper escapes. j = 0; transmit_txt[j++] = KISS_FEND; transmit_txt[j++] = (device << 4) | (command & 0x0f); transmit_txt[j++] = value & 0xff; transmit_txt[j++] = KISS_FEND; // Terminate the string, but don't increment the 'j' counter. // We don't want to send the NULL byte out the KISS interface, // just make sure the string is terminated in all cases. // transmit_txt[j] = '\0'; //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; for (i = 0; i < j && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } //*********************************************************** // port_write_string() // // port is port# used // data is the string to write //*********************************************************** void port_write_string(int port, char *data) { int i,erd; int write_in_pos_hold; if (data == NULL) { return; } if (data[0] == '\0') { return; } erd = 0; if (debug_level & 2) { fprintf(stderr,"CMD:%s\n",data); } if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; // Normal Serial/Net output? if (port_data[port].device_type != DEVICE_AX25_TNC) { for (i = 0; i < (int)strlen(data) && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } } // AX.25 port output else { port_data[port].bytes_output += strlen(data); data_out_ax25(port,(unsigned char *)data); /* do for interface indicators */ if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } //*********************************************************** // port_read() // // port is port# used // // This function becomes the long-running thread that snags // characters from an interface and passes them off to the // decoding routines. One copy of this is run for each read // thread for each interface. //*********************************************************** void port_read(int port) { unsigned char cin; unsigned char buffer[MAX_DEVICE_BUFFER]; // Only used for AX.25 packets int i; struct timeval tmv; fd_set rd; int group; int binary_wx_data = 0; int max; /* * Some local variables used for checking AX.25 data - PE1DNN * * "from" is used to look up where the data comes from * "from_len" is used to keep the size of sockaddr structure * "dev" is used to keep the name of the interface that * belongs to our port/device_name */ struct sockaddr from; socklen_t from_len; #ifdef HAVE_LIBAX25 char *dev; #endif /* USE_AX25 */ if (debug_level & 2) { fprintf(stderr,"Port %d read start\n",port); } group = 0; max = MAX_DEVICE_BUFFER - 1; cin = (unsigned char)0; // We stay in this read loop until the port is shut down while(port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP) { port_data[port].read_in_pos = 0; port_data[port].scan = 1; while (port_data[port].scan && (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) && (port_data[port].status == DEVICE_UP) ) { int skip = 0; // Handle all EXCEPT AX25_TNC interfaces here if (port_data[port].device_type != DEVICE_AX25_TNC) { // Get one character port_data[port].scan = (int)read(port_data[port].channel,&cin,1); } else // Handle AX25_TNC interfaces { /* * Use recvfrom on a network socket to know from * which interface the packet came - PE1DNN */ #ifdef __solaris__ from_len = (unsigned int)sizeof(from); #else // __solaris__ from_len = (socklen_t)sizeof(from); #endif // __solaris__ port_data[port].scan = recvfrom(port_data[port].channel,buffer, sizeof(buffer) - 1, 0, &from, &from_len); } // Below is code for ALL types of interfaces if (port_data[port].scan > 0 && port_data[port].status == DEVICE_UP ) { if (port_data[port].device_type != DEVICE_AX25_TNC) { port_data[port].bytes_input += port_data[port].scan; // Add character to read buffer } // Handle all EXCEPT AX25_TNC interfaces here if (port_data[port].device_type != DEVICE_AX25_TNC) { // Do special KISS packet processing here. // We save the last character in // port_data[port].channel2, as it is // otherwise only used for AX.25 ports. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { if (port_data[port].channel2 == KISS_FESC) // Frame Escape char { if (cin == KISS_TFEND) // Transposed Frame End char { // Save this char for next time // around port_data[port].channel2 = cin; cin = KISS_FEND; } else if (cin == KISS_TFESC) // Transposed Frame Escape char { // Save this char for next time // around port_data[port].channel2 = cin; cin = KISS_FESC; } else { port_data[port].channel2 = cin; } } else if (port_data[port].channel2 == KISS_FEND) // Frame End char { // Frame start or frame end. Drop // the next character which should // either be another frame end or a // type byte. // Note this "type" byte is where it specifies which KISS interface // the packet came from. We may want to use this later for // multi-drop KISS or other types of KISS protocols. // Save this char for next time // around port_data[port].channel2 = cin; skip++; } else if (cin == KISS_FESC) // Frame Escape char { port_data[port].channel2 = cin; skip++; } else { port_data[port].channel2 = cin; } } // End of first special KISS processing // AGWPE // Process AGWPE packets here. Massage the frames so that they look // like normal serial packets to the Xastir decoding functions? // // We turn on monitoring of packets when we first connect. We now // need to throw away all but the "U" packets, which are unconnected // information packets. // // Check for enough bytes to complete a header (36 bytes). If // enough, check the datalength to see if an entire packet has been // read. If so, run that packet through a conversion routine to // convert it to a TAPR2-style packet. // // Right now we're not taking into account multiple radio ports that // AGWPE is capable of. Just assume that we'll receive from all // radio ports, but transmit out port 0. // if (port_data[port].device_type == DEVICE_NET_AGWPE) { int bytes_available = 0; long frame_length = 0; skip = 1; // Keeps next block of code from // trying to process this data. // Add it to the buffer if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (1) on %d\n",port); } port_data[port].read_in_pos = 0; } bytes_available = port_data[port].read_in_pos - port_data[port].read_out_pos; if (bytes_available < 0) { bytes_available = (bytes_available + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } if (bytes_available >= 36) { // We have a full AGWPE header, // which means we can compute the // frame length. unsigned char count[4]; int my_pointer; // Snag bytes 28-32 of the buffer and compute frame_length my_pointer = (port_data[port].read_out_pos + 28) % MAX_DEVICE_BUFFER; count[0] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[1] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[2] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[3] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; frame_length = 0; frame_length = frame_length | (count[0] ); frame_length = frame_length | (count[1] << 8); frame_length = frame_length | (count[2] << 16); frame_length = frame_length | (count[3] << 24); // Have a complete AGWPE packet? If // so, convert it to a more standard // packet format then feed it to our // decoding routines. // if (bytes_available >= (frame_length+36)) { char input_string[MAX_DEVICE_BUFFER]; char output_string[MAX_DEVICE_BUFFER]; int ii,jj,new_length; my_pointer = port_data[port].read_out_pos; jj = 0; for (ii = 0; ii < frame_length+36; ii++) { input_string[jj++] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; } // Add a terminator. We need // this for the raw packets so // that we don't end up getting // portions of strings // concatenated onto the end of // our current packet during // later processing. input_string[jj] = '\0'; my_pointer = port_data[port].read_out_pos; if ( parse_agwpe_packet((unsigned char *)input_string, frame_length+36, (unsigned char *)output_string, &new_length) ) { channel_data(port, (unsigned char *)output_string, new_length+1); // include terminator } for (i = 0; i <= port_data[port].read_in_pos; i++) { port_data[port].device_read_buffer[i] = (char)0; } port_data[port].read_in_pos = 0; } } else { // Not enough for a full header so // we can't compute frame length // yet. Do nothing until we have // more data. } } // End of new AGWPE code // We shouldn't see any AX.25 flag // characters on a KISS interface because // they are stripped out by the KISS code. // What we should see though are KISS_FEND // characters at the beginning of each // packet. These characters are where we // should break the data apart in order to // send strings to the decode routines. It // may be just fine to still break it on \r // or \n chars, as the KISS_FEND should // appear immediately afterwards in // properly formed packets. if ( (!skip) && (cin == (unsigned char)'\r' || cin == (unsigned char)'\n' || port_data[port].read_in_pos >= (MAX_DEVICE_BUFFER - 1) || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) ) || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) ) && port_data[port].data_type == 0) // If end-of-line { // End serial/net type data send it to the decoder Put a terminating // zero at the end of the read-in data port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; if (port_data[port].status == DEVICE_UP && port_data[port].read_in_pos > 0) { int length; // Compute length of string in // circular queue // KISS TNC sends binary data if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { length = port_data[port].read_in_pos - port_data[port].read_out_pos; if (length < 0) { length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } length++; } else // ASCII data { length = 0; } channel_data(port, (unsigned char *)port_data[port].device_read_buffer, length); // Length of string } for (i = 0; i <= port_data[port].read_in_pos; i++) { port_data[port].device_read_buffer[i] = (char)0; } port_data[port].read_in_pos = 0; } else if (!skip) { // Check for binary WX station data if (port_data[port].data_type == 1 && (port_data[port].device_type == DEVICE_NET_WX || port_data[port].device_type == DEVICE_SERIAL_WX)) { /* BINARY DATA input (WX data ?) */ /* check RS WX200 */ switch (cin) { case 0x8f: case 0x9f: case 0xaf: case 0xbf: case 0xcf: if (group == 0) { port_data[port].read_in_pos = 0; group = (int)cin; switch (cin) { case 0x8f: max = 35; binary_wx_data = 1; break; case 0x9f: max = 34; binary_wx_data = 1; break; case 0xaf: max = 31; binary_wx_data = 1; break; case 0xbf: max = 14; binary_wx_data = 1; break; case 0xcf: max = 27; binary_wx_data = 1; break; default: break; } } break; default: break; } if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (1) on %d\n",port); } port_data[port].read_in_pos = 0; } if (port_data[port].read_in_pos >= max) { if (group != 0) /* ok try to decode it */ { int length = 0; if (binary_wx_data) { length = port_data[port].read_in_pos - port_data[port].read_out_pos; if (length < 0) { length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } length++; } channel_data(port, (unsigned char *)port_data[port].device_read_buffer, length); } max = MAX_DEVICE_BUFFER - 1; group = 0; port_data[port].read_in_pos = 0; } } else /* Normal Data input */ { if (cin == '\0') // OWW WX daemon sends 0x00's! { cin = '\n'; } if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (2) on %d\n",port); } port_data[port].read_in_pos = 0; } } } // Ascii WX station data but no line-ends? if (port_data[port].read_in_pos > MAX_DEVICE_BUFFER_UNTIL_BINARY_SWITCH && (port_data[port].device_type == DEVICE_NET_WX || port_data[port].device_type == DEVICE_SERIAL_WX)) { /* normal data on WX not found do look at data for binary WX */ port_data[port].data_type++; port_data[port].data_type &= 1; port_data[port].read_in_pos = 0; } } // End of non-AX.25 interface code block else // Process ax25 interface data and send to the decoder { /* * Only accept data from our own interface (recvfrom will get * data from all AX.25 interfaces!) - PE1DNN */ #ifdef HAVE_LIBAX25 if (port_data[port].device_name != NULL) { if ((dev = ax25_config_get_dev(port_data[port].device_name)) != NULL) { /* if the data is not from our interface, ignore it! PE1DNN */ if(strcmp(dev, from.sa_data) == 0) { /* Received data from our interface! - process data */ if (process_ax25_packet(buffer, port_data[port].scan, port_data[port].device_read_buffer, sizeof(port_data[port].device_read_buffer)) != NULL) { port_data[port].bytes_input += strlen(port_data[port].device_read_buffer); channel_data(port, (unsigned char *)port_data[port].device_read_buffer, 0); } /* do this for interface indicator in this case we only do it for, data from the correct AX.25 port */ if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].read_in_pos += port_data[port].scan; } else { /* no buffer over runs writing a line at a time */ port_data[port].read_in_pos = 0; } } } } #endif /* HAVE_LIBAX25 */ } // End of AX.25 interface code block } else if (port_data[port].status == DEVICE_UP) /* error or close on read */ { port_data[port].errors++; if (port_data[port].scan == 0) { // Should not get this unless the device is down. NOT TRUE! // We seem to also be able to get here if we're closing/restarting // another interface. For that reason I commented out the below // statement so that this interface won't go down. The inactivity // timer solves that issue now anyway. --we7u. port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (debug_level & 2) { fprintf(stderr,"end of file on read, or signal interrupted the read, port %d\n",port); } // Show the latest status in the interface control dialog update_interface_list(); } else { if (port_data[port].scan == -1) { /* Should only get this if an real error occurs */ port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect // Show the latest status in the // interface control dialog update_interface_list(); if (debug_level & 2) { fprintf(stderr,"error on read with error no %d, or signal interrupted the read, port %d, DEVICE_ERROR ***\n", errno,port); switch (errno) { case EINTR: fprintf(stderr,"EINTR ERROR\n"); break; case EAGAIN: fprintf(stderr,"EAGAIN ERROR\n"); break; case EIO: fprintf(stderr,"EIO ERROR\n"); break; case EISDIR: fprintf(stderr,"EISDIR ERROR\n"); break; case EBADF: // Get this one when we terminate nearby threads fprintf(stderr,"EBADF ERROR\n"); break; case EINVAL: fprintf(stderr,"EINVAL ERROR\n"); break; case EFAULT: fprintf(stderr,"EFAULT ERROR\n"); break; default: fprintf(stderr,"OTHER ERROR\n"); break; } } } } } } } if (port_data[port].active == DEVICE_IN_USE) { // We need to delay here so that the thread doesn't use // high amounts of CPU doing nothing. // This select that waits on data and a timeout, so that if data // doesn't come in within a certain period of time, we wake up to // check whether the socket has gone down. Else, we go back into // the select to wait for more data or a timeout. FreeBSD has a // problem if this is less than 1ms. Linux works ok down to 100us. // We don't need it anywhere near that short though. We just need // to check whether the main thread has requested the interface be // closed, and so need to have this short enough to have reasonable // response time to the user. // Set up the select to block until data ready or 100ms // timeout, whichever occurs first. FD_ZERO(&rd); FD_SET(port_data[port].channel, &rd); tmv.tv_sec = 0; tmv.tv_usec = 100000; // 100 ms (void)select(0,&rd,NULL,NULL,&tmv); } } if (debug_level & 2) { fprintf(stderr,"Thread for port %d read down!\n",port); } } //*********************************************************** // port_write() // // port is port# used // // This function becomes the long-running thread that sends // characters to an interface. One copy of this is run for // each write thread for each interface. //*********************************************************** void port_write(int port) { int retval; struct timeval tmv; fd_set wd; int wait_max; unsigned long bytes_input; char write_buffer[MAX_DEVICE_BUFFER]; int quantity; if (debug_level & 2) { fprintf(stderr,"Port %d write start\n",port); } init_critical_section(&port_data[port].write_lock); while(port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP) { // Some messiness necessary because we're using // xastir_mutex's instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex; // Install the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for // the thread to have this work properly. We must first // get the pthread_mutex_t address: cleanup_mutex = &port_data[port].write_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex); if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } if ( (port_data[port].write_in_pos != port_data[port].write_out_pos) && port_data[port].status == DEVICE_UP) { // We have something in the buffer to transmit! // Handle control-C delay switch (port_data[port].device_type) { // Use this block for serial interfaces where we // need special delays for control-C character // processing in the TNC. case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC: // Are we trying to send a control-C? If so, wait a // special amount of time _before_ we send // it out the serial port. if (port_data[port].device_write_buffer[port_data[port].write_out_pos] == (char)0x03) { // Sending control-C. if (debug_level & 128) { fprintf(stderr,"Writing command [%x] on port %d, at pos %d\n", *(port_data[port].device_write_buffer + port_data[port].write_out_pos), port, port_data[port].write_out_pos); } wait_max = 0; bytes_input = port_data[port].bytes_input + 40; while ( (port_data[port].bytes_input != bytes_input) && (port_data[port].status == DEVICE_UP) && (wait_max < 100) ) { bytes_input = port_data[port].bytes_input; /*wait*/ FD_ZERO(&wd); FD_SET(port_data[port].channel, &wd); tmv.tv_sec = 0; tmv.tv_usec = 80000l; // Delay 80ms (void)select(0,NULL,&wd,NULL,&tmv); wait_max++; } } // End of command byte wait break; // Use this block for all other interfaces. default: // Do nothing (no delays for control-C's) break; } // End of switch // End of control-C delay code pthread_testcancel(); // Check for thread termination request // Handle method of sending data (1 or multiple chars per TX) switch (port_data[port].device_type) { // Use this block for serial interfaces where we // need character pacing and so must send one // character per write. case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: // Do the actual write here, one character // at a time for these types of interfaces. retval = (int)write(port_data[port].channel, &port_data[port].device_write_buffer[port_data[port].write_out_pos], 1); pthread_testcancel(); // Check for thread termination request if (retval == 1) // We succeeded in writing one byte { port_data[port].bytes_output++; port_data[port].write_out_pos++; if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_out_pos = 0; } } else { /* error of some kind */ port_data[port].errors++; port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (retval == 0) { /* Should not get this unless the device is down */ if (debug_level & 2) { fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port); } } else { if (retval == -1) { /* Should only get this if an real error occurs */ if (debug_level & 2) { fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port); } } } // Show the latest status in the interface control dialog update_interface_list(); } if (serial_char_pacing > 0) { // Character pacing. Delay in between // each character in milliseconds. // Convert to microseconds for this // usleep() call . usleep(serial_char_pacing * 1000); } break; // Use this block for all other interfaces where // we don't need character pacing and we can // send blocks of data in one write. default: // Do the actual write here, one buffer's // worth at a time. // Copy the data to a linear write buffer so // that we can send it all in one shot. // Need to handle the case where only a portion of the data was // written by the write() function. Perhaps just write out an error // message? quantity = 0; while (port_data[port].write_in_pos != port_data[port].write_out_pos) { write_buffer[quantity] = port_data[port].device_write_buffer[port_data[port].write_out_pos]; port_data[port].write_out_pos++; if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_out_pos = 0; } quantity++; } retval = (int)write(port_data[port].channel, write_buffer, quantity); pthread_testcancel(); // Check for thread termination request if (retval == quantity) // We succeeded in writing one byte { port_data[port].bytes_output++; } else { /* error of some kind */ port_data[port].errors++; port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (retval == 0) { /* Should not get this unless the device is down */ if (debug_level & 2) { fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port); } } else { if (retval == -1) { /* Should only get this if an real error occurs */ if (debug_level & 2) { fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port); } } } // Show the latest status in the interface control dialog update_interface_list(); } break; } // End of switch // End of handling method of sending data (1 or multiple char per TX) } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for // the thread to have this work properly. // pthread_cleanup_pop(0); } if (port_data[port].active == DEVICE_IN_USE) { // Delay here so that the thread doesn't use high // amounts of CPU doing _nothing_. Take this delay out // and the thread will take lots of CPU time. // Try to change this to a select that waits on data and a timeout, // so that if data doesn't come in within a certain period of time, // we wake up to check whether the socket has gone down. Else, we // go back into the select to wait for more data or a timeout. // FreeBSD has a problem if this is less than 1ms. Linux works ok // down to 100us. Theoretically we don't need it anywhere near that // short, we just need to check whether the main thread has // requested the interface be closed, and so need to have this short // enough to have reasonable response time to the user. // Unfortunately it has been reported that having this at 100ms // causes about 9 seconds of delay when transmitting to a KISS TNC, // so it's good to keep this short also. FD_ZERO(&wd); FD_SET(port_data[port].channel, &wd); tmv.tv_sec = 0; tmv.tv_usec = 2000; // Delay 2ms (void)select(0,NULL,&wd,NULL,&tmv); } } if (debug_level & 2) { fprintf(stderr,"Thread for port %d write down!\n",port); } } //*********************************************************** // read_access_port_thread() // // Port read thread. // port is port# used // // open threads for reading data from this port. //*********************************************************** static void* read_access_port_thread(void *arg) { int port; port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); port_read(port); return(NULL); } //*********************************************************** // write_access_port_thread() // // Port write thread. // port is port# used // // open threads for writing data to this port. //*********************************************************** static void* write_access_port_thread(void *arg) { int port; port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); port_write(port); return(NULL); } //*********************************************************** // Start port read & write threads // port is port# used // // open threads for reading and writing data to and from this // port. //*********************************************************** int start_port_threads(int port) { int ok; port_id[port] = port; if (debug_level & 2) { fprintf(stderr,"Start port %d threads\n",port); } ok = 1; if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP) { if (debug_level & 2) { fprintf(stderr,"*** Startup of read/write threads for port %d ***\n",port); } /* start the two threads */ if (pthread_create(&port_data[port].read_thread, NULL, read_access_port_thread, &port_id[port])) { /* error starting read thread*/ fprintf(stderr,"Error starting read thread, port %d\n",port); port_data[port].read_thread = 0; ok = -1; } else if (pthread_create(&port_data[port].write_thread, NULL, write_access_port_thread, &port_id[port])) { /* error starting write thread*/ fprintf(stderr,"Error starting write thread, port %d\n",port); port_data[port].write_thread = 0; ok = -1; } } else if (debug_level & 2) { fprintf(stderr,"*** Skipping startup of read/write threads for port %d ***\n",port); } if (debug_level & 2) { fprintf(stderr,"End port %d threads\n",port); } return(ok); } //*********************************************************** // Clear Port Data // int port to be cleared //*********************************************************** void clear_port_data(int port, int clear_more) { if (begin_critical_section(&port_data_lock, "interface.c:clear_port_data(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].device_type = -1; port_data[port].active = DEVICE_NOT_IN_USE; port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); port_data[port].device_name[0] = '\0'; port_data[port].device_host_name[0] = '\0'; port_data[port].addr_list = NULL; if (begin_critical_section(&connect_lock, "interface.c:clear_port_data(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].thread_status = -1; port_data[port].connect_status = -1; port_data[port].read_thread = 0; port_data[port].write_thread = 0; if (end_critical_section(&connect_lock, "interface.c:clear_port_data(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].decode_errors = 0; port_data[port].data_type = 0; port_data[port].socket_port = -1; port_data[port].device_host_pswd[0] = '\0'; if (clear_more) { port_data[port].channel = -1; } port_data[port].channel2 = -1; port_data[port].ui_call[0] = '\0'; port_data[port].dtr = 0; port_data[port].sp = -1; port_data[port].style = -1; port_data[port].errors = 0; port_data[port].bytes_input = 0l; port_data[port].bytes_output = 0l; port_data[port].bytes_input_last = 0l; port_data[port].bytes_output_last = 0l; port_data[port].port_activity = 1; // First time-period is a freebie port_data[port].read_in_pos = 0; port_data[port].read_out_pos = 0; port_data[port].write_in_pos = 0; port_data[port].write_out_pos = 0; if (end_critical_section(&port_data_lock, "interface.c:clear_port_data(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } //*********************************************************** // Clear All Port Data //*********************************************************** void clear_all_port_data(void) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { clear_port_data(i,1); } } //*********************************************************** // INIT Device names Data //*********************************************************** void init_device_names(void) { xastir_snprintf(dtype[DEVICE_NONE].device_name, sizeof(dtype[DEVICE_NONE].device_name), "%s", langcode("IFDNL00000")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_TNC].device_name), "%s", langcode("IFDNL00001")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name), "%s", langcode("IFDNL00002")); xastir_snprintf(dtype[DEVICE_SERIAL_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_GPS].device_name), "%s", langcode("IFDNL00003")); xastir_snprintf(dtype[DEVICE_SERIAL_WX].device_name, sizeof(dtype[DEVICE_SERIAL_WX].device_name), "%s", langcode("IFDNL00004")); xastir_snprintf(dtype[DEVICE_NET_STREAM].device_name, sizeof(dtype[DEVICE_NET_STREAM].device_name), "%s", langcode("IFDNL00005")); xastir_snprintf(dtype[DEVICE_AX25_TNC].device_name, sizeof(dtype[DEVICE_AX25_TNC].device_name), "%s", langcode("IFDNL00006")); xastir_snprintf(dtype[DEVICE_NET_GPSD].device_name, sizeof(dtype[DEVICE_NET_GPSD].device_name), "%s", langcode("IFDNL00007")); xastir_snprintf(dtype[DEVICE_NET_WX].device_name, sizeof(dtype[DEVICE_NET_WX].device_name), "%s", langcode("IFDNL00008")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name), "%s", langcode("IFDNL00009")); xastir_snprintf(dtype[DEVICE_SERIAL_KISS_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_KISS_TNC].device_name), "%s", langcode("IFDNL00010")); xastir_snprintf(dtype[DEVICE_NET_DATABASE].device_name, sizeof(dtype[DEVICE_NET_DATABASE].device_name), "%s", langcode("IFDNL00011")); xastir_snprintf(dtype[DEVICE_NET_AGWPE].device_name, sizeof(dtype[DEVICE_NET_AGWPE].device_name), "%s", langcode("IFDNL00012")); xastir_snprintf(dtype[DEVICE_SERIAL_MKISS_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_MKISS_TNC].device_name), "%s", langcode("IFDNL00013")); #ifdef HAVE_DB // SQL Database (experimental) xastir_snprintf(dtype[DEVICE_SQL_DATABASE].device_name, sizeof(dtype[DEVICE_SQL_DATABASE].device_name), "%s", langcode("IFDNL00014")); #endif /* HAVE_DB */ } //*********************************************************** // Delete Device. Shuts down active port/ports. //*********************************************************** int del_device(int port) { int ok; char temp[300]; long wait_time = 0; if (debug_level & 2) { fprintf(stderr,"Delete Device start\n"); } ok = -1; switch (port_data[port].device_type) { case(DEVICE_SERIAL_TNC): case(DEVICE_SERIAL_KISS_TNC): case(DEVICE_SERIAL_MKISS_TNC): case(DEVICE_SERIAL_GPS): case(DEVICE_SERIAL_WX): case(DEVICE_SERIAL_TNC_HSP_GPS): case(DEVICE_SERIAL_TNC_AUX_GPS): switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC device\n"); } begin_critical_section(&devices_lock, "interface.c:del_device" ); xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device" ); (void)command_file_to_tnc_port(port,get_data_base_dir(temp)); break; case DEVICE_SERIAL_KISS_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial KISS TNC device\n"); } break; case DEVICE_SERIAL_MKISS_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial MKISS TNC device\n"); } break; case DEVICE_SERIAL_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial GPS device\n"); } if (using_gps_position) { using_gps_position--; } break; case DEVICE_SERIAL_WX: if (debug_level & 2) { fprintf(stderr,"Close a Serial WX device\n"); } break; case DEVICE_SERIAL_TNC_HSP_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC w/HSP GPS\n"); } if (using_gps_position) { using_gps_position--; } begin_critical_section(&devices_lock, "interface.c:del_device" ); xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device" ); (void)command_file_to_tnc_port(port,get_data_base_dir(temp)); break; case DEVICE_SERIAL_TNC_AUX_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC w/AUX GPS\n"); } if (using_gps_position) { using_gps_position--; } begin_critical_section(&devices_lock, "interface.c:del_device"); sprintf(temp, "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device"); (void)command_file_to_tnc_port(port, get_data_base_dir(temp)); break; default: break; } // End of switch // Let the write queue empty before we return, to make // sure all of the data gets written out. while ( (port_data[port].write_in_pos != port_data[port].write_out_pos) && port_data[port].status == DEVICE_UP) { // Check whether we're hung waiting on the device if (wait_time > SERIAL_MAX_WAIT) { break; // Break out of the while loop } sched_yield(); usleep(25000); // 25ms wait_time = wait_time + 25000; } if (debug_level & 2) { fprintf(stderr,"Serial detach\n"); } ok = serial_detach(port); break; case(DEVICE_NET_STREAM): case(DEVICE_AX25_TNC): case(DEVICE_NET_GPSD): case(DEVICE_NET_WX): case(DEVICE_NET_DATABASE): case(DEVICE_NET_AGWPE): switch (port_data[port].device_type) { case DEVICE_NET_STREAM: if (debug_level & 2) { fprintf(stderr,"Close a Network stream\n"); } break; case DEVICE_AX25_TNC: if (debug_level & 2) { fprintf(stderr,"Close a AX25 TNC device\n"); } break; case DEVICE_NET_GPSD: if (debug_level & 2) { fprintf(stderr,"Close a Network GPSd stream\n"); } if (using_gps_position) { using_gps_position--; } break; case DEVICE_NET_WX: if (debug_level & 2) { fprintf(stderr,"Close a Network WX stream\n"); } break; case DEVICE_NET_DATABASE: if (debug_level & 2) { fprintf(stderr,"Close a Network Database stream\n"); } break; case DEVICE_NET_AGWPE: if (debug_level & 2) { fprintf(stderr,"Close a Network AGWPE stream\n"); } break; default: break; } if (debug_level & 2) { fprintf(stderr,"Net detach\n"); } ok = net_detach(port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: if (debug_level & 2) { fprintf(stderr,"Close connection to database on device %d\n",port); } if (port_data[port].status==DEVICE_UP) { ok = closeConnection(&connections[port],port); } // remove the connection from the list of open connections /* clear port active */ port_data[port].active = DEVICE_NOT_IN_USE; /* clear port status */ port_data[port].active = DEVICE_DOWN; update_interface_list(); fprintf(stderr,"Closed connection to database on device %d\n",port); break; #endif /* HAVE_DB */ default: break; } if (ok) { int retvalue; if (debug_level & 2) { fprintf(stderr,"port detach OK\n"); } usleep(100000); // 100ms if (debug_level & 2) { fprintf(stderr,"Cancel threads\n"); } if (begin_critical_section(&port_data_lock, "interface.c:del_device(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (begin_critical_section(&connect_lock, "interface.c:del_device(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (port_data[port].read_thread != 0) // If we have a thread defined { retvalue = pthread_cancel(port_data[port].read_thread); if (retvalue == ESRCH) { } } if (port_data[port].write_thread != 0) // If we have a thread defined { retvalue = pthread_cancel(port_data[port].write_thread); // we used to test retvalue against ESRCH and throw a // warning if this failed, but it got commented out a very // long time ago (around 2003). } if (end_critical_section(&connect_lock, "interface.c:del_device(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (end_critical_section(&port_data_lock, "interface.c:del_device(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } usleep(100000); // 100ms } else { if (debug_level & 2) { fprintf(stderr,"Port %d could not be closed\n",port); } } usleep(10); // Cover the case where someone plays with a GPS interface or // three and then turns it/them off again: They won't send a // posit again until the next restart or whenever they enable a // GPS interface again that has good data, unless we set this // variable again for them. if (!using_gps_position) { my_position_valid = 1; } return(ok); } #ifdef HAVE_DB /* Add a device, passing it a pointer to the ioparam * that describes the interface to start up, rather than passing * an extracted list of elements * * temporary addition for testing sql_database_functionality * when working, needs to be integrated into add_device */ int add_device_by_ioparam(int port_avail, ioparam *device) { int ok; int got_conn; int done = 0; DataRow *dr; ok = -1; if (port_avail >= 0) { switch (device->device_type) { case DEVICE_SQL_DATABASE: if (debug_level & 4096) { fprintf(stderr,"Opening a sql db connection to %s\n",device->device_host_name); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_SQL_DATABASE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", device->device_host_name); if (connections_initialized==0) { if (debug_level & 4096) { fprintf(stderr,"Calling initConnections in add_device_by_ioparam\n"); } fprintf(stderr,"adddevice, initializing connections"); connections_initialized = initConnections(); } if (debug_level & 4096) { fprintf(stderr,"Opening (in interfaces) device on port [%d] with connection [%p]\n",port_avail,&connections[port_avail]); fprintf(stderr,"device [%p][%p] device_type=%d\n",device,&device,device->device_type); } got_conn = 0; got_conn=openConnection(device, &connections[port_avail]); if (debug_level & 4096) { fprintf(stderr,"got_conn connections[%d] [%p] result=%d\n",port_avail,&connections[port_avail],got_conn); if (got_conn==1) { fprintf(stderr,"got_conn connection type %d\n",connections[port_avail].type); } } if ((got_conn == 1) && (!(connections[port_avail].type==NULL))) { if (debug_level & 4096) { fprintf(stderr, "Opened connection [%d] type=[%d]\n",port_avail,connections[port_avail].type); } ok = 1; port_data[port_avail].active = DEVICE_IN_USE; port_data[port_avail].status = DEVICE_UP; } else { port_data[port_avail].active = DEVICE_IN_USE; port_data[port_avail].status = DEVICE_ERROR; } // Show the latest status in the interface control dialog update_interface_list(); if (ok == 1) { /* if connected save top of call list */ ok = storeStationSimpleToGisDb(&connections[port_avail], n_first); if (ok==1) { if (debug_level & 4096) { fprintf(stderr,"Stored station n_first\n"); } // iterate through station_pointers and write all stations currently known dr = n_first->n_next; if (dr!=NULL) { while (done==0) { if (debug_level & 4096) { fprintf(stderr,"storing additional stations\n"); } // Need to check that stations aren't from the database // preventing creation of duplicate round trip records. ok = storeStationSimpleToGisDb(&connections[port_avail], dr); if (ok==1) { dr = dr->n_next; if (dr==NULL) { done = 1; } } else { done = 1; } } } } } } } return ok; } #endif /* HAVE_DB */ //*********************************************************** // Add Device. Starts up ports (makes them active). // dev_type is the device type to add // dev_num is the device name // dev_hst is the host name to connect to (network only) // dev_sck_p is the socket port to connect to (network only) // dev_sp is the baud rate of the port (serial only) // dev_sty is the port style (serial only) // // this will return the port # if one is available // otherwise it will return -1 if there is an error //*********************************************************** int add_device(int port_avail,int dev_type,char *dev_nm,char *passwd,int dev_sck_p, int dev_sp,int dev_sty,int reconnect, char *filter_string) { char logon_txt[600]; char init_kiss_string[5]; // KISS-mode on startup int ok; char temp[300]; char verstr[15]; if ( (dev_nm == NULL) || (passwd == NULL) ) { return(-1); } if (dev_nm[0] == '\0') { return(-1); } xastir_snprintf(verstr, sizeof(verstr), "XASTIR %s", VERSION); ok = -1; if (port_avail >= 0) { if (debug_level & 2) { fprintf(stderr,"Port Available %d\n",port_avail); } switch(dev_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: switch (dev_type) { case DEVICE_SERIAL_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC device\n"); } break; case DEVICE_SERIAL_KISS_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial KISS TNC device\n"); } break; case DEVICE_SERIAL_MKISS_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial MKISS TNC device\n"); } break; case DEVICE_SERIAL_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; case DEVICE_SERIAL_WX: if (debug_level & 2) { fprintf(stderr,"Opening a Serial WX device\n"); } break; case DEVICE_SERIAL_TNC_HSP_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC w/HSP GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; case DEVICE_SERIAL_TNC_AUX_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC w/AUX GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; default: break; } clear_port_data(port_avail,0); port_data[port_avail].device_type = dev_type; xastir_snprintf(port_data[port_avail].device_name, sizeof(port_data[port_avail].device_name), "%s", dev_nm); port_data[port_avail].sp = dev_sp; port_data[port_avail].style = dev_sty; if (dev_type == DEVICE_SERIAL_WX) { if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } } ok = serial_init(port_avail); break; case DEVICE_NET_STREAM: if (debug_level & 2) { fprintf(stderr,"Opening a Network stream\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_STREAM; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); xastir_snprintf(port_data[port_avail].device_host_pswd, sizeof(port_data[port_avail].device_host_pswd), "%s", passwd); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; ok = net_init(port_avail); if (ok == 1) { /* if connected now send password */ if (strlen(passwd)) { if (filter_string != NULL && strlen(filter_string) > 0) // Filter specified { // Please note that "filter" must be the 8th // parameter on the line in order to be // parsed properly by the servers. xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass %s vers %s filter %s%c%c", my_callsign, passwd, verstr, filter_string, '\r', '\n'); } else // No filter specified { xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass %s vers %s%c%c", my_callsign, passwd, verstr, '\r', '\n'); } } else { xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass -1 vers %s %c%c", my_callsign, verstr, '\r', '\n'); } port_write_string(port_avail,logon_txt); } break; case DEVICE_AX25_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a network AX25 TNC\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_AX25_TNC; xastir_snprintf(port_data[port_avail].device_name, sizeof(port_data[port_avail].device_name), "%s", dev_nm); ok = ax25_init(port_avail); break; case DEVICE_NET_GPSD: if (debug_level & 2) { fprintf(stderr,"Opening a network GPS using gpsd\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_GPSD; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; ok = net_init(port_avail); if (ok == 1) { // Pre-2.90 GPSD protocol xastir_snprintf(logon_txt, sizeof(logon_txt), "R\r\n"); port_write_string(port_avail,logon_txt); // Post-2.90 GPSD protocol is handled near the // bottom of this routine. // Must wait for valid GPS parsing after sending // one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); } break; case DEVICE_NET_WX: if (debug_level & 2) { fprintf(stderr,"Opening a network WX\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_WX; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { /* if connected now send call and program version */ xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n'); port_write_string(port_avail,logon_txt); } break; case DEVICE_NET_DATABASE: if (debug_level & 2) { fprintf(stderr,"Opening a network database stream\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_DATABASE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { /* if connected now send call and program version */ xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n'); port_write_string(port_avail,logon_txt); } break; case DEVICE_NET_AGWPE: if (debug_level & 2) { fprintf(stderr,"Opening a network AGWPE stream"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_AGWPE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { // If password isn't empty, send login // information // if (strlen(passwd) != 0) { // Send the login packet send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'P', // Login/Password Frame NULL, // FromCall NULL, // ToCall NULL, // Path (unsigned char *)passwd, // Data strlen(passwd)); // Length } } break; default: break; } if (ok == 1) // If port is connected... { if (debug_level & 2) { fprintf(stderr,"*** add_device: ok: %d ***\n",ok); } /* if all is ok check and start read write threads */ (void)start_port_threads(port_avail); usleep(100000); // 100ms switch (dev_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (ok == 1) { xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port_avail].tnc_up_file); (void)command_file_to_tnc_port(port_avail,get_data_base_dir(temp)); } break; case DEVICE_SERIAL_KISS_TNC: // Initialize KISS-Mode at startup if (devices[port_avail].init_kiss) { xastir_snprintf(init_kiss_string, sizeof(init_kiss_string), "\x1B@k\r"); // [ESC@K sets tnc from terminal- into kissmode port_write_string(port_avail,init_kiss_string); usleep(100000); // wait a little bit... } // Send the KISS parameters to the TNC send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay)); send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence)); send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime)); send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail)); send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex); break; //WE7U case DEVICE_SERIAL_MKISS_TNC: // Send the KISS parameters to the TNC. We'll // need to send them to the correct port for // this MKISS device. send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay)); send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence)); send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime)); send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail)); send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex); break; case DEVICE_NET_AGWPE: // Query for the AGWPE version // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'R', // Request SW Version Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length // Query for port information // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'G', // Request Port Info Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length // Ask to receive "raw" frames // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'k', // Request Raw Packets Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length /* // Send a dummy UI frame for testing purposes. // send_agwpe_packet(port_avail, atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port '\0', // type "TEST-3", // FromCall "APRS", // ToCall NULL, // Path "Test", // Data 4); // length // Send another dummy UI frame. // send_agwpe_packet(port_avail, atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port '\0', // type "TEST-3", // FromCall "APRS", // ToCall "RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1", // Path "Testing this darned thing!", // Data 26); // length */ break; case DEVICE_NET_GPSD: // Post-2.90 GPSD protocol // (Pre-2.90 protocol handled in a prior section of // this routine) xastir_snprintf(logon_txt, sizeof(logon_txt), "?WATCH={\"enable\":true,\"nmea\":true}\r\n"); port_write_string(port_avail,logon_txt); break; default: break; } } if (ok == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00015"), port_avail); popup_message(langcode("POPEM00004"),temp); port_avail = -1; } else { if (ok == 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00016"), port_avail); popup_message(langcode("POPEM00004"),temp); port_avail = -1; } } } else { popup_message(langcode("POPEM00004"),langcode("POPEM00017")); } return(port_avail); } //*********************************************************** // port status // port is the port to get status on //*********************************************************** void port_stats(int port) { if (port >= 0) { fprintf(stderr,"Port %d %s Status\n\n",port,dtype[port_data[port].device_type].device_name); fprintf(stderr,"Errors %d\n",port_data[port].errors); fprintf(stderr,"Reconnects %d\n",port_data[port].reconnects); fprintf(stderr,"Bytes in: %ld out: %ld\n",(long)port_data[port].bytes_input,(long)port_data[port].bytes_output); fprintf(stderr,"\n"); } } //*********************************************************** // startup defined ports // // port = -2: Start all defined interfaces // port = -1: Start all interfaces with "Activate on Startup" // port = 0 - MAX: Start only the one port specified //*********************************************************** void startup_all_or_defined_port(int port) { int i, override; int start; override = 0; switch (port) { case -1: // Start if "Activate on Startup" enabled start = 0; break; case -2: // Start all interfaces, period! start = 0; override = 1; break; default: // Start only the interface specified in "port" start = port; override = 1; break; } begin_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" ); for (i = start; i < MAX_IFACE_DEVICES; i++) { // Only start ports that aren't already up if ( (port_data[i].active != DEVICE_IN_USE) || (port_data[i].status != DEVICE_UP) ) { switch (devices[i].device_type) { case DEVICE_NET_STREAM: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_STREAM, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_DATABASE: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_DATABASE, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_AGWPE: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_AGWPE, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_GPSD: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_GPSD, devices[i].device_host_name, "", devices[i].sp, 0, 0, devices[i].reconnect, ""); } break; case DEVICE_SERIAL_WX: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_SERIAL_WX, devices[i].device_name, devices[i].device_host_pswd, -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_NET_WX: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_WX, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, ""); } break; case DEVICE_SERIAL_GPS: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_SERIAL_GPS, devices[i].device_name, "", -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, devices[i].device_type, devices[i].device_name, "", -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_AX25_TNC: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_AX25_TNC, devices[i].device_name, "", -1, -1, -1, 0, ""); } break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: if (debug_level & 4096) { fprintf(stderr,"Device %d Connect_on_startup=%d\n",i,devices[i].connect_on_startup); } if (devices[i].connect_on_startup == 1 || override) { ioparam *d = &devices[i]; if (debug_level & 4096) { fprintf(stderr,"Opening a sql db with device type %d\n",d->device_type); } (void)add_device_by_ioparam(i, &devices[i]); if (debug_level & 4096) { fprintf(stderr, "added device by ioparam [%d] type=[%d]\n",i,connections[i].type); } } break; #endif /* HAVE_DB */ default: break; } // End of switch } else if (debug_level & 2) { fprintf(stderr,"Skipping port %d, it's already running\n",i); } if (port != -1 && port != -2) { // We're doing a specific port #, so stop the loop i = MAX_IFACE_DEVICES+1; } } end_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" ); } //*********************************************************** // shutdown active ports // // port = -1: Shut down all active ports // port = 0 to max: Shut down the specified port if active //*********************************************************** void shutdown_all_active_or_defined_port(int port) { int i; int start; if (debug_level & 2) { fprintf(stderr,"\nshutdown_all_active_or_defined_port: %d\n\n",port); } if (port == -1) { start = 0; } else { start = port; } for( i = start; i < MAX_IFACE_DEVICES; i++ ) { if ( (port_data[i].active == DEVICE_IN_USE) && ( (port_data[i].status == DEVICE_UP) || (port_data[i].status == DEVICE_ERROR) ) ) { if (debug_level & 2) { fprintf(stderr,"Shutting down port %d \n",i); } (void)del_device(i); } if (port != -1) // Stop after one iteration if port specified { i = MAX_IFACE_DEVICES+1; } } } //************************************************************* // check ports // // Called periodically by main.c:UpdateTime() function. // Attempts to reconnect interfaces that are down. //************************************************************* void check_ports(void) { int i; int temp; for (i = 0; i < MAX_IFACE_DEVICES; i++) { switch (port_data[i].device_type) { case(DEVICE_NET_STREAM): //case(DEVICE_AX25_TNC): case(DEVICE_NET_GPSD): case(DEVICE_NET_WX): if (port_data[i].port_activity == 0) { // We've seen no activity for one time period. This variable // is updated in interface_gui.c if (port_data[i].status == DEVICE_ERROR) { // We're already in the error state, so force a reconnect port_data[i].reconnects = -1; } else if (port_data[i].status == DEVICE_UP) { // No activity on a port that's being used. // Cause a reconnect at the next iteration if (debug_level & 2) { fprintf(stderr,"check_ports(): Inactivity on port %d, DEVICE_ERROR ***\n",i); } port_data[i].status = DEVICE_ERROR; // No activity, so force a shutdown // Show the latest status in the interface control dialog update_interface_list(); // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[i].reconnects = -1; // Causes an immediate reconnect } } else // We saw activity on this port. { port_data[i].port_activity = 0; // Reset counter for next time } break; } if (port_data[i].active == DEVICE_IN_USE && port_data[i].status == DEVICE_ERROR) { if (debug_level & 2) { fprintf(stderr,"Found device error on port %d\n",i); } if (port_data[i].reconnect == 1) { port_data[i].reconnects++; temp = port_data[i].reconnects; if (temp < 1) { if (debug_level & 2) { fprintf(stderr,"Device asks for reconnect count now at %d\n",temp); } if (debug_level & 2) { fprintf(stderr,"Shutdown device %d\n",i); } shutdown_all_active_or_defined_port(i); if (debug_level & 2) { fprintf(stderr,"Starting device %d\n",i); } startup_all_or_defined_port(i); /* if error on startup */ if (port_data[i].status == DEVICE_ERROR) { port_data[i].reconnects = temp; } } else { if (debug_level & 2) { fprintf(stderr,"Device has either too many errors, or no activity at all!\n"); } port_data[i].reconnects = temp - 2; } } } } } static char unproto_path_txt[MAX_LINE_SIZE+5]; // Function which selects an unproto path in round-robin fashion. // Once we select a path, we save the number selected back to // devices[port].unprotonum so that the next time around we select // the next in the sequence. If we don't come up with a valid // unproto path, we use the unproto path: "WIDE2-2". // // Input: Port number // Output: String pointer containing unproto path // // WE7U: Should we check to make sure that there are printable // characters in the path? // unsigned char *select_unproto_path(int port) { int count; int done; int temp; int bump_up; // Set unproto path: // We look for a non-null path entry starting at the current // value of "unprotonum". The first non-null path wins. count = 0; done = 0; bump_up = 0; while (!done && (count < 3)) { temp = (devices[port].unprotonum + count) % 3; switch (temp) { case 0: if (strlen(devices[port].unproto1) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto1); done++; } else { // No path entered here. Skip this path in the // rotation for next time. bump_up++; } break; case 1: if (strlen(devices[port].unproto2) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto2); done++; } else { // No path entered here. Skip this path in // the rotation for next time. bump_up++; } break; case 2: if (strlen(devices[port].unproto3) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto3); done++; } else { // No path entered here. Skip this path in // the rotation for next time. bump_up++; } break; } // End of switch count++; } // End of while loop if (done) { // We found an unproto path. Check it for accepted values. // Output a warning message if it is beyond normal ranges, // but still allow it to be used. // if(check_unproto_path(unproto_path_txt)) { popup_message_always(langcode("WPUPCFT045"), langcode("WPUPCFT043")); } } else { // We found no entries in the unproto fields for the // interface. Set a default path of "WIDE2-2". xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "WIDE2-2"); } // Increment the path number for the next round of // transmissions. This will round-robin the paths so that all // entered paths get used. devices[port].unprotonum = (devices[port].unprotonum + 1 + bump_up) % 3; // Make sure the path is in upper-case (void)to_upper(unproto_path_txt); return((unsigned char *)unproto_path_txt); } //*********************************************************** // output_my_aprs_data // This is the function responsible for sending out my own // posits. The next function below this one handles objects, // messages and the like (output_my_data). //*********************************************************** void output_my_aprs_data(void) { char header_txt[MAX_LINE_SIZE+5]; char header_txt_save[MAX_LINE_SIZE+5]; char data_txt[MAX_LINE_SIZE+5]; char data_txt_save[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char path_txt[MAX_LINE_SIZE+5]; char *unproto_path = ""; char data_txt2[5]; struct tm *day_time; time_t sec; char my_pos[256]; char my_output_lat[MAX_LAT]; char my_output_long[MAX_LONG]; char output_net[256]; char wx_data[200]; char output_phg[10]; char output_cs[10]; char output_alt[20]; int ok; int port; char my_comment_tx[MAX_COMMENT+1]; int interfaces_ok_for_transmit = 0; char logfile_tmp_path[MAX_VALUE]; // Check whether transmits are disabled globally if (transmit_disable) { if (emergency_beacon) { // Notify the operator because emergency_beacon mode is on but // nobody will know it 'cuz global transmit is disabled. // // "Warning" // "Global transmit is DISABLED. Emergency beacons are NOT going out!" popup_message_always( langcode("POPEM00035"), langcode("POPEM00047") ); } return; } header_txt_save[0] = '\0'; data_txt_save[0] = '\0'; sec = sec_now(); // Check whether we're in emergency beacon mode. If so, add // "EMERGENCY" at the beginning of the comment field we'll // transmit. if (emergency_beacon) { strncpy(my_comment_tx, "EMERGENCY", sizeof(my_comment_tx)); my_comment_tx[sizeof(my_comment_tx)-1] = '\0'; // Terminate string } else { xastir_snprintf(my_comment_tx, sizeof(my_comment_tx), "%s", my_comment); } // Format latitude string for transmit later if (transmit_compressed_posit) // High res version { xastir_snprintf(my_output_lat, sizeof(my_output_lat), "%s", my_lat); } else // Create a low-res version of the latitude string { long my_temp_lat; char temp_data[20]; // Convert to long my_temp_lat = convert_lat_s2l(my_lat); // Convert to low-res string convert_lat_l2s(my_temp_lat, temp_data, sizeof(temp_data), CONVERT_LP_NORMAL); xastir_snprintf(my_output_lat, sizeof(my_output_lat), "%c%c%c%c.%c%c%c", temp_data[0], temp_data[1], temp_data[3], temp_data[4], temp_data[6], temp_data[7], temp_data[8]); } (void)output_lat(my_output_lat,transmit_compressed_posit); if (debug_level & 128) { fprintf(stderr,"OUT LAT <%s>\n",my_output_lat); } // Format longitude string for transmit later if (transmit_compressed_posit) // High res version { xastir_snprintf(my_output_long, sizeof(my_output_long), "%s", my_long); } else // Create a low-res version of the longitude string { long my_temp_long; char temp_data[20]; // Convert to long my_temp_long = convert_lon_s2l(my_long); // Convert to low-res string convert_lon_l2s(my_temp_long, temp_data, sizeof(temp_data), CONVERT_LP_NORMAL); xastir_snprintf(my_output_long, sizeof(my_output_long), "%c%c%c%c%c.%c%c%c", temp_data[0], temp_data[1], temp_data[2], temp_data[4], temp_data[5], temp_data[7], temp_data[8], temp_data[9]); } (void)output_long(my_output_long,transmit_compressed_posit); if (debug_level & 128) { fprintf(stderr,"OUT LONG <%s>\n",my_output_long); } output_net[0]='\0'; // Make sure this array at least starts initialized. begin_critical_section(&devices_lock, "interface.c:output_my_aprs_data" ); // Iterate across the ports, set up each device's headers/paths/handshakes, // then transmit the posit if the port is open and tx is enabled. for (port = 0; port < MAX_IFACE_DEVICES; port++) { // First send any header/path info we might need out the port, // set up TNC's to the proper mode, etc. ok = 1; switch (port_data[port].device_type) { // case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: output_net[0]='\0'; // We don't need this header for AGWPE break; case DEVICE_NET_STREAM: xastir_snprintf(output_net, sizeof(output_net), "%s>%s,TCPIP*:", my_callsign, VERSIONFRM); break; case DEVICE_SERIAL_TNC_HSP_GPS: /* make dtr normal (talk to TNC) */ if (port_data[port].status == DEVICE_UP) { port_dtr(port,0); } /* Falls through. */ case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: /* clear this for a TNC */ output_net[0] = '\0'; /* Set my call sign */ xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s\r", '\3', "MYCALL", my_callsign); // Send the callsign out to the TNC only if the interface is up and tx is enabled??? // We don't set it this way for KISS TNC interfaces. if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, unproto_path); xastir_snprintf(header_txt_save, sizeof(header_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, unproto_path); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); // Send the header data to the TNC. This sets the // unproto path that'll be used by the next packet. // We don't set it this way for KISS TNC interfaces. if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Set converse mode according to device's configuration setting. // xastir_snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', devices[port].device_converse_string); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Delay a bit if the user clicked on the "Add Delay" // togglebutton in the port's interface properties dialog. // This is primarily needed for KAM TNCs, which will fail to // go into converse mode if there is no delay here. if (devices[port].tnc_extra_delay != 0) { usleep(devices[port].tnc_extra_delay); } break; default: /* port has unknown device_type */ ok = 0; break; } // End of switch // Set up some more strings for later transmission /* send station info */ output_cs[0] = '\0'; output_phg[0] = '\0'; output_alt[0] = '\0'; if (transmit_compressed_posit) xastir_snprintf(my_pos, sizeof(my_pos), "%s", compress_posit(my_output_lat, my_group, my_output_long, my_symbol, my_last_course, my_last_speed, // In knots my_phg)); else /* standard non compressed mode */ { xastir_snprintf(my_pos, sizeof(my_pos), "%s%c%s%c", my_output_lat, my_group, my_output_long, my_symbol); /* get PHG, if used for output */ if (strlen(my_phg) >= 6) xastir_snprintf(output_phg, sizeof(output_phg), "%s", my_phg); /* get CSE/SPD, Always needed for output even if 0 */ xastir_snprintf(output_cs, sizeof(output_cs), "%03d/%03d", my_last_course, my_last_speed); // Speed in knots /* get altitude */ if (my_last_altitude_time > 0) xastir_snprintf(output_alt, sizeof(output_alt), "/A=%06ld", my_last_altitude); } // And set up still more strings for later transmission switch (output_station_type) { case(1): /* APRS_MOBILE LOCAL TIME */ day_time = localtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02d/%s%s%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(2): /* APRS_MOBILE ZULU DATE-TIME */ day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dz%s%s%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(3): /* APRS_MOBILE ZULU TIME w/SEC */ day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dh%s%s%s%s", day_time->tm_hour, day_time->tm_min, day_time->tm_sec, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(4): /* APRS position with WX data, no timestamp */ sec = wx_tx_data1(wx_data, sizeof(wx_data)); if (sec != 0) { xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%c%s%s", aprs_station_message_type, my_pos, wx_data); // WE7U2: // There's no limit on the max size for this kind of packet except // for the AX.25 limit of 256 bytes! // // Truncate at max length for this type of APRS // packet. Left the compressed/uncompressed // "if" statement here in case we need to change // this in the future due to spec changes. // Consistent with the rest of the code in this // function which does similar things. // if (transmit_compressed_posit) { if (strlen(data_txt_save) > 256) { data_txt_save[256] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 256) { data_txt_save[256] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string } else { /* default to APRS FIXED if no wx data. No timestamp */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt), output_net); } break; case(5): /* APRS position with ZULU DATE-TIME and WX data */ sec = wx_tx_data1(wx_data,sizeof(wx_data)); if (sec != 0) { day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dz%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, wx_data); // WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string } else { /* default to APRS FIXED if no wx data */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt),output_net); } break; /* default to APRS FIXED if no wx data */ case(0): default: /* APRS_FIXED */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt),output_net); break; } if (ok) { // Here's where the actual transmit of the posit occurs. The // transmit string has been set up in "data_txt" by this point. // If transmit or posits have been turned off, don't transmit posit if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { interfaces_ok_for_transmit++; // WE7U: Change so that path is passed as well for KISS TNC // interfaces: header_txt_save would probably be the one to pass, // or create a new string just for KISS TNC's. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { // Note: This one has callsign & destination in the string // Transmit the posit out the KISS interface send_ax25_frame(port, my_callsign, // source VERSIONFRM, // destination path_txt, // path data_txt); // data } //WE7U:AGWPE else if (port_data[port].device_type == DEVICE_NET_AGWPE) { // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); // We need to remove the complete AX.25 header from data_txt before // we call this routine! Instead put the digipeaters into the // ViaCall fields. We do this above by setting output_net to '\0' // before creating the data_txt string. send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort '\0', // Type of frame (unsigned char *)my_callsign, // source (unsigned char *)VERSIONFRM, // destination (unsigned char *)unproto_path, // Path, (unsigned char *)data_txt, // Data strlen(data_txt) - 1); // Skip \r } else { // Not a Serial KISS TNC interface port_write_string(port, data_txt); // Transmit the posit } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",port,data_txt); } /* add new line on network data */ if (port_data[port].device_type == DEVICE_NET_STREAM) { xastir_snprintf(data_txt2, sizeof(data_txt2), "\n"); // Transmit a newline port_write_string(port, data_txt2); } // Put our transmitted packet into the Incoming Data // window as well. This way we can see both sides of a // conversation. data_port == -1 for x_spider port, // normal interface number otherwise. -99 to get a "**" // display meaning all ports. // // For packets that we're igating we end up with a CR or // LF on the end of them. Remove that so the display // looks nice. strcpy(temp, my_callsign); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ">"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, VERSIONFRM); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ","); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, unproto_path); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ":"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data_txt); temp[sizeof(temp)-1] = '\0'; // Terminate string makePrintable(temp); packet_data_add("TX ", temp, port); } else { } } // End of posit transmit: "if (ok)" } // End of big loop end_critical_section(&devices_lock, "interface.c:output_my_aprs_data" ); // Check the interfaces_ok_for_transmit variable if we're in // emergency_beacon mode. If we didn't transmit out any interfaces, alert // the operator so that they can either enable interfaces or get emergency // help in some other manner. // if (emergency_beacon) { if (interfaces_ok_for_transmit) { // Beacons are going out in emergency beacon mode. Alert the // operator so that he/she knows they've enabled that mode. // // "Emergency Beacon Mode" // "EMERGENCY BEACON MODE, transmitting every 60 seconds!" popup_message_always( langcode("POPEM00048"), langcode("POPEM00049") ); } else // Emergency beacons are not going out for some reason { // Notify the operator because emergency_beacon mode is on but // nobody will know it 'cuz there are no interfaces enabled for // transmit. // // "Warning" // "Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!" popup_message_always( langcode("POPEM00035"), langcode("POPEM00050") ); } } // This will log a posit in the general format for a network interface // whether or not any network interfaces are currently up. if (log_net_data) { strcpy(data_txt, my_callsign); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ">"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, VERSIONFRM); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ",TCPIP*:"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } if (enable_server_port && !transmit_disable && !posit_tx_disable) { // Send data to the x_spider server strcpy(data_txt, my_callsign); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ">"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, VERSIONFRM); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ",TCPIP*:"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string if (writen(pipe_xastir_to_tcp_server, data_txt, strlen(data_txt)) != (int)strlen(data_txt)) { fprintf(stderr, "my_aprs_data: Writen error: %d\n", errno); } // Terminate it with a linefeed if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1) { fprintf(stderr, "my_aprs_data: Writen error: %d\n", errno); } } // End of x_spider server send code // Note that this will only log one TNC line per transmission now matter // how many TNC's are defined. It's a representative sample of what we're // sending out. At least one TNC interface must be enabled in order to // have anything output to the log file here. if (log_tnc_data) { if (header_txt_save[0] != '\0') { strcpy(data_txt, header_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } } } //***************************************************************************** // output_my_data() // // 1) Used to send local messages/objects/items. Cooked mode. // 2) Used from output_igate_net(), igating from RF to the 'net. Raw mode. // 3) Used from output_igate_rf() to igate from the 'net to RF. Cooked mode. // 4) Used from output_nws_igate_rf() to send NWS packets out RF. Cooked mode. // 5) Used for queries and responses. Cooked mode. // // Parameters: // message: the message data to send // port: the port transmitting through, or -1 for all // type: 0 for my data, 1 for raw data (Cooked/Raw) // loopback_only: 0 for transmit/loopback, 1 for loopback only // use_igate_path: 0 for standard unproto paths, 1 for igate path // path: Set to non-NULL if special path selected for messaging // // This function sends out messages/objects/bulletins/etc. // This one currently tries to do local logging even if // transmit is disabled. //***************************************************************************** void output_my_data(char *message, int incoming_port, int type, int loopback_only, int use_igate_path, char *path) { char data_txt[MAX_LINE_SIZE+5]; char data_txt_save[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char path_txt[MAX_LINE_SIZE+5]; char *unproto_path = ""; char output_net[256]; int ok, start, finish, port; int done; char logfile_tmp_path[MAX_VALUE]; // Check whether transmits are disabled globally if (transmit_disable && !loopback_only) { return; } //// cbell- if path is null, strlen/printf segv in solaris if (path == NULL) { path = ""; } if (debug_level & 1) { fprintf(stderr, "Sending out port: %d, type: %d, path: %s\n", incoming_port, type, path); } if (message == NULL) { return; } if (message[0] == '\0') { return; } data_txt_save[0] = '\0'; if (incoming_port == -1) // Send out all of the interfaces { start = 0; finish = MAX_IFACE_DEVICES; } else // Only send out the chosen interface { start = incoming_port; finish = incoming_port + 1; } begin_critical_section(&devices_lock, "interface.c:output_my_data" ); for (port = start; port < finish; port++) { ok = 1; if (type == 0) // my data { switch (port_data[port].device_type) { // case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: output_net[0] = '\0'; // Clear header break; case DEVICE_NET_STREAM: if (debug_level & 1) { fprintf(stderr,"%d Net\n",port); } xastir_snprintf(output_net, sizeof(output_net), "%s>%s,TCPIP*:", my_callsign, VERSIONFRM); break; case DEVICE_SERIAL_TNC_HSP_GPS: if (port_data[port].status == DEVICE_UP && !loopback_only && !transmit_disable) { port_dtr(port,0); // make DTR normal (talk to TNC) } /* Falls through. */ case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: if (debug_level & 1) { fprintf(stderr,"%d AX25 TNC\n",port); } output_net[0] = '\0'; // clear this for a TNC /* Set my call sign */ xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s\r", '\3', "MYCALL", my_callsign); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(10000); // 10ms } done = 0; // Set unproto path. First check whether we're // to use the igate path. If so and the path // isn't empty, skip the rest of the path selection: if ( (use_igate_path) && (strlen(devices[port].unproto_igate) > 0) ) { // WE7U: Should we check here and in the following path // selection code to make sure that there are printable characters // in the path? Also: Output_my_aprs_data() has nearly identical // path selection code. Fix it in one place, fix it in the other. // Check whether igate path is socially // acceptable. Output warning if not, but // still allow the transmit. if(check_unproto_path(devices[port].unproto_igate)) { popup_message_always(langcode("WPUPCFT046"), langcode("WPUPCFT043")); } xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, devices[port].unproto_igate); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, devices[port].unproto_igate); xastir_snprintf(path_txt, sizeof(path_txt), "%s", devices[port].unproto_igate); done++; } // Check whether a path was passed to us as a // parameter: if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s\r", '\3', "UNPROTO", VERSIONFRM); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s:", my_callsign, VERSIONFRM); } else { xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, path); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, path); } if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path path_txt[0] = '\0'; // Empty path } else { xastir_snprintf(path_txt, sizeof(path_txt), "%s", path); } done++; // If "DEFAULT PATH" was passed to us, then // we're not done yet. // if (strncmp(path, "DEFAULT PATH", 12) == 0) { done = 0; } } if (!done) { // Set unproto path: Get next unproto path // in sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, unproto_path); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, unproto_path); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); done++; } if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(10000); // 10ms } // Set converse mode using approprate string from configuration. xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', devices[port].device_converse_string); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(20000); // 20ms } break; default: /* unknown */ ok = 0; break; } // End of switch } else // Type == 1, raw data. Probably igating something... { output_net[0] = '\0'; } if (ok) { /* send data */ xastir_snprintf(data_txt, sizeof(data_txt), "%s%s\r", output_net, message); if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { // WE7U: Change so that path is passed as well for KISS TNC // interfaces: data_txt_save would probably be the one to pass, // or create a new string just for KISS TNC's. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { // Transmit send_ax25_frame(port, my_callsign, // source VERSIONFRM, // destination path_txt, // path data_txt); // data } //WE7U:AGWPE else if (port_data[port].device_type == DEVICE_NET_AGWPE) { // Set unproto path. First check whether we're // to use the igate path. If so and the path // isn't empty, skip the rest of the path selection: if ( (use_igate_path) && (strlen(devices[port].unproto_igate) > 0) ) { // Check whether igate path is socially // acceptable. Output warning if not, but // still allow the transmit. if(check_unproto_path(devices[port].unproto_igate)) { popup_message_always(langcode("WPUPCFT046"), langcode("WPUPCFT043")); } xastir_snprintf(path_txt, sizeof(path_txt), "%s", devices[port].unproto_igate); } // Check whether a path was passed to us as a // parameter: else if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DEFAULT PATH", 12) == 0) { unproto_path = (char *)select_unproto_path(port); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); } else if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path path_txt[0] = '\0'; // Empty string // WE7U // TEST THIS TO SEE IF IT WORKS ON AGWPE TO HAVE NO PATH } else { xastir_snprintf(path_txt, sizeof(path_txt), "%s", path); } } else { // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); } // We need to remove the complete AX.25 header from data_txt before // we call this routine! Instead put the digipeaters into the // ViaCall fields. We do this above by setting output_net to '\0' // before creating the data_txt string. send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort '\0', // Type of frame (unsigned char *)my_callsign, // source (unsigned char *)VERSIONFRM, // destination (unsigned char *)path_txt, // Path, (unsigned char *)data_txt, // Data strlen(data_txt) - 1); // Skip \r } else { // Not a Serial KISS TNC interface port_write_string(port, data_txt); // Transmit } if (debug_level & 1) fprintf(stderr,"Sending to interface:%d, %s\n", port, data_txt); // Put our transmitted packet into the Incoming Data // window as well. This way we can see both sides of a // conversation. data_port == -1 for x_spider port, // normal interface number otherwise. -99 to get a "**" // display meaning all ports. // // For packets that we're igating we end up with a CR or // LF on the end of them. Remove that so the display // looks nice. // // Check whether a path was passed to us as a // parameter: if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DEFAULT PATH", 12) == 0) { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, unproto_path, message); } else if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path xastir_snprintf(temp, sizeof(temp), "%s>%s:%s", my_callsign, VERSIONFRM, message); } else { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, path, message); } } else { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, unproto_path, message); } makePrintable(temp); packet_data_add("TX ", temp, port); } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",port,data_txt); } /* add newline on network data */ if (port_data[port].device_type == DEVICE_NET_STREAM) { xastir_snprintf(data_txt, sizeof(data_txt), "\n"); if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); } } else { } } // if (incoming_port != -1) // port = MAX_IFACE_DEVICES+1; // process only one port } end_critical_section(&devices_lock, "interface.c:output_my_data" ); // This will log a posit in the general format for a network interface // whether or not any network interfaces are currently up. xastir_snprintf(data_txt, sizeof(data_txt), "%s>%s,TCPIP*:%s", my_callsign, VERSIONFRM, message); if (debug_level & 2) { fprintf(stderr,"output_my_data: Transmitting and decoding: %s\n", data_txt); } if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); // Note that this will only log one TNC line per transmission now matter // how many TNC's are defined. It's a representative sample of what we're // sending out. At least one TNC interface must be enabled in order to // have anything output to the log file here. if (data_txt_save[0] != '\0') { xastir_snprintf(data_txt, sizeof(data_txt), "%s%s", data_txt_save, message); if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } if (enable_server_port && !loopback_only && !transmit_disable) { // Send data to the x_spider server if (type == 0) // My data, add a header { xastir_snprintf(data_txt, sizeof(data_txt), "%s>%s,TCPIP*:%s", my_callsign, VERSIONFRM, message); } else // Not my data, don't add a header { xastir_snprintf(data_txt, sizeof(data_txt), "%s", message); } if (writen(pipe_xastir_to_tcp_server, data_txt, strlen(data_txt)) != (int)strlen(data_txt)) { fprintf(stderr, "output_my_data: Writen error: %d\n", errno); } // Terminate it with a linefeed if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1) { fprintf(stderr, "output_my_data: Writen error: %d\n", errno); } } // End of x_spider server send code // Decode our own transmitted packets. // Note that this function call is destructive to the first parameter. // This is why we call it _after_ we call the log_data functions. // // This must be the "L" packet we see in the View->Messages // dialog. We don't see a "T" packet (for TNC) and we only see // "I" packets if we re-receive our own packet from the internet // feeds. if (incoming_port == -1) // We were sending to all ports { // Pretend we received it from port 1 decode_ax25_line( data_txt, DATA_VIA_LOCAL, 1, 1); } else // We were sending to a specific port { decode_ax25_line( data_txt, DATA_VIA_LOCAL, incoming_port, 1); } } //***************************************************************************** // output_waypoint_data() // // message: the message data to send // // This function sends out waypoint creation strings to GPS // interfaces capable of dealing with it. // //***************************************************************************** void output_waypoint_data(char *message) { char data_txt[MAX_LINE_SIZE+5]; int ok, start, finish, i; if (message == NULL) { return; } if (message[0] == '\0') { return; } if (debug_level & 1) { fprintf(stderr,"Sending to GPS interfaces: %s\n", message); } start = 0; finish = MAX_IFACE_DEVICES; begin_critical_section(&devices_lock, "interface.c:output_waypoint_data" ); for (i = start; i < finish; i++) { ok = 1; switch (port_data[i].device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: port_dtr(i,1); // make DTR active (select GPS) break; case DEVICE_SERIAL_GPS: break; default: /* unknown */ ok = 0; break; } // End of switch if (ok) // Found a GPS interface { /* send data */ xastir_snprintf(data_txt, sizeof(data_txt), "%s\r\n", message); if (port_data[i].status == DEVICE_UP) { port_write_string(i,data_txt); usleep(250000); // 0.25 secs if (debug_level & 1) { fprintf(stderr,"Sending to interface:%d, %s\n",i,data_txt); } } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",i,data_txt); } if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { port_dtr(i,0); // make DTR inactive (select TNC data) } } } end_critical_section(&devices_lock, "interface.c:output_waypoint_data" ); } // Added by KB6MER for KAM XL(SERIAL_TNC_AUX_GPS) support // buf is a null terminated string // returns buf as a null terminated string after cleaning. // Currently: // removes leading 'cmd:' prompts from TNC if needed // Can be used to add any additional data cleaning functions desired. // Currently only called for SERIAL_TNC_AUX_GPS, but could be added // to other device routines to improve packet decode on other devices. // // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void tnc_data_clean(char *buf) { if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // strncpy is ok here as long as nulls not in data. We // null-terminate it ourselves to make sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_data_clean: called to clean %s\n", filtered_data); } while (!strncmp(buf,"cmd:",4)) { int ii; // We're _shortening_ the string here, so we don't need to // know the length of the buffer unless it has no '\0' // terminator to begin with! In that one case we could run // off the end of the string and get a segfault or cause // other problems. for (ii = 0; ; ii++) { buf[ii] = buf[ii+4]; if (buf[ii] == '\0') { break; } } } if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as long as nulls not // in data. We null-terminate it ourselves to make sure it // is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_data_clean: clean result %s\n", filtered_data); } } // Added by KB6MER for KAM XL (SERIAL_TNC_AUX_GPS) support // buf is a null terminated string. // port is integer offset into port_data[] array of iface data (see interface.h) // returns int 0=AX25, 1=GPS // Tries to guess from the contents of buf whether it represents data from // the GPS or data from an AX25 packet. // // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // int tnc_get_data_type(char *buf, int UNUSED(port) ) { register int i; int type=1; // Don't know what it is yet. Assume NMEA for now. if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as long as nulls not // in data. We null-terminate it ourselves to make sure it // is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: parsing %s\n", filtered_data); } // First, let's look for NMEA-ish things. if (buf[0]=='$') { //This looks kind of NMEA-ish, let's check for known message type //headers ($P[A-Z][A-Z][A-Z][A-Z] or $GP[A-Z][A-Z][A-Z]) if(buf[1]=='P') { for(i=2; i<=5; i++) { if (buf[i]<'A' || buf[i]>'Z') { type=0; // Disqualified, not valid NMEA-0183 if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as // long as nulls not in data. We // null-terminate it ourselves to make // sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n", filtered_data); } } } } else if(buf[1]=='G' && buf[2]=='P') { for(i=3; i<=5; i++) { if (buf[i]<'A' || buf[i]>'Z') { type=0; // Disqualified, not valid NMEA-0183 if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as // long as nulls not in data. We // null-terminate it ourselves to make // sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n", filtered_data); } } } } } else // Must be APRS data { type = 0; } if (debug_level & 1) { if (type == 0) { fprintf(stderr,"APRS data\n"); } else { fprintf(stderr,"NMEA data\n"); } } return(type); } /* This function is reused several times in the output_my_aprs_data function to create a string for the fixed aprs station, no timestamp. It is created to do away with three instances of cut/pasted code that complicated maintenance and readability. */ void output_fixed_position(char *data_txt_save, size_t data_txt_save_size, char *my_pos, char * output_phg, char * output_alt, char *my_comment_tx, char *data_txt, size_t data_txt_size, char *output_net) { xastir_snprintf(data_txt_save, data_txt_save_size, "%c%s%s%s%s", aprs_station_message_type, my_pos, output_phg, output_alt, my_comment_tx); // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 54) { data_txt_save[54] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 63) { data_txt_save[63] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", data_txt_save_size-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[data_txt_size-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[data_txt_size-1] = '\0'; // Terminate string } Xastir-Release-2.2.2/src/interface.h000066400000000000000000000336001501463444000172500ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_INTERFACE_H #define __XASTIR_INTERFACE_H #include #include #include "util.h" #include "xastir.h" #define MAX_DEVICE_NAME 128 #define MAX_DEVICE_BUFFER 4096 #define MAX_DEVICE_BUFFER_UNTIL_BINARY_SWITCH 700 #define MAX_DEVICE_HOSTNM 40 #define MAX_DEVICE_HOSTPW 40 #define MAX_IFACE_DEVICES 15 #define NET_CONNECT_TIMEOUT 20 #define DEFAULT_GPS_RETR 0x05 /* CTRL-E */ // Define a 60 second max wait on a serial port (in microseconds) #define SERIAL_MAX_WAIT 60000000 // KISS Protocol Special Characters & Commands: #define KISS_FEND 0xc0 // Frame End #define KISS_FESC 0xdb // Frame Escape #define KISS_TFEND 0xdc // Transposed Frame End #define KISS_TFESC 0xdd // Transposed Frame Escape #define KISS_DATA 0x00 #define KISS_TXDELAY 0x01 #define KISS_PERSISTENCE 0x02 #define KISS_SLOTTIME 0x03 #define KISS_TXTAIL 0x04 #define KISS_FULLDUPLEX 0x05 #define KISS_SETHARDWARE 0x06 #define KISS_RETURN 0xff #define MAX_IFACE_DEVICE_TYPES 15 /* Define Device Types */ enum Device_Types { DEVICE_NONE, DEVICE_SERIAL_TNC, DEVICE_SERIAL_TNC_HSP_GPS, DEVICE_SERIAL_GPS, DEVICE_SERIAL_WX, DEVICE_NET_STREAM, DEVICE_AX25_TNC, DEVICE_NET_GPSD, DEVICE_NET_WX, DEVICE_SERIAL_TNC_AUX_GPS, // KB6MER -> KAM XL or other TNC w/GPS on AUX port DEVICE_SERIAL_KISS_TNC, // KISS TNC on serial port (not ax.25 kernel device) DEVICE_NET_DATABASE, DEVICE_NET_AGWPE, DEVICE_SERIAL_MKISS_TNC, // Multi-port KISS TNC, like the Kantronics KAM DEVICE_SQL_DATABASE // SQL server (MySQL/Postgis) database }; enum Device_Active { DEVICE_NOT_IN_USE, DEVICE_IN_USE }; enum Device_Status { DEVICE_DOWN, DEVICE_UP, DEVICE_ERROR }; typedef struct { int device_type; /* device type */ int active; /* channel in use */ int status; /* current status (up or down) */ char device_name[MAX_DEVICE_NAME+1]; /* device name */ char device_host_name[MAX_DEVICE_HOSTNM+1]; /* device host name for network */ struct addrinfo *addr_list; /* possible network addresses */ unsigned long int address; /* XXX Delete this */ int thread_status; /* thread status for connect thread */ int connect_status; /* connect status for connect thread */ int decode_errors; /* decode error count, used for data type */ int data_type; /* 0=normal 1=wx_binary */ int socket_port; /* socket port# for network */ char device_host_pswd[MAX_DEVICE_HOSTPW+1]; /* host password */ int channel; /* for serial and net ports */ int channel2; /* for AX25 ports */ char ui_call[30]; /* current call for this port */ struct termios t,t_old; /* terminal struct for serial port */ int dtr; /* dtr signal for HSP cable (status) */ int sp; /* serial port speed */ int style; /* serial port style */ int scan; /* data read available */ int errors; /* errors for this port */ int reconnect; /* reconnect on net failure */ int reconnects; /* total number of reconnects by this port */ unsigned long bytes_input; /* total bytes read by this port */ unsigned long bytes_output; /* total bytes written by this port */ unsigned long bytes_input_last; /* total bytes read last check */ unsigned long bytes_output_last; /* total bytes read last check */ int port_activity; /* 0 if no activity between checks */ pthread_t read_thread; /* read thread */ int read_in_pos; /* current read buffer input pos */ int read_out_pos; /* current read buffer output pos */ char device_read_buffer[MAX_DEVICE_BUFFER]; /* read buffer for this port */ xastir_mutex read_lock; /* Lock for reading the port data */ pthread_t write_thread; /* write thread */ int write_in_pos; /* current write buffer input pos */ int write_out_pos; /* current write buffer output pos */ xastir_mutex write_lock; /* Lock for writing the port data */ char device_write_buffer[MAX_DEVICE_BUFFER];/* write buffer for this port */ } iface; typedef struct { char device_name[100]; } iodevices; typedef struct { int device_type; /* device type */ char device_name[MAX_DEVICE_NAME+1]; /* device name */ char radio_port[3]; /* port for multi-port TNC's */ char device_host_name[MAX_DEVICE_HOSTNM+1]; /* device host name for network */ char device_host_pswd[MAX_DEVICE_HOSTPW+1]; /* host password also WX device data type */ char device_host_filter_string[201]; /* host filter string */ char device_converse_string[10+1]; /* string used to enter converse mode */ char comment[50]; /* Local comment or name for port */ char unproto1[50]; /* unproto path 1 for this port */ char unproto2[50]; /* unproto path 2 for this port */ char unproto3[50]; /* unproto path 3 for this port */ char unproto_igate[50]; /* unproto igate path for this port */ int unprotonum; /* unproto path selection */ char tnc_up_file[100]; /* file for setting up TNC on this port */ char tnc_down_file[100]; /* file for shutting down TNC on this port */ int sp; /* serial port speed/Net port */ int style; /* serial port style */ int igate_options; /* Igate options (0=none,1=input,2=in/out) */ int transmit_data; /* Data transmit out of this port */ int reconnect; /* reconnect on net failure */ int connect_on_startup; /* connect to this device on startup */ int gps_retrieve; /* Character to cause SERIAL_TNC_AUX_GPS to spit out current GPS data */ int tnc_extra_delay; /* Introduces fixed delay when talking to TNC in command-mode */ int set_time; /* Set System Time from GPS on this port */ char txdelay[4]; /* KISS parameter */ char persistence[4]; /* KISS parameter */ char slottime[4]; /* KISS parameter */ char txtail[4]; /* KISS parameter */ int fullduplex; /* KISS parameter */ int relay_digipeat; /* If 1: interface should RELAY digipeat */ int init_kiss; /* Initialize KISS-Mode on startup */ #ifdef HAVE_DB // to support connections to sql server databases for db_gis.c char database_username[20]; /* Username to use to connect to database */ int database_type; /* Type of dbms (posgresql, mysql, etc) */ char database_schema[20]; /* Name of database or schema to use */ char database_errormessage[255]; /* Most recent error message from attempting to make a connection with using this descriptor. */ int database_schema_type; /* table structures to use in the database A database schema could contain both APRSWorld and XASTIR table structures, but a separate database descriptor needs to be defined for each. */ char database_unix_socket[255]; /* MySQL - unix socket parameter (path and filename) */ // Need a pointer here, and one in connection pointing back here. How to do???? //Connection *database_connection; /* Pointer to database connection that contains database handle (with type of handle being dependent on type of database. */ int query_on_startup; /* Load stations from this database on startup. */ // Use of other ioparam variables for sql server database connections: // device_host_name = hostname for database server // sp = port on which to connect to database server // device_host_pswd = password to use to connect to database -- security issue needs to be addressed #endif // HAVE_DB } ioparam; extern iodevices dtype[]; extern xastir_mutex port_data_lock; // Protects the port_data[] array of structs extern xastir_mutex devices_lock; // Protects the devices[] array extern iface port_data[]; extern int port_id[]; extern int get_device_status(int port); extern int del_device(int port); extern int get_open_device(void); extern int add_device(int port_avail,int dev_type, char *dev_nm, char *passwd, int dev_sck_p, int dev_sp, int dev_sty, int reconnect, char *filter_string); extern xastir_mutex data_lock; // Protects incoming_data_queue extern xastir_mutex output_data_lock; // Protects interface.c:channel_data() function only extern xastir_mutex connect_lock; // Protects port_data[].thread_status and port_data[].connect_status extern ioparam devices[]; #if !HAVE_SOCKLEN_T typedef unsigned int socklen_t; #endif /* from interface_gui.c */ extern void interface_gui_init(void); extern void Configure_interface_destroy_shell(Widget widget, XtPointer clientData, XtPointer callData); extern void Configure_interface(Widget w, XtPointer clientData, XtPointer callData); extern void output_my_aprs_data(void); extern void control_interface(Widget w, XtPointer clientData, XtPointer callData); extern void dtr_all_set(int dtr); extern void interface_status(Widget w); extern void update_interface_list(void); extern int WX_rain_gauge_type; /* interface.c */ extern int is_local_interface(int port); extern int is_network_interface(int port); extern void send_agwpe_packet(int xastir_interface, int RadioPort, unsigned char type, unsigned char *FromCall, unsigned char *ToCall, unsigned char *Path, unsigned char *Data, int length); extern int pop_incoming_data(unsigned char *data_string, int *port); extern int push_incoming_data(unsigned char *data_string, int length, int port); extern unsigned char incoming_data_copy[MAX_LINE_SIZE]; extern unsigned char incoming_data_copy_previous[MAX_LINE_SIZE]; extern int NETWORK_WAITTIME; extern void startup_all_or_defined_port(int port); extern void shutdown_all_active_or_defined_port(int port); extern void check_ports(void); extern void clear_all_port_data(void); extern char aprs_station_message_type; extern void port_dtr(int port, int dtr); extern void send_kiss_config(int port, int device, int command, int value); void port_write_string(int port, char *data); extern void init_device_names(void); extern void output_my_data(char *message, int port, int type, int loopback_only, int use_igate_path, char *path); int tnc_get_data_type(char *buf, int port); void tnc_data_clean(char *buf); extern void output_waypoint_data(char *message); extern void send_ax25_frame(int port, char *source, char *destination, char *path, char *data); extern pid_t getpgid(pid_t pid); #endif /* XASTIR_INTERFACE_H */ Xastir-Release-2.2.2/src/interface_gui.c000066400000000000000000014267561501463444000201320ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include "xastir.h" #include "main.h" #include "xa_config.h" #include "interface.h" #include "wx.h" #include "draw_symbols.h" #include "util.h" #include "db_gis.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX Widget configure_interface_dialog = NULL; Widget choose_interface_dialog = NULL; Widget interface_type_list = NULL; Widget control_interface_dialog = NULL; Widget control_iface_list = NULL; static xastir_mutex control_interface_dialog_lock; ioparam devices[MAX_IFACE_DEVICES]; xastir_mutex devices_lock; void Choose_interface_destroy_shell(Widget widget, XtPointer clientData, XtPointer callData); void modify_device_list(int option, int port); void interface_gui_init(void) { init_critical_section( &control_interface_dialog_lock ); init_critical_section( &devices_lock ); } /*****************************************************/ /* Universal Serial GUI */ /*****************************************************/ int device_speed; int device_style; int device_igate_options; int device_data_type; void speed_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_speed = atoi(which); } else { device_speed = 0; } } void style_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_style = atoi(which); } else { device_style = 0; } } void data_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_data_type = atoi(which); } else { device_data_type = 0; } } void rain_gauge_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { WX_rain_gauge_type = atoi(which); } else { WX_rain_gauge_type = 0; } } void igate_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_igate_options = atoi(which); } else { device_igate_options = 0; } } void set_port_speed(int port) { switch (device_speed) { case(1): devices[port].sp=B300; break; case(2): devices[port].sp=B1200; break; case(3): devices[port].sp=B2400; break; case(4): devices[port].sp=B4800; break; case(5): devices[port].sp=B9600; break; case(6): devices[port].sp=B19200; break; case(7): devices[port].sp=B38400; break; #ifndef __LSB__ case(8): devices[port].sp=B57600; break; case(9): devices[port].sp=B115200; break; case(10): #ifndef B230400 devices[port].sp=B115200; #else // B230400 devices[port].sp=B230400; #endif // B230400 break; #endif // __LSB__ default: break; } } /*****************************************************/ /* Configure Serial TNC GUI */ /*****************************************************/ /**** TNC CONFIGURE ******/ int TNC_port; int TNC_device; Widget config_TNC_dialog = (Widget)NULL; Widget TNC_active_on_startup; Widget TNC_transmit_data; Widget TNC_device_name_data; Widget TNC_radio_port_data; // Used only for Multi-Port TNC's Widget TNC_converse_string; Widget TNC_comment; Widget TNC_unproto1_data; Widget TNC_unproto2_data; Widget TNC_unproto3_data; Widget TNC_igate_data; Widget TNC_up_file_data; Widget TNC_down_file_data; Widget TNC_txdelay; Widget TNC_persistence; Widget TNC_slottime; Widget TNC_txtail; Widget TNC_init_kiss; // Used to initialize KISS-Mode Widget TNC_fullduplex; Widget TNC_extra_delay; Widget TNC_GPS_set_time; Widget TNC_AUX_GPS_Retrieve_Needed; Widget TNC_relay_digipeat; void Config_TNC_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_TNC_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_TNC_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int type; int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(TNC_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ //WE7U: Modify for MKISS? (void)del_device(TNC_port); was_up=1; usleep(1000000); // Wait for one second } /* device type */ type=DEVICE_SERIAL_TNC; // Default in case not defined next if (TNC_device) { type=TNC_device; // Modified to support more than two types } begin_critical_section(&devices_lock, "interface_gui.c:Config_TNC_change_data" ); temp_ptr = XmTextFieldGetString(TNC_device_name_data); xastir_snprintf(devices[TNC_port].device_name, sizeof(devices[TNC_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].device_name); temp_ptr = XmTextFieldGetString(TNC_converse_string); xastir_snprintf(devices[TNC_port].device_converse_string, sizeof(devices[TNC_port].device_converse_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].device_converse_string); temp_ptr = XmTextFieldGetString(TNC_comment); xastir_snprintf(devices[TNC_port].comment, sizeof(devices[TNC_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].comment); if (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) { // If MKISS, fetch "radio_port". If empty, store a zero. temp_ptr = XmTextFieldGetString(TNC_radio_port_data); xastir_snprintf(devices[TNC_port].radio_port, sizeof(devices[TNC_port].radio_port), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].radio_port); if (strcmp(devices[TNC_port].radio_port,"") == 0) { xastir_snprintf(devices[TNC_port].radio_port, sizeof(devices[TNC_port].radio_port), "0"); } //fprintf(stderr,"Radio Port: %s\n",devices[TNC_port].radio_port); } if (XmToggleButtonGetState(TNC_active_on_startup)) { devices[TNC_port].connect_on_startup=1; } else { devices[TNC_port].connect_on_startup=0; } if(XmToggleButtonGetState(TNC_transmit_data)) { devices[TNC_port].transmit_data=1; if ( (devices[TNC_port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGI } } else { devices[TNC_port].transmit_data=0; if ( (devices[TNC_port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { XtSetSensitive(TNC_relay_digipeat, FALSE); } } if ( (type == DEVICE_SERIAL_KISS_TNC) || (type == DEVICE_SERIAL_MKISS_TNC) ) { if (XmToggleButtonGetState(TNC_relay_digipeat)) { devices[TNC_port].relay_digipeat=1; } else { devices[TNC_port].relay_digipeat=0; } } switch(type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (XmToggleButtonGetState(TNC_extra_delay)) { devices[TNC_port].tnc_extra_delay=1000000; // 1,000,000 us } else { devices[TNC_port].tnc_extra_delay=0; } break; default: break; } switch(type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (XmToggleButtonGetState(TNC_GPS_set_time)) { devices[TNC_port].set_time=1; } else { devices[TNC_port].set_time=0; } if (type == DEVICE_SERIAL_TNC_AUX_GPS) { if (XmToggleButtonGetState(TNC_AUX_GPS_Retrieve_Needed)) { devices[TNC_port].gps_retrieve=DEFAULT_GPS_RETR; } else { devices[TNC_port].gps_retrieve=0; } } break; case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: default: break; } set_port_speed(TNC_port); devices[TNC_port].style=device_style; devices[TNC_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(TNC_unproto1_data); xastir_snprintf(devices[TNC_port].unproto1, sizeof(devices[TNC_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto1); if(check_unproto_path(devices[TNC_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_unproto2_data); xastir_snprintf(devices[TNC_port].unproto2, sizeof(devices[TNC_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto2); if(check_unproto_path(devices[TNC_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_unproto3_data); xastir_snprintf(devices[TNC_port].unproto3, sizeof(devices[TNC_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto3); if(check_unproto_path(devices[TNC_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_igate_data); xastir_snprintf(devices[TNC_port].unproto_igate, sizeof(devices[TNC_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto_igate); if(check_unproto_path(devices[TNC_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } if ( (type == DEVICE_SERIAL_KISS_TNC) || (type == DEVICE_SERIAL_MKISS_TNC) ) { // KISS TNC, no up/down files for this one! devices[TNC_port].tnc_up_file[0] = '\0'; devices[TNC_port].tnc_down_file[0] = '\0'; // Instead we have KISS parameters to set // We really should do some validation of these strings //WE7U: Modify for MKISS: Must send to the proper Radio Port. temp_ptr = XmTextFieldGetString(TNC_txdelay); xastir_snprintf(devices[TNC_port].txdelay, sizeof(devices[TNC_port].txdelay), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x01,atoi(devices[TNC_port].txdelay)); temp_ptr = XmTextFieldGetString(TNC_persistence); xastir_snprintf(devices[TNC_port].persistence, sizeof(devices[TNC_port].persistence), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x02,atoi(devices[TNC_port].persistence)); temp_ptr = XmTextFieldGetString(TNC_slottime); xastir_snprintf(devices[TNC_port].slottime, sizeof(devices[TNC_port].slottime), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x03,atoi(devices[TNC_port].slottime)); temp_ptr = XmTextFieldGetString(TNC_txtail); xastir_snprintf(devices[TNC_port].txtail, sizeof(devices[TNC_port].txtail), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x04,atoi(devices[TNC_port].txtail)); if (XmToggleButtonGetState(TNC_fullduplex)) { devices[TNC_port].fullduplex=1; } else { devices[TNC_port].fullduplex=0; } send_kiss_config(TNC_port,0,0x05,devices[TNC_port].fullduplex); // For KISS-mode if (XmToggleButtonGetState(TNC_init_kiss)) { devices[TNC_port].init_kiss=1; } else { devices[TNC_port].init_kiss=0; } } else { temp_ptr = XmTextFieldGetString(TNC_up_file_data); xastir_snprintf(devices[TNC_port].tnc_up_file, sizeof(devices[TNC_port].tnc_up_file), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].tnc_up_file); temp_ptr = XmTextFieldGetString(TNC_down_file_data); xastir_snprintf(devices[TNC_port].tnc_down_file, sizeof(devices[TNC_port].tnc_down_file), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].tnc_down_file); } //WE7U: Modify for MKISS? /* reopen port*/ if (was_up) { (void)add_device(TNC_port, type, devices[TNC_port].device_name, "", -1, devices[TNC_port].sp, devices[TNC_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[TNC_port].device_type=type; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_TNC_change_data" ); // Rebuild the interface control list update_interface_list(); Config_TNC_destroy_shell(widget,clientData,callData); } void Config_TNC( Widget UNUSED(w), int device_type, int config_type, int port) { static Widget pane, scrollwindow, form, form2, button_ok, button_cancel, frame, frame2, frame3, frame4, setup1, setup3, setup4, device, converse, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget setup, setup2, speed; #ifndef __LSB__ static Widget speed_57600, speed_115200, speed_230400; #endif // __LSB__ static Widget style_box, style_8n1, style_7e1, style_7o1, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, proto, proto1, proto2, proto3, radio_port_label; // static Widget style, igate; char temp[50]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ register char *tmp; tmp=(char *)NULL; char tmp_string[100]; if(!config_TNC_dialog) { TNC_port=port; TNC_device=device_type; /* config_TNC_dialog = XtVaCreatePopupShell(device_type ? langcode("WPUPCFT023"):langcode("WPUPCFT001"), -- replaced by KB6MER with the lines below for adding AUX GPS type TNC */ switch(device_type) { case DEVICE_SERIAL_TNC: tmp=langcode("WPUPCFT001"); break; case DEVICE_SERIAL_KISS_TNC: tmp=langcode("WPUPCFT030"); break; case DEVICE_SERIAL_MKISS_TNC: tmp=langcode("WPUPCFT040"); break; case DEVICE_SERIAL_TNC_HSP_GPS: tmp=langcode("WPUPCFT023"); break; case DEVICE_SERIAL_TNC_AUX_GPS: tmp=langcode("WPUPCFT028"); break; default: // "Configure TNC w/INVALID ENUM" sprintf(tmp_string, langcode("WPUPCFT029"), (int)device_type); tmp = tmp_string; break; } config_TNC_dialog = XtVaCreatePopupShell( tmp, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_TNC pane",xmPanedWindowWidgetClass, config_TNC_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_TNC form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); TNC_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: TNC_extra_delay = XtVaCreateManagedWidget(langcode("UNIOP00038"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: TNC_GPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_extra_delay, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(TNC_GPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(TNC_GPS_set_time,FALSE); #endif // __CYGWIN__ // Let the user turn off the Control-E thing // that only SOME "tnc-with-gps" devices actually // require, and that confuse the heck out of others. // D700 is among the confused, by the way. TVR -- 14 Aug 2012 if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) { TNC_AUX_GPS_Retrieve_Needed = XtVaCreateManagedWidget(langcode("UNIOP00037"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_GPS_set_time, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); } break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: // Add a "RELAY Digipeat?" button for KISS/MKISS TNC's TNC_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGIPEAT break; case DEVICE_SERIAL_TNC: default: break; } device = XtVaCreateManagedWidget(langcode("WPUPCFT003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_device_name_data = XtVaCreateManagedWidget("Config_TNC device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // converse = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, converse = XtVaCreateManagedWidget("Converse CMD:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_device_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_converse_string = XtVaCreateManagedWidget("Config_TNC comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, converse, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_converse_string, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_comment = XtVaCreateManagedWidget("Config_TNC comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); if (device_type == DEVICE_SERIAL_MKISS_TNC) { // "Radio Port" field for Multi-Port KISS TNC's. radio_port_label = XtVaCreateManagedWidget(langcode("WPUPCFT041"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_comment, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_radio_port_data = XtVaCreateManagedWidget("Config_TNC device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNwidth, ((5*7)+2), XmNmaxLength, 2, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, radio_port_label, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); } frame = XtVaCreateManagedWidget("Config_TNC frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset, 10, XmNtopWidget, device, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_TNC Speed_box",al,ac); XtVaSetValues(speed_box,XmNnumColumns,5,NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); #ifndef __LSB__ speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); #endif // __LSB__ switch(device_type) { case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: break; default: frame2 = XtVaCreateManagedWidget("Config_TNC frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_TNC Style box",al,ac); XtVaSetValues(style_box,XmNorientation, XmHORIZONTAL,NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); break; } frame4 = XtVaCreateManagedWidget("Config_TNC frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, (device_type == DEVICE_SERIAL_KISS_TNC || device_type == DEVICE_SERIAL_MKISS_TNC) ? frame : frame2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); //igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); igate_box = XmCreateRadioBox(frame4,"Config_TNC IGate box",al,ac); XtVaSetValues(igate_box,XmNorientation, XmVERTICAL,XmNnumColumns,2,NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto1_data = XtVaCreateManagedWidget("Config_TNC protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_unproto1_data, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto2_data = XtVaCreateManagedWidget("Config_TNC protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 15, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto3_data = XtVaCreateManagedWidget("Config_TNC protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, TNC_unproto3_data, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_igate_data = XtVaCreateManagedWidget("Config_TNC igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Draw a different frame3 for Serial KISS/MKISS TNC interfaces switch(device_type) { case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: frame3 = XtVaCreateManagedWidget("Config_TNC frame3", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, TNC_igate_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // KISS Parameters //setup XtVaCreateManagedWidget(langcode("WPUPCFT034"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form2 = XtVaCreateWidget("Config_TNC form2",xmFormWidgetClass, frame3, XmNfractionBase, 6, XmNbackground, colors[0xff], NULL); // TXDelay (10 ms units) setup1 = XtVaCreateManagedWidget(langcode("WPUPCFT035"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_txdelay = XtVaCreateManagedWidget("Config_TNC TNC_txdelay", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Persistence (0 to 255) //setup2 XtVaCreateManagedWidget(langcode("WPUPCFT036"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_persistence = XtVaCreateManagedWidget("Config_TNC persistence", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // SlotTime (10 ms units) setup3 = XtVaCreateManagedWidget(langcode("WPUPCFT037"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_slottime = XtVaCreateManagedWidget("Config_TNC slottime", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // TxTail (10 ms units) setup4 = XtVaCreateManagedWidget(langcode("WPUPCFT038"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup3, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_txtail = XtVaCreateManagedWidget("Config_TNC TxTail", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup3, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Full Duplex TNC_fullduplex = XtVaCreateManagedWidget(langcode("WPUPCFT039"),xmToggleButtonWidgetClass,form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, setup4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Button to enable KISS-mode at startup TNC_init_kiss = XtVaCreateManagedWidget(langcode("WPUPCFT047"),xmToggleButtonWidgetClass,form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, setup4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 135, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); break; default: frame3 = XtVaCreateManagedWidget("Config_TNC frame3", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, TNC_igate_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //setup XtVaCreateManagedWidget(langcode("WPUPCFT031"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form2 = XtVaCreateWidget("Config_TNC form2",xmFormWidgetClass, frame3, XmNfractionBase, 5, XmNbackground, colors[0xff], NULL); setup1 = XtVaCreateManagedWidget(langcode("WPUPCFT032"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_up_file_data = XtVaCreateManagedWidget("Config_TNC up_file", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); //setup2 XtVaCreateManagedWidget(langcode("WPUPCFT033"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_down_file_data = XtVaCreateManagedWidget("Config_TNC down_file", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); break; } //------------------------------------------------------------ button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_TNC_change_data, config_TNC_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_TNC_destroy_shell, config_TNC_dialog); pos_dialog(config_TNC_dialog); delw = XmInternAtom(XtDisplay(config_TNC_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_TNC_dialog, delw, Config_TNC_destroy_shell, (XtPointer)config_TNC_dialog); if (config_type==0) { /* first time port */ devices[TNC_port].gps_retrieve=DEFAULT_GPS_RETR; if (debug_level & 128) { fprintf(stderr,"Storing %d to gps_retrieve for %d\n", DEFAULT_GPS_RETR, port); } XmTextFieldSetString(TNC_device_name_data,TNC_PORT); XmTextFieldSetString(TNC_converse_string,"k"); XmTextFieldSetString(TNC_comment,""); if (device_type == DEVICE_SERIAL_MKISS_TNC) { XmTextFieldSetString(TNC_radio_port_data,"0"); //fprintf(stderr,"Assigning default '0' to radio port\n"); } XmToggleButtonSetState(TNC_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(TNC_transmit_data,TRUE,FALSE); switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: XmToggleButtonSetState(TNC_extra_delay, FALSE, FALSE); break; default: break; } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: XmToggleButtonSetState(TNC_GPS_set_time, FALSE, FALSE); if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, TRUE, FALSE); break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: XmToggleButtonSetState(TNC_relay_digipeat, FALSE, FALSE); XmToggleButtonSetState(TNC_fullduplex, FALSE, FALSE); XmToggleButtonSetState(TNC_init_kiss, FALSE, FALSE); // For KISS-Mode break; case DEVICE_SERIAL_TNC: default: break; } XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; if ( (device_type != DEVICE_SERIAL_KISS_TNC) && (device_type != DEVICE_SERIAL_MKISS_TNC) ) { XmToggleButtonSetState(style_8n1,TRUE,FALSE); } device_style=0; device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(TNC_unproto1_data,"WIDE2-2"); XmTextFieldSetString(TNC_unproto2_data,""); XmTextFieldSetString(TNC_unproto3_data,""); XmTextFieldSetString(TNC_igate_data,""); //WE7U if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { // We don't allow changing the selection for KISS // TNC's, as they require 8N1 device_style = 0; XmTextFieldSetString(TNC_txdelay,"40"); XmTextFieldSetString(TNC_persistence,"63"); XmTextFieldSetString(TNC_slottime,"20"); XmTextFieldSetString(TNC_txtail,"30"); } else { XmTextFieldSetString(TNC_up_file_data,"tnc-startup.sys"); XmTextFieldSetString(TNC_down_file_data,"tnc-stop.sys"); } } else { /* reconfig */ if (debug_level & 128) { fprintf(stderr,"Reconfiguring interface\n"); } begin_critical_section(&devices_lock, "interface_gui.c:Config_TNC" ); XmTextFieldSetString(TNC_device_name_data,devices[TNC_port].device_name); XmTextFieldSetString(TNC_converse_string,devices[TNC_port].device_converse_string); XmTextFieldSetString(TNC_comment,devices[TNC_port].comment); if (device_type == DEVICE_SERIAL_MKISS_TNC) { XmTextFieldSetString(TNC_radio_port_data, devices[TNC_port].radio_port); //fprintf(stderr,"Reconfig: %s\n", devices[TNC_port].radio_port); } if (devices[TNC_port].connect_on_startup) { XmToggleButtonSetState(TNC_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(TNC_active_on_startup,FALSE,FALSE); } if (devices[TNC_port].transmit_data) { XmToggleButtonSetState(TNC_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(TNC_transmit_data,FALSE,FALSE); } switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[TNC_port].tnc_extra_delay) { XmToggleButtonSetState(TNC_extra_delay, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_extra_delay, FALSE, FALSE); } break; default: break; } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[TNC_port].set_time) { XmToggleButtonSetState(TNC_GPS_set_time, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_GPS_set_time, FALSE, FALSE); } if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) { if (devices[TNC_port].gps_retrieve != 0) XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, TRUE, FALSE); else XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, FALSE, FALSE); } break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: if (devices[TNC_port].relay_digipeat) { XmToggleButtonSetState(TNC_relay_digipeat, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_relay_digipeat, FALSE, FALSE); } if (devices[TNC_port].fullduplex) { XmToggleButtonSetState(TNC_fullduplex, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_fullduplex, FALSE, FALSE); } // For KISS-Mode if (devices[TNC_port].init_kiss) { XmToggleButtonSetState(TNC_init_kiss, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_init_kiss, FALSE, FALSE); } if (devices[TNC_port].transmit_data) { #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGI } else { XtSetSensitive(TNC_relay_digipeat, FALSE); } break; case DEVICE_SERIAL_TNC: default: break; } switch (devices[TNC_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; #ifndef __LSB__ case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 #endif // __LSB__ default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { // We don't allow changing the selection for KISS // TNC's, as they require 8N1 device_style = 0; } else { switch (devices[TNC_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } } switch (devices[TNC_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } XmTextFieldSetString(TNC_unproto1_data,devices[TNC_port].unproto1); XmTextFieldSetString(TNC_unproto2_data,devices[TNC_port].unproto2); XmTextFieldSetString(TNC_unproto3_data,devices[TNC_port].unproto3); XmTextFieldSetString(TNC_igate_data,devices[TNC_port].unproto_igate); if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { XmTextFieldSetString(TNC_txdelay,devices[TNC_port].txdelay); XmTextFieldSetString(TNC_persistence,devices[TNC_port].persistence); XmTextFieldSetString(TNC_slottime,devices[TNC_port].slottime); XmTextFieldSetString(TNC_txtail,devices[TNC_port].txtail); } else { XmTextFieldSetString(TNC_up_file_data,devices[TNC_port].tnc_up_file); XmTextFieldSetString(TNC_down_file_data,devices[TNC_port].tnc_down_file); } end_critical_section(&devices_lock, "interface_gui.c:Config_TNC" ); } XtManageChild(form); XtManageChild(form2); XtManageChild(speed_box); if ( (device_type != DEVICE_SERIAL_KISS_TNC) && (device_type != DEVICE_SERIAL_MKISS_TNC) ) { XtManageChild(style_box); } XtManageChild(igate_box); XtManageChild(pane); resize_dialog(form, config_TNC_dialog); XtPopup(config_TNC_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_TNC_dialog), XtWindow(config_TNC_dialog)); } } /*****************************************************/ /* Configure Serial GPS GUI */ /*****************************************************/ /**** GPS CONFIGURE ******/ int GPS_port; Widget config_GPS_dialog = (Widget)NULL; Widget GPS_device_name_data; Widget GPS_comment; Widget GPS_active_on_startup; Widget GPS_set_time; void Config_GPS_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_GPS_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_GPS_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(GPS_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(GPS_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_GPS_change_data" ); temp_ptr = XmTextFieldGetString(GPS_device_name_data); xastir_snprintf(devices[GPS_port].device_name, sizeof(devices[GPS_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[GPS_port].device_name); temp_ptr = XmTextFieldGetString(GPS_comment); xastir_snprintf(devices[GPS_port].comment, sizeof(devices[GPS_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[GPS_port].comment); if(XmToggleButtonGetState(GPS_active_on_startup)) { devices[GPS_port].connect_on_startup=1; } else { devices[GPS_port].connect_on_startup=0; } if (XmToggleButtonGetState(GPS_set_time)) { devices[GPS_port].set_time=1; } else { devices[GPS_port].set_time=0; } set_port_speed(GPS_port); devices[GPS_port].style=device_style; /* reopen */ if ( was_up ) { (void)add_device(GPS_port, DEVICE_SERIAL_GPS, devices[GPS_port].device_name, "", -1, devices[GPS_port].sp, devices[GPS_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[GPS_port].device_type=DEVICE_SERIAL_GPS; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_GPS_change_data" ); // Rebuild the interface control list update_interface_list(); Config_GPS_destroy_shell(widget,clientData,callData); } void Config_GPS( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, frame2, device, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget speed; #ifndef __LSB__ static Widget speed_57600, speed_115200, speed_230400; #endif // __LSB__ static Widget style_box, style_8n1, style_7e1, style_7o1, sep; // static Widget style; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_GPS_dialog) { GPS_port=port; config_GPS_dialog = XtVaCreatePopupShell(langcode("WPUPCFG001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_GPS pane",xmPanedWindowWidgetClass, config_GPS_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_GPS form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); device = XtVaCreateManagedWidget(langcode("WPUPCFG003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_device_name_data = XtVaCreateManagedWidget("Config_GPS device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_comment = XtVaCreateManagedWidget("Config_GPS comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); GPS_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, GPS_active_on_startup, XmNtopOffset, 7, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(GPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(GPS_set_time,FALSE); #endif // __CYGWIN__ frame = XtVaCreateManagedWidget("Config_GPS frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, GPS_set_time, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_GPS Speed_box",al,ac); XtVaSetValues(speed_box,XmNnumColumns,3,NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); #ifndef __LSB__ speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); #endif // __LSB__ frame2 = XtVaCreateManagedWidget("Config_GPS frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_GPS Style box",al,ac); XtVaSetValues(style_box, XmNorientation, XmHORIZONTAL, NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); sep = XtVaCreateManagedWidget("Config_GPS sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_GPS_change_data, config_GPS_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_GPS_destroy_shell, config_GPS_dialog); pos_dialog(config_GPS_dialog); delw = XmInternAtom(XtDisplay(config_GPS_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_GPS_dialog, delw, Config_GPS_destroy_shell, (XtPointer)config_GPS_dialog); if (config_type==0) { /* first time port */ XmTextFieldSetString(GPS_device_name_data,GPS_PORT); XmTextFieldSetString(GPS_comment,""); XmToggleButtonSetState(GPS_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(GPS_set_time, FALSE, FALSE); XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_GPS" ); XmTextFieldSetString(GPS_device_name_data,devices[GPS_port].device_name); XmTextFieldSetString(GPS_comment,devices[GPS_port].comment); if (devices[GPS_port].connect_on_startup) { XmToggleButtonSetState(GPS_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(GPS_active_on_startup,FALSE,FALSE); } if (devices[GPS_port].set_time) { XmToggleButtonSetState(GPS_set_time,TRUE,FALSE); } else { XmToggleButtonSetState(GPS_set_time,FALSE,FALSE); } switch (devices[GPS_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; #ifndef __LSB__ case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 #endif // __LSB__ default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } switch (devices[GPS_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } end_critical_section(&devices_lock, "interface_gui.c:Config_GPS" ); } XtManageChild(form); XtManageChild(speed_box); XtManageChild(style_box); XtManageChild(pane); resize_dialog(form, config_GPS_dialog); XtPopup(config_GPS_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_GPS_dialog), XtWindow(config_GPS_dialog)); } } /*****************************************************/ /* Configure Serial WX GUI */ /*****************************************************/ /**** WX CONFIGURE ******/ int WX_port; int WX_rain_gauge_type; Widget config_WX_dialog = (Widget)NULL; Widget WX_transmit_data; Widget WX_device_name_data; Widget WX_comment; Widget WX_active_on_startup; Widget WX_tenths, WX_hundredths, WX_millimeters; void Config_WX_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_WX_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_WX_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(WX_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(WX_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_WX_change_data" ); temp_ptr = XmTextFieldGetString(WX_device_name_data); xastir_snprintf(devices[WX_port].device_name, sizeof(devices[WX_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[WX_port].device_name); temp_ptr = XmTextFieldGetString(WX_comment); xastir_snprintf(devices[WX_port].comment, sizeof(devices[WX_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[WX_port].comment); if(XmToggleButtonGetState(WX_active_on_startup)) { devices[WX_port].connect_on_startup=1; } else { devices[WX_port].connect_on_startup=0; } set_port_speed(WX_port); devices[WX_port].style=device_style; xastir_snprintf(devices[WX_port].device_host_pswd, sizeof( devices[WX_port].device_host_pswd), "%d", device_data_type); /* reopen */ if ( was_up) { (void)add_device(WX_port, DEVICE_SERIAL_WX, devices[WX_port].device_name, devices[WX_port].device_host_pswd, -1, devices[WX_port].sp, devices[WX_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[WX_port].device_type=DEVICE_SERIAL_WX; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_WX_change_data" ); // Rebuild the interface control list update_interface_list(); Config_WX_destroy_shell(widget,clientData,callData); } void Config_WX( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, frame2, frame3, frame4, WX_none, device, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget speed; #ifndef __LSB__ static Widget speed_57600, speed_115200, speed_230400; #endif // __LSB__ static Widget style_box, style_8n1, style_7e1, style_7o1, data_box, data_auto, data_bin, data_ascii, gauge_box, sep; // static Widget data_type, gauge_type; // static Widget style; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_WX_dialog) { WX_port=port; config_WX_dialog = XtVaCreatePopupShell(langcode("WPUPCFWX01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_WX pane",xmPanedWindowWidgetClass, config_WX_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_WX form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); device = XtVaCreateManagedWidget(langcode("WPUPCFWX02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_device_name_data = XtVaCreateManagedWidget("Config_WX device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_comment = XtVaCreateManagedWidget("Config_WX comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); WX_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_WX frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, WX_active_on_startup, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_WX Speed_box",al,ac); XtVaSetValues(speed_box, XmNnumColumns,3, NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); #ifndef __LSB__ speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); #endif // __LSB__ frame2 = XtVaCreateManagedWidget("Config_WX frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_WX Style box",al,ac); XtVaSetValues(style_box, XmNorientation, XmHORIZONTAL, NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); frame3 = XtVaCreateManagedWidget("Config_WX frame3", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // data_type XtVaCreateManagedWidget(langcode("WPUPCFT024"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); data_box = XmCreateRadioBox(frame3,"Config_WX data box",al,ac); XtVaSetValues(data_box, XmNorientation, XmHORIZONTAL, NULL); data_auto = XtVaCreateManagedWidget(langcode("WPUPCFT025"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_auto,XmNvalueChangedCallback,data_toggle,"0"); data_bin = XtVaCreateManagedWidget(langcode("WPUPCFT026"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_bin,XmNvalueChangedCallback,data_toggle,"1"); data_ascii = XtVaCreateManagedWidget(langcode("WPUPCFT027"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_ascii,XmNvalueChangedCallback,data_toggle,"2"); frame4 = XtVaCreateManagedWidget("Config_WX frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // Rain Gauge Type // gauge_type XtVaCreateManagedWidget(langcode("WPUPCFWX03"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); gauge_box = XmCreateRadioBox(frame4,"Config_WX gauge box",al,ac); XtVaSetValues(gauge_box, XmNorientation, XmHORIZONTAL, NULL); WX_none = XtVaCreateManagedWidget(langcode("WPUPCFWX07"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_tenths = XtVaCreateManagedWidget(langcode("WPUPCFWX04"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hundredths = XtVaCreateManagedWidget(langcode("WPUPCFWX05"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_millimeters = XtVaCreateManagedWidget(langcode("WPUPCFWX06"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(WX_none,XmNvalueChangedCallback,rain_gauge_toggle,"0"); XtAddCallback(WX_tenths,XmNvalueChangedCallback,rain_gauge_toggle,"1"); XtAddCallback(WX_hundredths,XmNvalueChangedCallback,rain_gauge_toggle,"2"); XtAddCallback(WX_millimeters,XmNvalueChangedCallback,rain_gauge_toggle,"3"); sep = XtVaCreateManagedWidget("Config_WX sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_WX_change_data, config_WX_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_WX_destroy_shell, config_WX_dialog); pos_dialog(config_WX_dialog); delw = XmInternAtom(XtDisplay(config_WX_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_WX_dialog, delw, Config_WX_destroy_shell, (XtPointer)config_WX_dialog); begin_critical_section(&devices_lock, "interface_gui.c:Config_WX" ); if (config_type==0) { /* first time port */ XmTextFieldSetString(WX_device_name_data,GPS_PORT); XmTextFieldSetString(WX_comment,""); XmToggleButtonSetState(WX_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; device_data_type=0; XmToggleButtonSetState(data_auto,TRUE,FALSE); } else { /* reconfig */ XmTextFieldSetString(WX_device_name_data,devices[WX_port].device_name); XmTextFieldSetString(WX_comment,devices[WX_port].comment); if (devices[WX_port].connect_on_startup) { XmToggleButtonSetState(WX_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(WX_active_on_startup,FALSE,FALSE); } switch (devices[WX_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; #ifndef __LSB__ case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 #endif // __LSB__ default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } switch (devices[WX_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } switch (atoi(devices[WX_port].device_host_pswd)) { case(0): XmToggleButtonSetState(data_auto,TRUE,FALSE); device_data_type=0; break; case(1): XmToggleButtonSetState(data_bin,TRUE,FALSE); device_data_type=1; break; case(2): XmToggleButtonSetState(data_ascii,TRUE,FALSE); device_data_type=2; break; default: device_data_type=0; break; } } end_critical_section(&devices_lock, "interface_gui.c:Config_WX" ); XmToggleButtonSetState(WX_none,FALSE,FALSE); XmToggleButtonSetState(WX_tenths,FALSE,FALSE); XmToggleButtonSetState(WX_hundredths,FALSE,FALSE); XmToggleButtonSetState(WX_millimeters,FALSE,FALSE); switch (WX_rain_gauge_type) { case(1): XmToggleButtonSetState(WX_tenths,TRUE,FALSE); break; case(2): XmToggleButtonSetState(WX_hundredths,TRUE,FALSE); break; case(3): XmToggleButtonSetState(WX_millimeters,TRUE,FALSE); break; default: XmToggleButtonSetState(WX_none,TRUE,FALSE); break; } XtManageChild(form); XtManageChild(speed_box); XtManageChild(style_box); XtManageChild(data_box); XtManageChild(gauge_box); XtManageChild(pane); resize_dialog(form, config_WX_dialog); XtPopup(config_WX_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_WX_dialog), XtWindow(config_WX_dialog)); } } /**** net WX CONFIGURE ******/ int NWX_port; Widget config_NWX_dialog = (Widget)NULL; Widget NWX_host_name_data; Widget NWX_host_port_data; Widget NWX_comment; Widget NWX_active_on_startup; Widget NWX_host_reconnect_data; void Config_NWX_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_NWX_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_NWX_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(NWX_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(NWX_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_NWX_change_data" ); temp_ptr = XmTextFieldGetString(NWX_host_name_data); xastir_snprintf(devices[NWX_port].device_host_name, sizeof(devices[NWX_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NWX_port].device_host_name); temp_ptr = XmTextFieldGetString(NWX_host_port_data); devices[NWX_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(NWX_comment); xastir_snprintf(devices[NWX_port].comment, sizeof(devices[NWX_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NWX_port].comment); if (XmToggleButtonGetState(NWX_active_on_startup)) { devices[NWX_port].connect_on_startup=1; } else { devices[NWX_port].connect_on_startup=0; } if(XmToggleButtonGetState(NWX_host_reconnect_data)) { devices[NWX_port].reconnect=1; } else { devices[NWX_port].reconnect=0; } xastir_snprintf(devices[NWX_port].device_host_pswd, sizeof(devices[NWX_port].device_host_pswd), "%d", device_data_type); /* reopen if was up*/ if ( was_up) { (void)add_device(NWX_port, DEVICE_NET_WX, devices[NWX_port].device_host_name, devices[NWX_port].device_host_pswd, devices[NWX_port].sp, 0, 0, devices[NWX_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[NWX_port].device_type=DEVICE_NET_WX; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_NWX_change_data" ); // Rebuild the interface control list update_interface_list(); Config_NWX_destroy_shell(widget,clientData,callData); } void Config_NWX( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, frame3, frame4, WX_none, button_ok, button_cancel, hostn, portn, comment, data_box, data_auto, data_bin, data_ascii, gauge_box, sep; // static Widget data_type, gauge_type; char temp[20]; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ Atom delw; if(!config_NWX_dialog) { NWX_port=port; config_NWX_dialog = XtVaCreatePopupShell(langcode("WPUPCFG021"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_NWX pane",xmPanedWindowWidgetClass, config_NWX_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_NWX form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); hostn = XtVaCreateManagedWidget(langcode("WPUPCFG022"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_name_data = XtVaCreateManagedWidget("Config_NWX host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, hostn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); portn = XtVaCreateManagedWidget(langcode("WPUPCFG023"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_port_data = XtVaCreateManagedWidget("Config_NWX port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, portn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_comment = XtVaCreateManagedWidget("Config_NWX comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); NWX_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFG020"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NWX_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; frame3 = XtVaCreateManagedWidget("Config_NWX frame3", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NWX_host_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // data_type XtVaCreateManagedWidget(langcode("WPUPCFT024"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); data_box = XmCreateRadioBox(frame3,"Config_NWX data box",al,ac); XtVaSetValues(data_box, XmNorientation, XmHORIZONTAL, NULL); data_auto = XtVaCreateManagedWidget(langcode("WPUPCFT025"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_auto,XmNvalueChangedCallback,data_toggle,"0"); data_bin = XtVaCreateManagedWidget(langcode("WPUPCFT026"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_bin,XmNvalueChangedCallback,data_toggle,"1"); data_ascii = XtVaCreateManagedWidget(langcode("WPUPCFT027"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_ascii,XmNvalueChangedCallback,data_toggle,"2"); frame4 = XtVaCreateManagedWidget("Config_WX frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // Rain Gauge Type // gauge_type XtVaCreateManagedWidget(langcode("WPUPCFWX03"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); gauge_box = XmCreateRadioBox(frame4,"Config_WX gauge box",al,ac); XtVaSetValues(gauge_box, XmNorientation, XmHORIZONTAL, NULL); WX_none = XtVaCreateManagedWidget(langcode("WPUPCFWX07"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_tenths = XtVaCreateManagedWidget(langcode("WPUPCFWX04"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hundredths = XtVaCreateManagedWidget(langcode("WPUPCFWX05"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_millimeters = XtVaCreateManagedWidget(langcode("WPUPCFWX06"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(WX_none,XmNvalueChangedCallback,rain_gauge_toggle,"0"); XtAddCallback(WX_tenths,XmNvalueChangedCallback,rain_gauge_toggle,"1"); XtAddCallback(WX_hundredths,XmNvalueChangedCallback,rain_gauge_toggle,"2"); XtAddCallback(WX_millimeters,XmNvalueChangedCallback,rain_gauge_toggle,"3"); sep = XtVaCreateManagedWidget("Config_NWX sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_NWX_change_data, config_NWX_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_NWX_destroy_shell, config_NWX_dialog); pos_dialog(config_NWX_dialog); delw = XmInternAtom(XtDisplay(config_NWX_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_NWX_dialog, delw, Config_NWX_destroy_shell, (XtPointer)config_NWX_dialog); begin_critical_section(&devices_lock, "interface_gui.c:Config_NWX" ); if (config_type==0) { /* first time port */ XmTextFieldSetString(NWX_host_name_data,"localhost"); XmTextFieldSetString(NWX_host_port_data,"1234"); XmTextFieldSetString(NWX_comment,""); XmToggleButtonSetState(NWX_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(NWX_host_reconnect_data,TRUE,FALSE); device_data_type=0; XmToggleButtonSetState(data_auto,TRUE,FALSE); } else { /* reconfig */ XmTextFieldSetString(NWX_host_name_data,devices[NWX_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[NWX_port].sp); /* port number */ XmTextFieldSetString(NWX_host_port_data,temp); XmTextFieldSetString(NWX_comment,devices[NWX_port].comment); if (devices[NWX_port].connect_on_startup) { XmToggleButtonSetState(NWX_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(NWX_active_on_startup,FALSE,FALSE); } if (devices[NWX_port].reconnect) { XmToggleButtonSetState(NWX_host_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(NWX_host_reconnect_data,FALSE,FALSE); } switch (atoi(devices[NWX_port].device_host_pswd)) { case(0): XmToggleButtonSetState(data_auto,TRUE,FALSE); device_data_type=0; break; case(1): XmToggleButtonSetState(data_bin,TRUE,FALSE); device_data_type=1; break; case(2): XmToggleButtonSetState(data_ascii,TRUE,FALSE); device_data_type=2; break; default: device_data_type=0; break; } } XmToggleButtonSetState(WX_none,FALSE,FALSE); XmToggleButtonSetState(WX_tenths,FALSE,FALSE); XmToggleButtonSetState(WX_hundredths,FALSE,FALSE); XmToggleButtonSetState(WX_millimeters,FALSE,FALSE); switch (WX_rain_gauge_type) { case(1): XmToggleButtonSetState(WX_tenths,TRUE,FALSE); break; case(2): XmToggleButtonSetState(WX_hundredths,TRUE,FALSE); break; case(3): XmToggleButtonSetState(WX_millimeters,TRUE,FALSE); break; default: XmToggleButtonSetState(WX_none,TRUE,FALSE); break; } end_critical_section(&devices_lock, "interface_gui.c:Config_NWX" ); XtManageChild(form); XtManageChild(data_box); XtManageChild(frame3); XtManageChild(gauge_box); XtManageChild(pane); resize_dialog(form, config_NWX_dialog); XtPopup(config_NWX_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_NWX_dialog), XtWindow(config_NWX_dialog)); } } /*****************************************************/ /* Configure net GPS GUI */ /*****************************************************/ /**** net GPS CONFIGURE ******/ int NGPS_port; Widget config_NGPS_dialog = (Widget)NULL; Widget NGPS_host_name_data; Widget NGPS_host_port_data; Widget NGPS_comment; Widget NGPS_active_on_startup; Widget NGPS_host_reconnect_data; Widget NGPS_set_time; void Config_NGPS_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_NGPS_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_NGPS_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(NGPS_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(NGPS_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_NGPS_change_data" ); temp_ptr = XmTextFieldGetString(NGPS_host_name_data); xastir_snprintf(devices[NGPS_port].device_host_name, sizeof(devices[NGPS_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NGPS_port].device_host_name); temp_ptr = XmTextFieldGetString(NGPS_host_port_data); devices[NGPS_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(NGPS_comment); xastir_snprintf(devices[NGPS_port].comment, sizeof(devices[NGPS_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NGPS_port].comment); if(XmToggleButtonGetState(NGPS_active_on_startup)) { devices[NGPS_port].connect_on_startup=1; } else { devices[NGPS_port].connect_on_startup=0; } if (XmToggleButtonGetState(NGPS_host_reconnect_data)) { devices[NGPS_port].reconnect=1; } else { devices[NGPS_port].reconnect=0; } if (XmToggleButtonGetState(NGPS_set_time)) { devices[NGPS_port].set_time=1; } else { devices[NGPS_port].set_time=0; } /* reopen */ if ( was_up ) { (void)add_device(NGPS_port, DEVICE_NET_GPSD, devices[NGPS_port].device_host_name, "", devices[NGPS_port].sp, 0, 0, devices[NGPS_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[NGPS_port].device_type=DEVICE_NET_GPSD; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_NGPS_change_data" ); // Rebuild the interface control list update_interface_list(); Config_NGPS_destroy_shell(widget,clientData,callData); } void Config_NGPS( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, hostn, portn, comment, sep; char temp[20]; Atom delw; if (!config_NGPS_dialog) { NGPS_port=port; config_NGPS_dialog = XtVaCreatePopupShell(langcode("WPUPCFG019"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_NGPS pane",xmPanedWindowWidgetClass, config_NGPS_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_NGPS form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); hostn = XtVaCreateManagedWidget(langcode("WPUPCFG017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_name_data = XtVaCreateManagedWidget("Config_NGPS host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, hostn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); portn = XtVaCreateManagedWidget(langcode("WPUPCFG018"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_port_data = XtVaCreateManagedWidget("Config_NGPS port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, portn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_comment = XtVaCreateManagedWidget("Config_NGPS comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); NGPS_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFG020"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NGPS_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NGPS_host_reconnect_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(NGPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(NGPS_set_time,FALSE); #endif // __CYGWIN__ sep = XtVaCreateManagedWidget("Config_NGPS sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, NGPS_set_time, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_NGPS_change_data, config_NGPS_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_NGPS_destroy_shell, config_NGPS_dialog); pos_dialog(config_NGPS_dialog); delw = XmInternAtom(XtDisplay(config_NGPS_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_NGPS_dialog, delw, Config_NGPS_destroy_shell, (XtPointer)config_NGPS_dialog); if (config_type==0) { /* first time port */ XmTextFieldSetString(NGPS_host_name_data,"localhost"); XmTextFieldSetString(NGPS_host_port_data,"2947"); XmTextFieldSetString(NGPS_comment,""); XmToggleButtonSetState(NGPS_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(NGPS_host_reconnect_data,TRUE,FALSE); XmToggleButtonSetState(NGPS_set_time, FALSE, FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_NGPS" ); XmTextFieldSetString(NGPS_host_name_data,devices[NGPS_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[NGPS_port].sp); /* port number */ XmTextFieldSetString(NGPS_host_port_data,temp); XmTextFieldSetString(NGPS_comment,devices[NGPS_port].comment); if (devices[NGPS_port].connect_on_startup) { XmToggleButtonSetState(NGPS_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(NGPS_active_on_startup,FALSE,FALSE); } if (devices[NGPS_port].reconnect) { XmToggleButtonSetState(NGPS_host_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(NGPS_host_reconnect_data,FALSE,FALSE); } if (devices[NGPS_port].set_time) { XmToggleButtonSetState(NGPS_set_time, TRUE, FALSE); } else { XmToggleButtonSetState(NGPS_set_time, FALSE, FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_NGPS" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_NGPS_dialog); XtPopup(config_NGPS_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_NGPS_dialog), XtWindow(config_NGPS_dialog)); } } /*****************************************************/ /* Configure AX.25 TNC GUI */ /*****************************************************/ /**** AX.25 CONFIGURE ******/ int AX25_port; Widget config_AX25_dialog = (Widget)NULL; Widget AX25_device_name_data; Widget AX25_comment; Widget AX25_unproto1_data; Widget AX25_unproto2_data; Widget AX25_unproto3_data; Widget AX25_igate_data; Widget AX25_active_on_startup; Widget AX25_transmit_data; Widget AX25_relay_digipeat; void Config_AX25_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_AX25_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_AX25_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(AX25_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(AX25_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_AX25_change_data" ); temp_ptr = XmTextFieldGetString(AX25_device_name_data); xastir_snprintf(devices[AX25_port].device_name, sizeof(devices[AX25_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].device_name); temp_ptr = XmTextFieldGetString(AX25_comment); xastir_snprintf(devices[AX25_port].comment, sizeof(devices[AX25_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].comment); if(XmToggleButtonGetState(AX25_active_on_startup)) { devices[AX25_port].connect_on_startup=1; } else { devices[AX25_port].connect_on_startup=0; } if(XmToggleButtonGetState(AX25_transmit_data)) { devices[AX25_port].transmit_data=1; XtSetSensitive(AX25_relay_digipeat, TRUE); } else { devices[AX25_port].transmit_data=0; XtSetSensitive(AX25_relay_digipeat, FALSE); } if(XmToggleButtonGetState(AX25_relay_digipeat)) { devices[AX25_port].relay_digipeat=1; } else { devices[AX25_port].relay_digipeat=0; } devices[AX25_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(AX25_unproto1_data); xastir_snprintf(devices[AX25_port].unproto1, sizeof(devices[AX25_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto1); if(check_unproto_path(devices[AX25_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_unproto2_data); xastir_snprintf(devices[AX25_port].unproto2, sizeof(devices[AX25_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto2); if(check_unproto_path(devices[AX25_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_unproto3_data); xastir_snprintf(devices[AX25_port].unproto3, sizeof(devices[AX25_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto3); if(check_unproto_path(devices[AX25_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_igate_data); xastir_snprintf(devices[AX25_port].unproto_igate, sizeof(devices[AX25_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto_igate); if(check_unproto_path(devices[AX25_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } devices[AX25_port].reconnect=1; // reopen if open before - n8ysz 20041213 // if (devices[AX25_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(AX25_port, DEVICE_AX25_TNC, devices[AX25_port].device_name, "", -1, -1, -1, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[AX25_port].device_type=DEVICE_AX25_TNC; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_AX25_change_data" ); // Rebuild the interface control list update_interface_list(); Config_AX25_destroy_shell(widget,clientData,callData); } void Config_AX25( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, devn, comment, proto, proto1, proto2, proto3, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, sep; // static Widget igate; char temp[50]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_AX25_dialog) { AX25_port=port; config_AX25_dialog = XtVaCreatePopupShell(langcode("WPUPCAX001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_AX25 pane",xmPanedWindowWidgetClass, config_AX25_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_AX25 form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); AX25_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); devn = XtVaCreateManagedWidget(langcode("WPUPCAX002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_device_name_data = XtVaCreateManagedWidget("Config_AX25 device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, devn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_device_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_comment = XtVaCreateManagedWidget("Config_AX25 comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_AX25 frame", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, devn, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; igate_box = XmCreateRadioBox(frame,"Config_AX25 IGate box",al,ac); XtVaSetValues(igate_box, XmNorientation, XmVERTICAL, XmNnumColumns,2, NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto1_data = XtVaCreateManagedWidget("Config_AX25 protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto2_data = XtVaCreateManagedWidget("Config_AX25 protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto3_data = XtVaCreateManagedWidget("Config_AX25 protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto3, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_igate_data = XtVaCreateManagedWidget("Config_TNC igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto3_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_AX25 sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, igate_label, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); #ifdef HAVE_LIBAX25 XtAddCallback(button_ok, XmNactivateCallback, Config_AX25_change_data, config_AX25_dialog); #else // Need code to use button_ok variable to quiet a compiler warning //when we don't have LIBAX25 linked-in. if (button_ok != button_cancel) { // Do nothing (to shut up a compiler warning) } #endif /* USE_AX25 */ XtAddCallback(button_cancel, XmNactivateCallback, Config_AX25_destroy_shell, config_AX25_dialog); pos_dialog(config_AX25_dialog); delw = XmInternAtom(XtDisplay(config_AX25_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_AX25_dialog, delw, Config_AX25_destroy_shell, (XtPointer)config_AX25_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(AX25_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(AX25_transmit_data,TRUE,FALSE); XmToggleButtonSetState(AX25_relay_digipeat,FALSE,FALSE); XmTextFieldSetString(AX25_device_name_data,""); XmTextFieldSetString(AX25_comment,""); device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(AX25_unproto1_data,"WIDE2-2"); XmTextFieldSetString(AX25_unproto2_data,""); XmTextFieldSetString(AX25_unproto3_data,""); XmTextFieldSetString(AX25_igate_data,""); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_AX25" ); if (devices[AX25_port].connect_on_startup) { XmToggleButtonSetState(AX25_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_active_on_startup,FALSE,FALSE); } switch (devices[AX25_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } if (devices[AX25_port].transmit_data) { XmToggleButtonSetState(AX25_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_transmit_data,FALSE,FALSE); } if (devices[AX25_port].relay_digipeat) { XmToggleButtonSetState(AX25_relay_digipeat,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_relay_digipeat,FALSE,FALSE); } XmTextFieldSetString(AX25_device_name_data,devices[AX25_port].device_name); XmTextFieldSetString(AX25_comment,devices[AX25_port].comment); XmTextFieldSetString(AX25_unproto1_data,devices[AX25_port].unproto1); XmTextFieldSetString(AX25_unproto2_data,devices[AX25_port].unproto2); XmTextFieldSetString(AX25_unproto3_data,devices[AX25_port].unproto3); XmTextFieldSetString(AX25_igate_data,devices[AX25_port].unproto_igate); end_critical_section(&devices_lock, "interface_gui.c:Config_AX25" ); } XtManageChild(form); XtManageChild(igate_box); XtManageChild(pane); resize_dialog(form, config_AX25_dialog); XtPopup(config_AX25_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_AX25_dialog), XtWindow(config_AX25_dialog)); } } /*****************************************************/ /* Configure Network server GUI */ /*****************************************************/ /**** INTERNET CONFIGURE ******/ Widget config_Inet_dialog = (Widget)NULL; Widget Inet_active_on_startup; Widget Inet_host_data; Widget Inet_port_data; Widget Inet_comment; Widget Inet_password_data; Widget Inet_filter_data; Widget Inet_transmit_data; Widget Inet_reconnect_data; int Inet_port; void Inet_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Inet_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Inet_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(Inet_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(Inet_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Inet_change_data" ); temp_ptr = XmTextFieldGetString(Inet_host_data); xastir_snprintf(devices[Inet_port].device_host_name, sizeof(devices[Inet_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_name); temp_ptr = XmTextFieldGetString(Inet_password_data); xastir_snprintf(devices[Inet_port].device_host_pswd, sizeof(devices[Inet_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_pswd); temp_ptr = XmTextFieldGetString(Inet_filter_data); xastir_snprintf(devices[Inet_port].device_host_filter_string, sizeof(devices[Inet_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_filter_string); temp_ptr = XmTextFieldGetString(Inet_comment); xastir_snprintf(devices[Inet_port].comment, sizeof(devices[Inet_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].comment); temp_ptr = XmTextFieldGetString(Inet_port_data); devices[Inet_port].sp=atoi(temp_ptr); XtFree(temp_ptr); if(XmToggleButtonGetState(Inet_active_on_startup)) { devices[Inet_port].connect_on_startup=1; } else { devices[Inet_port].connect_on_startup=0; } if(XmToggleButtonGetState(Inet_transmit_data)) { devices[Inet_port].transmit_data=1; } else { devices[Inet_port].transmit_data=0; } if(XmToggleButtonGetState(Inet_reconnect_data)) { devices[Inet_port].reconnect=1; } else { devices[Inet_port].reconnect=0; } // Changed 20041213 per emails with we7u - n8ysz // if (devices[Inet_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(Inet_port, DEVICE_NET_STREAM, devices[Inet_port].device_host_name, devices[Inet_port].device_host_pswd, devices[Inet_port].sp, 0, 0, devices[Inet_port].reconnect, devices[Inet_port].device_host_filter_string); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[Inet_port].device_type=DEVICE_NET_STREAM; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Inet_change_data" ); // Rebuild the interface control list update_interface_list(); Inet_destroy_shell(widget,clientData,callData); } void Config_Inet( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, filter, comment, sep; // static Widget password_fl; Atom delw; char temp[40]; if(!config_Inet_dialog) { Inet_port=port; config_Inet_dialog = XtVaCreatePopupShell(langcode("WPUPCFI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Inet pane",xmPanedWindowWidgetClass, config_Inet_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Inet form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); Inet_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFI002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_host_data = XtVaCreateManagedWidget("Config_Inet host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFI003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,Inet_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Inet_host_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_port_data = XtVaCreateManagedWidget("Config_Inet port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,10, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFI009"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_password_data = XtVaCreateManagedWidget("Config_Inet password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFI010"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Inet_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); filter = XtVaCreateManagedWidget(langcode("WPUPCFI015"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_filter_data = XtVaCreateManagedWidget("Config_Inet filter_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, filter, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_filter_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_comment = XtVaCreateManagedWidget("Config_Inet comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_filter_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); Inet_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFI011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_Inet sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_reconnect_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Inet_change_data, config_Inet_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Inet_destroy_shell, config_Inet_dialog); pos_dialog(config_Inet_dialog); delw = XmInternAtom(XtDisplay(config_Inet_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Inet_dialog, delw, Inet_destroy_shell, (XtPointer)config_Inet_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(Inet_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Inet_transmit_data,TRUE,FALSE); // Core APRS-IS Servers XmTextFieldSetString(Inet_host_data,"rotate.aprs.net"); // Filtered port XmTextFieldSetString(Inet_port_data,"14580"); // Filter of 500 miles around my location. But only if I // enable transmit on that interface and globally! XmTextFieldSetString(Inet_filter_data,"m/500"); XmTextFieldSetString(Inet_comment,"Core INET Servers"); XmToggleButtonSetState(Inet_reconnect_data,TRUE,FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_Inet" ); if (devices[Inet_port].connect_on_startup) { XmToggleButtonSetState(Inet_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_active_on_startup,FALSE,FALSE); } if (devices[Inet_port].transmit_data) { XmToggleButtonSetState(Inet_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Inet_host_data,devices[Inet_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[Inet_port].sp); XmTextFieldSetString(Inet_port_data,temp); XmTextFieldSetString(Inet_password_data,devices[Inet_port].device_host_pswd); XmTextFieldSetString(Inet_filter_data,devices[Inet_port].device_host_filter_string); XmTextFieldSetString(Inet_comment,devices[Inet_port].comment); if (devices[Inet_port].reconnect) { XmToggleButtonSetState(Inet_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_Inet" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Inet_dialog); XtPopup(config_Inet_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Inet_dialog), XtWindow(config_Inet_dialog)); } } //WE7U-DATABASE /*****************************************************/ /* Configure Database Server GUI */ /*****************************************************/ /**** DATABASE CONFIGURE ******/ Widget config_Database_dialog = (Widget)NULL; Widget Database_active_on_startup; Widget Database_host_data; Widget Database_port_data; Widget Database_comment; Widget Database_password_data; Widget Database_filter_data; Widget Database_transmit_data; Widget Database_reconnect_data; int Database_port; void Database_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Database_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Database_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(Database_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(Database_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Database_change_data" ); temp_ptr = XmTextFieldGetString(Database_host_data); xastir_snprintf(devices[Database_port].device_host_name, sizeof(devices[Database_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_name); temp_ptr = XmTextFieldGetString(Database_password_data); xastir_snprintf(devices[Database_port].device_host_pswd, sizeof(devices[Database_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_pswd); temp_ptr = XmTextFieldGetString(Database_filter_data); xastir_snprintf(devices[Database_port].device_host_filter_string, sizeof(devices[Database_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_filter_string); temp_ptr = XmTextFieldGetString(Database_comment); xastir_snprintf(devices[Database_port].comment, sizeof(devices[Database_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].comment); temp_ptr = XmTextFieldGetString(Database_port_data); devices[Database_port].sp=atoi(temp_ptr); XtFree(temp_ptr); if(XmToggleButtonGetState(Database_active_on_startup)) { devices[Database_port].connect_on_startup=1; } else { devices[Database_port].connect_on_startup=0; } if(XmToggleButtonGetState(Database_transmit_data)) { devices[Database_port].transmit_data=1; } else { devices[Database_port].transmit_data=0; } if(XmToggleButtonGetState(Database_reconnect_data)) { devices[Database_port].reconnect=1; } else { devices[Database_port].reconnect=0; } // n8ysz 20041213 // if (devices[Database_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(Database_port, DEVICE_NET_DATABASE, devices[Database_port].device_host_name, devices[Database_port].device_host_pswd, devices[Database_port].sp, 0, 0, devices[Database_port].reconnect, devices[Database_port].device_host_filter_string); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[Database_port].device_type=DEVICE_NET_DATABASE; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Database_change_data" ); // Rebuild the interface control list update_interface_list(); Database_destroy_shell(widget,clientData,callData); } void Config_Database( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, filter, sep, comment; // static Widget password_fl; Atom delw; char temp[40]; if(!config_Database_dialog) { Database_port=port; config_Database_dialog = XtVaCreatePopupShell(langcode("WPUPCFID01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Database pane",xmPanedWindowWidgetClass, config_Database_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Database form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); Database_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFID02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_host_data = XtVaCreateManagedWidget("Config_Database host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFID03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Database_host_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_port_data = XtVaCreateManagedWidget("Config_Database port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,10, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFID09"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_password_data = XtVaCreateManagedWidget("Config_Database password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFID10"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Database_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); filter = XtVaCreateManagedWidget(langcode("WPUPCFID15"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_filter_data = XtVaCreateManagedWidget("Config_Database filter_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, filter, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, filter, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_comment = XtVaCreateManagedWidget("Config_Database comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, filter, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); Database_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFID11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_Database sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Database_reconnect_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Database_change_data, config_Database_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Database_destroy_shell, config_Database_dialog); pos_dialog(config_Database_dialog); delw = XmInternAtom(XtDisplay(config_Database_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Database_dialog, delw, Database_destroy_shell, (XtPointer)config_Database_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Database_transmit_data,TRUE,FALSE); //XmTextFieldSetString(Database_host_data,"first.aprs.net"); XmTextFieldSetString(Database_host_data,""); XmTextFieldSetString(Database_port_data,""); XmTextFieldSetString(Database_filter_data,""); XmTextFieldSetString(Database_comment,""); XmToggleButtonSetState(Database_reconnect_data,FALSE,FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_Database" ); if (devices[Database_port].connect_on_startup) { XmToggleButtonSetState(Database_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Database_active_on_startup,FALSE,FALSE); } if (devices[Database_port].transmit_data) { XmToggleButtonSetState(Database_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Database_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Database_host_data,devices[Database_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[Database_port].sp); XmTextFieldSetString(Database_port_data,temp); XmTextFieldSetString(Database_password_data,devices[Database_port].device_host_pswd); XmTextFieldSetString(Database_filter_data,devices[Database_port].device_host_filter_string); XmTextFieldSetString(Database_comment,devices[Database_port].comment); if (devices[Database_port].reconnect) { XmToggleButtonSetState(Database_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Database_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_Database" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Database_dialog); XtPopup(config_Database_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Database_dialog), XtWindow(config_Database_dialog)); } } #ifdef HAVE_DB //AA3SD-SQL SERVER DATABASE, for db_gis spatial databases /*****************************************************/ /* Configure SQL Database Server GUI */ /*****************************************************/ /**** DATABASE CONFIGURE ******/ Widget config_Sql_Database_dialog = (Widget)NULL; // dialog for sql server database connections used in db_gis.c Widget Sql_Database_active_on_startup; Widget Sql_Database_query_on_startup_data; Widget Sql_Database_host_data; Widget Sql_Database_iport_data; // = sp, tcp port number on which to connect to database server Widget Sql_Database_comment; Widget Sql_Database_password_data; Widget Sql_Database_transmit_data; Widget Sql_Database_reconnect_data; int Sql_Database_port; // xastir interface port number, not tcp/ip port Widget Sql_Database_username_data; Widget Sql_Database_schema_name_data; // lesstif combo boxes are not fully implemented. // replace combo box with a fake combo box made out of a menu when only lesstif is available #ifdef USE_COMBO_BOX Widget Sql_Database_dbms_data; #else int sddd_value; // integer value of the currently selected item (replicating ordinal position in picklist) Widget sddd_button; // button to bring up the picklist Widget sddd_buttons[3]; Widget sddd_menuPane; /// menu that acts as the picklist of dbms types Widget sddd_menu; /// menu top level #endif // USE_COMBO_BOX Widget sddd_widget; // widget used to bind next control in either use combo box or not cases. Widget Sql_Database_unix_socket_data; Widget Sql_Database_schema_type_data; Widget Sql_Database_errormessage_data; // display most recent error message on connection #ifdef HAVE_MYSQL // Set the values on the user interface to an appropriate set // of defaults for connecting to a mysql database. void Sql_Database_set_defaults_mysql(Widget widget, XtPointer clientData, XtPointer callData) { XmString cb_item; //cb_item = XmStringCreateLtoR("MySQL (lat/long)", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL][0], XmFONTLIST_DEFAULT_TAG); //cb_item = XmStringCreateLtoR("MySQL (spatial)", XmFONTLIST_DEFAULT_TAG); #ifdef HAVE_MYSQL_SPATIAL cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], XmFONTLIST_DEFAULT_TAG); #endif /* HAVE_MYSQL_SPATIAL */ #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); #else XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[DB_MYSQL_SPATIAL], NULL); sddd_value = DB_MYSQL_SPATIAL; #endif // USE_COMBO_BOX XmStringFree(cb_item); //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); XmTextFieldSetString(Sql_Database_host_data,"localhost"); XmTextFieldSetString(Sql_Database_iport_data,"3306"); XmTextFieldSetString(Sql_Database_username_data,"xastir_user"); XmTextFieldSetString(Sql_Database_schema_name_data,"xastir"); // ** get default from mysql_config at configure time XmTextFieldSetString(Sql_Database_unix_socket_data,"/var/lib/mysql/mysql.sock"); XmTextFieldSetString(Sql_Database_comment,""); XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); // don't set Sql_Database_errormessage_data - leave most recent error message visible } #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS // Set the values on the user interface to an appropriate set // of defaults for connecting to a postgresql database. void Sql_Database_set_defaults_postgis(Widget widget, XtPointer clientData, XtPointer callData) { XmString cb_item; //cb_item = XmStringCreateLtoR("Postgres/Postgis", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_POSTGIS][0], XmFONTLIST_DEFAULT_TAG); #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); #else XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[DB_POSTGIS], NULL); sddd_value = DB_POSTGIS; #endif // USE_COMBO_BOX XmStringFree(cb_item); //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); XmTextFieldSetString(Sql_Database_host_data,"localhost"); XmTextFieldSetString(Sql_Database_iport_data,"5432"); XmTextFieldSetString(Sql_Database_username_data,"xastir_user"); XmTextFieldSetString(Sql_Database_schema_name_data,"xastir"); // ** get default from mysql_config at configure time XmTextFieldSetString(Sql_Database_unix_socket_data,""); XmTextFieldSetString(Sql_Database_comment,""); XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); // don't set Sql_Database_errormessage_data - leave most recent error message visible } #endif /* HAVE_POSTGIS */ // Destroy the dialog used to set properties for a SQL database interface. void Sql_Database_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Sql_Database_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } /* Callback for OK button on SQL database interface properties dialog. Creates a new interface with the parameters provided in the dialog, or alters the values of the selected interface that was displayed in the dialog. Differs from other interfaces in that an active database connection needs to be started from the interface parameters. */ void Sql_Database_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; // flag to restart connection with new parameters char *temp_ptr; // temporary variable for retrieving string data from XmTextFields int cb_selected; // temporary variable for retrieving combo box selections // change to use code from db_gis.c busy_cursor(appshell); was_up=0; if (debug_level & 2) { fprintf(stderr,"Storing SQL Database interface on port %d\n",Sql_Database_port); } // determine if there is an active connection based on this interface, // if so, stop it and restart after changes have been made. if (get_device_status(Sql_Database_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ fprintf(stderr,"Device is up, disconnecting from database \n"); was_up=1; // close connection } // This needs to be a unitary transaction for other interfaces as we don't // want to read/write data from an interface while its configuration is in an // inconsistent state. In this case (SQL databases, we still need this to be // a unitary transaction in case a new connection is created while the // configuration is in an inconsistent state. begin_critical_section(&devices_lock, "interface_gui.c:Sql_Database_change_data" ); // ** set the interface values needed to make a connection to a database ** // hostname temp_ptr = XmTextFieldGetString(Sql_Database_host_data); xastir_snprintf(devices[Sql_Database_port].device_host_name, sizeof(devices[Sql_Database_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_name); //port temp_ptr = XmTextFieldGetString(Sql_Database_iport_data); devices[Sql_Database_port].sp=atoi(temp_ptr); XtFree(temp_ptr); //username temp_ptr = XmTextFieldGetString(Sql_Database_username_data); xastir_snprintf(devices[Sql_Database_port].database_username, sizeof(devices[Sql_Database_port].database_username), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_pswd); //password temp_ptr = XmTextFieldGetString(Sql_Database_password_data); xastir_snprintf(devices[Sql_Database_port].device_host_pswd, sizeof(devices[Sql_Database_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_pswd); // schema name temp_ptr = XmTextFieldGetString(Sql_Database_schema_name_data); xastir_snprintf(devices[Sql_Database_port].database_schema, sizeof(devices[Sql_Database_port].database_schema), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].database_schema); // database type cb_selected = FALSE; #ifdef USE_COMBO_BOX XtVaGetValues(Sql_Database_dbms_data,XmNselectedPosition, &cb_selected, NULL); #else // find out the value of the latest selection from the Sql_Databas_dbms_data_menu cb_selected = sddd_value; #endif if (cb_selected) { devices[Sql_Database_port].database_type = cb_selected; } else { // If no selection, // default to mysql non-spatial, unless postgis is available. #ifdef HAVE_POSTGIS devices[Sql_Database_port].database_type = DB_POSTGIS; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL devices[Sql_Database_port].database_type = DB_MYSQL; #endif /* HAVE_MYSQL */ } // schema type cb_selected = FALSE; XtVaGetValues(Sql_Database_schema_type_data,XmNselectedPosition, &cb_selected, NULL); if (cb_selected) { devices[Sql_Database_port].database_schema_type = cb_selected; } else { // If no selection, default to simple schema. devices[Sql_Database_port].database_schema_type = XASTIR_SCHEMA_SIMPLE; } // unix socket temp_ptr = XmTextFieldGetString(Sql_Database_unix_socket_data); xastir_snprintf(devices[Sql_Database_port].database_unix_socket, sizeof(devices[Sql_Database_port].database_unix_socket), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].database_unix_socket); // reset the error message to a blank xastir_snprintf(devices[Sql_Database_port].database_errormessage, sizeof(devices[Sql_Database_port].database_errormessage), " "); // ** set additional interface values ** // comment to display on interface list temp_ptr = XmTextFieldGetString(Sql_Database_comment); xastir_snprintf(devices[Sql_Database_port].comment, sizeof(devices[Sql_Database_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].comment); // activate on startup if(XmToggleButtonGetState(Sql_Database_active_on_startup)) { devices[Sql_Database_port].connect_on_startup=1; } else { devices[Sql_Database_port].connect_on_startup=0; } // query on startup if(XmToggleButtonGetState(Sql_Database_query_on_startup_data)) { devices[Sql_Database_port].query_on_startup=1; } else { devices[Sql_Database_port].query_on_startup=0; } // allow saving data if(XmToggleButtonGetState(Sql_Database_transmit_data)) { devices[Sql_Database_port].transmit_data=1; } else { devices[Sql_Database_port].transmit_data=0; } // reconnect on database connection failure if(XmToggleButtonGetState(Sql_Database_reconnect_data)) { devices[Sql_Database_port].reconnect=1; } else { devices[Sql_Database_port].reconnect=0; } if (was_up) { // If the connection was allready open when we started then reconnect // and reopen the database connection with the new parameters. if (openConnection(&devices[Sql_Database_port],&connections[Sql_Database_port])==1) { port_data[Sql_Database_port].status = DEVICE_UP; } else { port_data[Sql_Database_port].status = DEVICE_ERROR; } } /* add device type */ devices[Sql_Database_port].device_type=DEVICE_SQL_DATABASE; end_critical_section(&devices_lock, "interface_gui.c:Sql_Database_change_data" ); // Rebuild the interface control list update_interface_list(); // close the dialog Sql_Database_destroy_shell(widget,clientData,callData); if (debug_level & 2) { fprintf(stderr,"Done storing sql interface parameters\n"); } } #ifndef USE_COMBO_BOX void sddd_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //sddd_menu is zero based, constants for database types are one based. sddd_value = (int)userData + 1; if (debug_level & 4096) { fprintf(stderr,"Selected value on dbms pulldown: %d\n",sddd_value); } } #endif // USE_COMBO_BOX /* dialog to obtain connection parameters for a SQL server (MySQL/Postgresql) * database for spatialy enabled database support */ void Config_sql_Database( Widget w, int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, label_dbms, label_schema_type, ihost, iport, password, unix_socket, error_message, sep, comment, username, schema_name; static Widget button_mysql_defaults; // set form values to defaults for mysql static Widget button_postgis_defaults; // set form values to defaults for postgresql/postgis Dimension width, height; int defaults_set; // Have defaults been set on form for new interface? // Used to make only a single set defaults call when // support for multiple types of dbms are available. Atom delw; char temp[40]; XmString cb_item; XmString *cb_items[2]; int x; #ifndef USE_COMBO_BOX int i; // loop counter Arg args[12]; // available for XtSetArguments char buf[18]; char *tmp; #endif // !USE_COMBO_BOX /* // configuration parameters for a sql server database char database_username[20]; // username to use to connect to database // default xastir int database_type; // type of dbms (posgresql, mysql, etc) // default mysql char database_schema[20]; // name of database or schema to use // default xastir char database_errormessage[255]; // most recent error message from attempting to make a connection with using this descriptor. int database_schema_type; // table structures to use in the database A database schema could contain both APRSWorld and XASTIR table structures, but a separate database descriptor should be defined for each. // default simple char database_unix_socket[255]; // MySQL - unix socket parameter (path and filename) // device_host_name = hostname for database server // sp = port on which to connect to database server (Not database_port) // device_host_password = password to use to connect to database -- security issue needs to be addressed */ if(!config_Sql_Database_dialog) { // port is position in xastir interface list, not tcp port on which to connect Sql_Database_port=port; // SQL Server Database config_Sql_Database_dialog = XtVaCreatePopupShell("SQL Server Database", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Database pane",xmPanedWindowWidgetClass, config_Sql_Database_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Database form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 13, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Activate on startup Sql_Database_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // DMBS label_dbms = XtVaCreateManagedWidget("Database:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_active_on_startup, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Combo box to pick dbms cb_items [0] = (XmString *) XtMalloc ( sizeof (XmString) * 4 ); // Combo box items are defined by xastir_dbms_type, defined in db_gis.c cb_items[0][0] = XmStringCreateLtoR( &xastir_dbms_type[1][0], XmFONTLIST_DEFAULT_TAG); cb_items[0][1] = XmStringCreateLtoR( &xastir_dbms_type[2][0], XmFONTLIST_DEFAULT_TAG); cb_items[0][2] = XmStringCreateLtoR( &xastir_dbms_type[3][0], XmFONTLIST_DEFAULT_TAG); // mysql //cb_items[0][0] = XmStringCreateLtoR("MySQL (lat/long)", XmFONTLIST_DEFAULT_TAG); // postgresql //cb_items[0][1] = XmStringCreateLtoR("Postgres/Postgis", XmFONTLIST_DEFAULT_TAG); // mysql with spatial extensions //cb_items[0][2] = XmStringCreateLtoR("MySQL (spatial)", XmFONTLIST_DEFAULT_TAG); cb_items[0][3] = NULL; #ifdef USE_COMBO_BOX Sql_Database_dbms_data = XtVaCreateManagedWidget("select dbms", xmComboBoxWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label_dbms, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNitems, cb_items[0], XmNitemCount, 3, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNmatchBehavior, XmQUICK_NAVIGATE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sddd_widget = Sql_Database_dbms_data; #else // lesstif, at least as of version 0.95 in 2008, doesn't fully support combo boxes. // // lesstif 0.94 doesn't support adding items to the list on creation through XmNitems // lesstif 0.94 combo boxes don't have means to set currently selected value // or to retrieve currently selected value. // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. // // Fake a combo box with a menu, as done by xpdf in in XPDFViewer.cc // // create widgets and populate menu // sddd_ abbreviates name of single control that is being replaced: Sql_Database_dbms_data // sddd_value // numeric value for the database dbms type // sddd_button // picklist item // sddd_menu // menu that acts as the picklist of dbms types x = 0; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; sddd_menuPane = XmCreatePulldownMenu(form,"sddd_menuPane", args, x); //sddd_menu is zero based, constants for database types are one based. //sddd_value is set to match constants in callback. for (i=0; i<3; i++) { x = 0; XmStringGetLtoR(cb_items[0][i],XmFONTLIST_DEFAULT_TAG,&tmp); XtSetArg(args[x], XmNlabelString, cb_items[0][i]); x++; XtSetArg(args[x], XmNuserData, (XtPointer)i); x++; XtSetArg(args[x], XmNfontList, fontlist1); x++; sprintf(buf,"button%d",i); sddd_button = XmCreatePushButton(sddd_menuPane, buf, args, x); XtManageChild(sddd_button); XtAddCallback(sddd_button, XmNactivateCallback, sddd_menuCallback, config_Sql_Database_dialog); sddd_buttons[i] = sddd_button; } x = 0; XtSetArg(args[x], XmNleftAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNleftWidget, label_dbms); ++x; XtSetArg(args[x], XmNtopAttachment, XmATTACH_FORM); ++x; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNtopOffset, 7); ++x; XtSetArg(args[x], XmNleftOffset, 1); ++x; XtSetArg(args[x], XmNsubMenuId, sddd_menuPane); ++x; sddd_menu = XmCreateOptionMenu(form, "sddd_Menu", args, x); XtManageChild(sddd_menu); sddd_widget = sddd_menu; #endif // free up the XmStrings used to create the picklist x=0; while ( cb_items[0][x] ) { XmStringFree ( cb_items[0][x++] ); } x=0; XtFree ( (char *) cb_items[0] ); // *** when localizing these strings propagate the localizations to // the set default functions above and to constants for picklist // selection recognition. *** //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,1,1); //XmStringFree(cb_item); //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_POSTGIS][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,2,1); //XmStringFree(cb_item); //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,3,1); //XmStringFree(cb_item); // Schema Type label_schema_type = XtVaCreateManagedWidget("With Tables for",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, sddd_widget, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Combo box to pick schema Sql_Database_schema_type_data = XtVaCreateManagedWidget("Tables to use", xmComboBoxWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label_schema_type, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to add constants for order and localization *** // ? use an array - schm_typ[XASTIR_SCHEMA_SIMPLE]=langcode("codeforxastirsimple").... ? // ?or some other form of key-value pairs? // simple //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(Sql_Database_schema_type_data,cb_item,1,1); XmStringFree(cb_item); /* not yet implemented // aprs world cb_item = XmStringCreateLtoR("APRSWorld", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); // full cb_item = XmStringCreateLtoR("Xastir - full", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); // cad cb_item = XmStringCreateLtoR("Xastir - CAD", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); */ // Store data Sql_Database_transmit_data = XtVaCreateManagedWidget("Store incoming data",xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sddd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Retrieve data on start Sql_Database_query_on_startup_data = XtVaCreateManagedWidget("Load data on start",xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sddd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_transmit_data, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // put retrieve now button here. // hostname ihost = XtVaCreateManagedWidget(langcode("WPUPCFID02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_host_data = XtVaCreateManagedWidget("Config_Database host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 55, XmNmaxLength, 255, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // tcp port for server, not xastir interface port // port iport = XtVaCreateManagedWidget(langcode("WPUPCFID03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_host_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_iport_data = XtVaCreateManagedWidget("Config_Database port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Username username = XtVaCreateManagedWidget("Username",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_username_data = XtVaCreateManagedWidget("Config_Database username_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNmaxLength, 25, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, username, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Password password = XtVaCreateManagedWidget("Password",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_username_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_password_data = XtVaCreateManagedWidget("Config_Database password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Schema/Database name schema_name = XtVaCreateManagedWidget("Schema/Database name",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_schema_name_data= XtVaCreateManagedWidget("Config_Database schema_name_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNmaxLength, 50, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, schema_name, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // MySQL unix socket unix_socket = XtVaCreateManagedWidget("MySQL unix socket",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_schema_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_unix_socket_data = XtVaCreateManagedWidget("Config_Database unix_socket_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, unix_socket, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // comment comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_schema_name_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_comment = XtVaCreateManagedWidget("Config_Database comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_schema_name_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // reconnect on network failure Sql_Database_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFID11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_comment, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // most recent error error_message = XtVaCreateManagedWidget("Most Recent Error:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // error message isn't editable and isn't saved Sql_Database_errormessage_data = XtVaCreateManagedWidget("Config_Database error_message", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, FALSE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 79, XmNwidth, ((79*7)+2), XmNmaxLength, 255, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_reconnect_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, error_message, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // separator line sep = XtVaCreateManagedWidget("Config_Database sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_errormessage_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: MySQL Defaults button_mysql_defaults = XtVaCreateManagedWidget("MySQL Defaults",xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: Postgis Defaults button_postgis_defaults = XtVaCreateManagedWidget("Postgis Defaults",xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 6, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: OK button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 7, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 9, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: Cancel button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 12, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(button_mysql_defaults,FALSE); #ifdef HAVE_MYSQL XtSetSensitive(button_mysql_defaults,TRUE); XtAddCallback(button_mysql_defaults, XmNactivateCallback, Sql_Database_set_defaults_mysql, config_Sql_Database_dialog); #endif /* HAVE_MYSQL */ XtSetSensitive(button_postgis_defaults,FALSE); #ifdef HAVE_POSTGIS XtSetSensitive(button_postgis_defaults,TRUE); XtAddCallback(button_postgis_defaults, XmNactivateCallback, Sql_Database_set_defaults_postgis, config_Sql_Database_dialog); #endif /* HAVE_POSTGIS */ XtAddCallback(button_ok, XmNactivateCallback, Sql_Database_change_data, config_Sql_Database_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Sql_Database_destroy_shell, config_Sql_Database_dialog); pos_dialog(config_Sql_Database_dialog); delw = XmInternAtom(XtDisplay(config_Sql_Database_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Sql_Database_dialog, delw, Sql_Database_destroy_shell, (XtPointer)config_Sql_Database_dialog); if (config_type==0) { /* first time port */ // Default settings for a new interface. defaults_set = 0; #ifdef HAVE_MYSQL Sql_Database_set_defaults_mysql(config_Sql_Database_dialog,NULL,NULL); defaults_set = 1; #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS if (defaults_set==0) { // mysql support not available, use postgis Sql_Database_set_defaults_postgis(config_Sql_Database_dialog,NULL,NULL); } #endif /* HAVE_POSTGIS */ } else { /* reconfigure an existing interface */ // why critical section here? We are reading data from an existing configuration, // not changing the configuration while the interface might be in use. begin_critical_section(&devices_lock, "interface_gui.c:Config_sql_Database" ); // *** need to look up localized string for database_type *** cb_item = XmStringCreateLtoR(&xastir_dbms_type[devices[Sql_Database_port].database_type][0], XmFONTLIST_DEFAULT_TAG); #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); XmComboBoxSetItem(Sql_Database_dbms_data,cb_item); #else //sddd_menu is zero based, constants for database types are one based. //sddd_value matches constants. XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[devices[Sql_Database_port].database_type - 1 ], NULL); sddd_value = devices[Sql_Database_port].database_type; #endif XmStringFree(cb_item); cb_item = XmStringCreateLtoR(&xastir_schema_type[devices[Sql_Database_port].database_schema_type][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmComboBoxSetItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); if (devices[Sql_Database_port].connect_on_startup) { XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_active_on_startup,FALSE,FALSE); } if (devices[Sql_Database_port].query_on_startup) { XmToggleButtonSetState(Sql_Database_query_on_startup_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_query_on_startup_data,FALSE,FALSE); } if (devices[Sql_Database_port].transmit_data) { XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Sql_Database_host_data,devices[Sql_Database_port].device_host_name); XmTextFieldSetString(Sql_Database_schema_name_data,devices[Sql_Database_port].database_schema); xastir_snprintf(temp, sizeof(temp), "%d", devices[Sql_Database_port].sp); XmTextFieldSetString(Sql_Database_iport_data,temp); XmTextFieldSetString(Sql_Database_username_data,devices[Sql_Database_port].database_username); XmTextFieldSetString(Sql_Database_password_data,devices[Sql_Database_port].device_host_pswd); XmTextFieldSetString(Sql_Database_unix_socket_data,devices[Sql_Database_port].database_unix_socket); XmTextFieldSetString(Sql_Database_comment,devices[Sql_Database_port].comment); // display most recent error message XmTextFieldSetString(Sql_Database_errormessage_data,devices[Sql_Database_port].database_errormessage); if (devices[Sql_Database_port].reconnect) { XmToggleButtonSetState(Sql_Database_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_sql_Database" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Sql_Database_dialog); XtPopup(config_Sql_Database_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Sql_Database_dialog), XtWindow(config_Sql_Database_dialog)); } } #endif /* HAVE_DB */ /*****************************************************/ /* Configure AGWPE Server GUI */ /*****************************************************/ /**** AGWPE CONFIGURE ******/ Widget config_AGWPE_dialog = (Widget)NULL; Widget AGWPE_active_on_startup; Widget AGWPE_host_data; Widget AGWPE_port_data; Widget AGWPE_comment; Widget AGWPE_password_data; Widget AGWPE_transmit_data; Widget AGWPE_igate_data; Widget AGWPE_reconnect_data; Widget AGWPE_unproto1_data; Widget AGWPE_unproto2_data; Widget AGWPE_unproto3_data; Widget AGWPE_relay_digipeat; Widget AGWPE_radioport_data; int AGWPE_port; void AGWPE_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_AGWPE_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void AGWPE_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(AGWPE_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(AGWPE_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:AGWPE_change_data" ); devices[AGWPE_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(AGWPE_host_data); xastir_snprintf(devices[AGWPE_port].device_host_name, sizeof(devices[AGWPE_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_name); temp_ptr = XmTextFieldGetString(AGWPE_password_data); xastir_snprintf(devices[AGWPE_port].device_host_pswd, sizeof(devices[AGWPE_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_pswd); temp_ptr = XmTextFieldGetString(AGWPE_comment); xastir_snprintf(devices[AGWPE_port].comment, sizeof(devices[AGWPE_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].comment); temp_ptr = XmTextFieldGetString(AGWPE_port_data); devices[AGWPE_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(AGWPE_unproto1_data); xastir_snprintf(devices[AGWPE_port].unproto1, sizeof(devices[AGWPE_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto1); if(check_unproto_path(devices[AGWPE_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_unproto2_data); xastir_snprintf(devices[AGWPE_port].unproto2, sizeof(devices[AGWPE_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto2); if(check_unproto_path(devices[AGWPE_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_unproto3_data); xastir_snprintf(devices[AGWPE_port].unproto3, sizeof(devices[AGWPE_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto3); if(check_unproto_path(devices[AGWPE_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_igate_data); xastir_snprintf(devices[AGWPE_port].unproto_igate, sizeof(devices[AGWPE_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto_igate); if(check_unproto_path(devices[AGWPE_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_radioport_data); xastir_snprintf(devices[AGWPE_port].device_host_filter_string, sizeof(devices[AGWPE_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_filter_string); if(XmToggleButtonGetState(AGWPE_active_on_startup)) { devices[AGWPE_port].connect_on_startup=1; } else { devices[AGWPE_port].connect_on_startup=0; } if(XmToggleButtonGetState(AGWPE_transmit_data)) { devices[AGWPE_port].transmit_data=1; } else { devices[AGWPE_port].transmit_data=0; } //WE7U // if(XmToggleButtonGetState(AGWPE_relay_digipeat)) // devices[AGWPE_port].relay_digipeat=1; // else devices[AGWPE_port].relay_digipeat=0; if(XmToggleButtonGetState(AGWPE_reconnect_data)) { devices[AGWPE_port].reconnect=1; } else { devices[AGWPE_port].reconnect=0; } // n8ysz 20041213 // if (devices[AGWPE_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(AGWPE_port, DEVICE_NET_AGWPE, devices[AGWPE_port].device_host_name, devices[AGWPE_port].device_host_pswd, devices[AGWPE_port].sp, 0, 0, devices[AGWPE_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[AGWPE_port].device_type=DEVICE_NET_AGWPE; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:AGWPE_change_data" ); // Rebuild the interface control list update_interface_list(); AGWPE_destroy_shell(widget,clientData,callData); } void Config_AGWPE( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, sep, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, frame, proto, proto1, proto2, proto3, radioport_label, comment; // static Widget igate, password_fl; Atom delw; char temp[40]; Arg al[50]; // Arg list register unsigned int ac = 0; // Arg Count if(!config_AGWPE_dialog) { AGWPE_port=port; config_AGWPE_dialog = XtVaCreatePopupShell(langcode("WPUPCFIA01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_AGWPE pane",xmPanedWindowWidgetClass, config_AGWPE_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_AGWPE form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); AGWPE_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFIA02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_host_data = XtVaCreateManagedWidget("Config_AGWPE host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFIA03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,AGWPE_host_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_port_data = XtVaCreateManagedWidget("Config_AGWPE port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNwidth, ((5*7)+2), XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_port_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_comment = XtVaCreateManagedWidget("Config_AGWPE comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFIA09"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_password_data = XtVaCreateManagedWidget("Config_AGWPE password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFIA10"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,AGWPE_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], NULL); AGWPE_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFIA11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); radioport_label = XtVaCreateManagedWidget(langcode("WPUPCFIA15"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_reconnect_data, XmNleftOffset, 50, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_radioport_data = XtVaCreateManagedWidget("Config_AGWPE radioport_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, radioport_label, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_AGWPE frame", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Set args for color ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; igate_box = XmCreateRadioBox(frame,"Config_AGWPE IGate box",al,ac); XtVaSetValues(igate_box,XmNorientation, XmVERTICAL,XmNnumColumns,2,NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto1_data = XtVaCreateManagedWidget("Config_AGWPE protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto2_data = XtVaCreateManagedWidget("Config_AGWPE protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto3_data = XtVaCreateManagedWidget("Config_AGWPE protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto3, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_igate_data = XtVaCreateManagedWidget("Config_AGWPE igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto3_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_AGWPE sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_igate_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, AGWPE_change_data, config_AGWPE_dialog); XtAddCallback(button_cancel, XmNactivateCallback, AGWPE_destroy_shell, config_AGWPE_dialog); pos_dialog(config_AGWPE_dialog); delw = XmInternAtom(XtDisplay(config_AGWPE_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_AGWPE_dialog, delw, AGWPE_destroy_shell, (XtPointer)config_AGWPE_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(AGWPE_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(AGWPE_transmit_data,TRUE,FALSE); //XmTextFieldSetString(AGWPE_host_data,"first.aprs.net"); XmTextFieldSetString(AGWPE_host_data,"localhost"); XmTextFieldSetString(AGWPE_port_data,"8000"); XmTextFieldSetString(AGWPE_comment,""); XmToggleButtonSetState(AGWPE_reconnect_data,FALSE,FALSE); XmToggleButtonSetState(AGWPE_relay_digipeat, FALSE, FALSE); device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(AGWPE_unproto1_data,"WIDE2-2"); XmTextFieldSetString(AGWPE_unproto2_data,""); XmTextFieldSetString(AGWPE_unproto3_data,""); XmTextFieldSetString(AGWPE_igate_data,""); XmTextFieldSetString(AGWPE_radioport_data,"1"); //WE7U // Keep this statement until we get relay digipeating functional for // this interface. XtSetSensitive(AGWPE_relay_digipeat, FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_AGWPE" ); if (devices[AGWPE_port].connect_on_startup) { XmToggleButtonSetState(AGWPE_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_active_on_startup,FALSE,FALSE); } if (devices[AGWPE_port].transmit_data) { XmToggleButtonSetState(AGWPE_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_transmit_data,FALSE,FALSE); } // if (devices[AGWPE_port].relay_digipeat) // XmToggleButtonSetState(AGWPE_relay_digipeat, TRUE, FALSE); // else XmToggleButtonSetState(AGWPE_relay_digipeat, FALSE, FALSE); // if (devices[AGWPE_port].transmit_data) { // XtSetSensitive(AGWPE_relay_digipeat, TRUE); // } // else XtSetSensitive(AGWPE_relay_digipeat, FALSE); XmTextFieldSetString(AGWPE_host_data,devices[AGWPE_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[AGWPE_port].sp); XmTextFieldSetString(AGWPE_port_data,temp); XmTextFieldSetString(AGWPE_password_data,devices[AGWPE_port].device_host_pswd); XmTextFieldSetString(AGWPE_comment,devices[AGWPE_port].comment); if (devices[AGWPE_port].reconnect) { XmToggleButtonSetState(AGWPE_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_reconnect_data,FALSE,FALSE); } XmTextFieldSetString(AGWPE_radioport_data,devices[AGWPE_port].device_host_filter_string); switch (devices[AGWPE_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } XmTextFieldSetString(AGWPE_unproto1_data,devices[AGWPE_port].unproto1); XmTextFieldSetString(AGWPE_unproto2_data,devices[AGWPE_port].unproto2); XmTextFieldSetString(AGWPE_unproto3_data,devices[AGWPE_port].unproto3); XmTextFieldSetString(AGWPE_igate_data,devices[AGWPE_port].unproto_igate); end_critical_section(&devices_lock, "interface_gui.c:Config_AGWPE" ); } XtManageChild(igate_box); XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_AGWPE_dialog); XtPopup(config_AGWPE_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_AGWPE_dialog), XtWindow(config_AGWPE_dialog)); } } /*****************************************************/ /* Configure Interface GUI */ /*****************************************************/ int are_shells_up(void) { int up; up=1; if (config_TNC_dialog) { (void)XRaiseWindow(XtDisplay(config_TNC_dialog), XtWindow(config_TNC_dialog)); } else { if (config_GPS_dialog) { (void)XRaiseWindow(XtDisplay(config_GPS_dialog), XtWindow(config_GPS_dialog)); } else { if (config_WX_dialog) { (void)XRaiseWindow(XtDisplay(config_WX_dialog), XtWindow(config_WX_dialog)); } else { if (config_NGPS_dialog) { (void)XRaiseWindow(XtDisplay(config_NGPS_dialog), XtWindow(config_NGPS_dialog)); } else { if (config_AX25_dialog) { (void)XRaiseWindow(XtDisplay(config_AX25_dialog), XtWindow(config_AX25_dialog)); } else { if (config_Inet_dialog) { (void)XRaiseWindow(XtDisplay(config_Inet_dialog), XtWindow(config_Inet_dialog)); } else { if (config_NWX_dialog) { (void)XRaiseWindow(XtDisplay(config_NWX_dialog), XtWindow(config_NWX_dialog)); } else { if (config_Database_dialog) { (void)XRaiseWindow(XtDisplay(config_Database_dialog), XtWindow(config_Database_dialog)); } else { #ifdef HAVE_DB if (config_Sql_Database_dialog) { (void)XRaiseWindow(XtDisplay(config_Sql_Database_dialog), XtWindow(config_Sql_Database_dialog)); } else { #endif /* HAVE_DB */ if (config_AGWPE_dialog) { (void)XRaiseWindow(XtDisplay(config_AGWPE_dialog), XtWindow(config_AGWPE_dialog)); } else { up=0; } #ifdef HAVE_DB } #endif /* HAVE_DB */ } } } } } } } } return(up); } void Choose_interface_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (are_shells_up()==0) { XtPopdown(shell); XtDestroyWidget(shell); choose_interface_dialog = (Widget)NULL; } } void modify_device_list(int option, int port) { int i,n; char temp[150]; char temp2[150]; XmString str_ptr; n=1; for (i=0; i < MAX_IFACE_DEVICES; i++) { if (devices[i].device_type!=DEVICE_NONE) { switch (option) { case 0 : /* delete entire list available */ XmListDeleteAllItems(control_iface_list); return; // Exit routine break; case 1 : /* delete item pointed to by port */ if (i==port) { XmListDeletePos(control_iface_list,n); } n++; break; case 2 : /* create item list */ /* format list for device modify*/ switch (devices[i].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00000"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_SERIAL_MKISS_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00001"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, atoi(devices[i].radio_port), devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_NET_DATABASE: case DEVICE_SQL_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_AGWPE: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00001"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_host_name, devices[i].sp, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_AX25_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00002"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; default: break; } /* look at list data (Must be "Device" port#) */ XmListAddItem(control_iface_list, str_ptr = XmStringCreateLtoR(temp,XmFONTLIST_DEFAULT_TAG),n++); XmStringFree(str_ptr); break; case 3 : /* create item list */ /* format list for device control*/ if (port_data[i].active==DEVICE_IN_USE) { switch (port_data[i].status) { case DEVICE_DOWN: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00006")); break; case DEVICE_UP: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00007")); break; case DEVICE_ERROR: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00008")); break; default: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00009")); break; } } else { xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00006")); } switch (devices[i].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00003"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_SERIAL_MKISS_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00004"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, atoi(devices[i].radio_port), devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_NET_DATABASE: case DEVICE_SQL_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_AGWPE: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00004"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_host_name, devices[i].sp, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_AX25_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00005"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; default: break; } /* look at list data (Must be "Device" port#) */ XmListAddItem(control_iface_list, str_ptr = XmStringCreateLtoR(temp,XmFONTLIST_DEFAULT_TAG),n++); XmStringFree(str_ptr); break; case 4 : /* delete entire list available */ XmListDeleteAllItems(control_iface_list); return; // Exit routine break; default: break; } } } } // Rebuild the list in the interface control dialog so that the // current status of each interface is shown. // void update_interface_list(void) { // If the interface control dialog exists if (control_interface_dialog) { // Delete the entire list modify_device_list(4,0); // Create the list again with updated values modify_device_list(3,0); } } void interface_setup(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { char *what = (char *)clientData; int x,i,do_w; char *temp; /*char temp2[100];*/ XmString *list; int port; int found; port=-1; found=0; do_w=atoi(what); /* get option selected */ XtVaGetValues(interface_type_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(interface_type_list,x)) { found=x; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { if (do_w==0) // Add an interface { /* add */ /*fprintf(stderr,"ADD DEVICE\n");*/ /* delete list */ begin_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); modify_device_list(0,0); end_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); port=get_open_device(); // Find an unused port number /*fprintf(stderr,"Open_port %d\n",port);*/ if(port!=-1) { /*devices[port].device_type=found;*/ /*fprintf(stderr,"adding device %s on port %d\n",dtype[found].device_name,port);*/ switch (found) { //WE7U: Set up for new KISS device type case DEVICE_SERIAL_KISS_TNC: // configure this port if (debug_level & 1) { fprintf(stderr,"ADD SERIAL KISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_KISS_TNC, 0, port); break; case DEVICE_SERIAL_MKISS_TNC: // configure this port if (debug_level & 1) { fprintf(stderr,"ADD SERIAL MKISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_MKISS_TNC, 0, port); break; case DEVICE_SERIAL_TNC: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC\n"); } Config_TNC(w, DEVICE_SERIAL_TNC, 0, port); break; case DEVICE_SERIAL_TNC_HSP_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC w HSP GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_HSP_GPS, 0, port); break; case DEVICE_SERIAL_TNC_AUX_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC w AUX GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_AUX_GPS, 0, port); break; case DEVICE_SERIAL_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL GPS\n"); } Config_GPS(w, 0, port); break; case DEVICE_SERIAL_WX: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL WX\n"); } Config_WX(w, 0, port); break; case DEVICE_NET_WX: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD Network WX\n"); } Config_NWX(w, 0, port); break; case DEVICE_NET_GPSD: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD Network GPS\n"); } Config_NGPS(w, 0, port); break; case DEVICE_AX25_TNC: /* configure this port */ if (debug_level & 1) #ifdef HAVE_LIBAX25 fprintf(stderr,"ADD AX.25 TNC\n"); Config_AX25(w, 0, port); #else // HAVE_LIBAX25 fprintf(stderr,"AX.25 support not compiled into Xastir!\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00021")); #endif // HAVE_LIBAX25 break; case DEVICE_NET_STREAM: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET STREAM\n"); } Config_Inet(w, 0, port); break; case DEVICE_NET_DATABASE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET DATABASE\n"); } Config_Database(w, 0, port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SQL DATABASE\n"); } Config_sql_Database(w, 0, port); break; #endif /* HAVE_DB */ case DEVICE_NET_AGWPE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET AGWPE\n"); } Config_AGWPE(w, 0, port); break; default: break; } } /* rebuild list */ begin_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); modify_device_list(2,0); end_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); } /*fprintf(stderr,"SELECTION is %s\n",temp);*/ XtFree(temp); } } // clientData: // 0 = Add // 1 = Delete // 2 = Properties // void interface_option(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, form, label, button_add, button_cancel; char *what = (char *)clientData; int i,x,n,do_w; char *temp; char temp2[50]; int port; XmString *list; // int data_on,pos; int found; Atom delw; XmString str_ptr; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ // data_on=0; // pos=0; found=0; do_w=atoi(what); switch (do_w) { case 0:/* add interface */ if (!choose_interface_dialog) { choose_interface_dialog = XtVaCreatePopupShell(langcode("WPUPCIF002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("interface_option pane",xmPanedWindowWidgetClass, choose_interface_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("interface_option form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); label = XtVaCreateManagedWidget(langcode("WPUPCIF002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, MAX_IFACE_DEVICE_TYPES); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; interface_type_list = XmCreateScrolledList(form,"interface_option list",al,ac); n=1; for (i=1; i key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(choose_interface_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(choose_interface_dialog), XtWindow(choose_interface_dialog)); } break; case 1:/* delete interface */ case 2:/* interface properties */ /* get option selected */ XtVaGetValues(control_iface_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if(XmListPosSelected(control_iface_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { /* look at list data (Must be "Device" port#) */ if (2 != sscanf(temp,"%49s %d",temp2,&port)) { fprintf(stderr,"interface_option:sscanf parsing error\n"); } if(do_w==1) { /* delete interface */ /*fprintf(stderr,"delete interface port %d\n",port);*/ if (port_data[port].active==DEVICE_IN_USE) { /* shut down and delete port */ /*fprintf(stderr,"Shutting down port %d\n",port);*/ (void)del_device(port); } begin_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* delete item at that port */ modify_device_list(1,port); /* Clear device */ devices[port].device_type=DEVICE_NONE; devices[port].device_name[0] = '\0'; devices[port].radio_port[0] = '\0'; devices[port].device_converse_string[0] = '\0'; devices[port].device_host_name[0] = '\0'; devices[port].device_host_pswd[0] = '\0'; devices[port].device_host_filter_string[0] = '\0'; devices[port].comment[0] = '\0'; devices[port].unproto1[0] = '\0'; devices[port].unproto2[0] = '\0'; devices[port].unproto3[0] = '\0'; devices[port].unproto_igate[0] = '\0'; devices[port].style=0; devices[port].igate_options=0; devices[port].transmit_data=0; devices[port].reconnect=0; devices[port].connect_on_startup=0; end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); } else { /* Properties */ begin_critical_section(&devices_lock, "interface_gui.c:interface_option" ); if (debug_level & 1) { fprintf(stderr,"Changing device %s on port %d\n", dtype[devices[port].device_type].device_name,port); } switch (devices[port].device_type) { case DEVICE_SERIAL_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC\n"); } Config_TNC(w, DEVICE_SERIAL_TNC, 1, port); break; case DEVICE_SERIAL_KISS_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL KISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_KISS_TNC, 1, port); break; case DEVICE_SERIAL_MKISS_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL MKISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_MKISS_TNC, 1, port); break; case DEVICE_SERIAL_TNC_HSP_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC with HSP GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_HSP_GPS, 1, port); break; case DEVICE_SERIAL_TNC_AUX_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC with AUX GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_AUX_GPS, 1, port); break; case DEVICE_SERIAL_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL GPS\n"); } Config_GPS(w, 1, port); break; case DEVICE_SERIAL_WX: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL WX\n"); } Config_WX(w, 1, port); break; case DEVICE_NET_WX: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify Network WX\n"); } Config_NWX(w, 1, port); break; case DEVICE_NET_GPSD: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify Network GPS\n"); } Config_NGPS(w, 1, port); break; case DEVICE_AX25_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify AX.25 TNC\n"); } Config_AX25(w, 1, port); break; case DEVICE_NET_STREAM: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET STREAM\n"); } Config_Inet(w, 1, port); break; case DEVICE_NET_DATABASE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET DATABASE\n"); } Config_Database(w, 1, port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SQL DATABASE\n"); } Config_sql_Database(w, 1, port); break; #endif /* HAVE_DB */ case DEVICE_NET_AGWPE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET AGWPE\n"); } Config_AGWPE(w, 1, port); break; default: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); break; } } /*fprintf(stderr,"interface - %s\n",temp);*/ XtFree(temp); } break; default: break; } } /*****************************************************/ /* Control Interface GUI */ /*****************************************************/ extern void startup_all_or_defined_port(int port); extern void shutdown_all_active_or_defined_port(int port); void start_stop_interface( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *which = (char *)clientData; int do_w; char temp2[50]; int i,x; char *temp; int port; XmString *list; int found; busy_cursor(appshell); found=0; /* get option selected */ XtVaGetValues(control_iface_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(control_iface_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { /* delete list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // modify_device_list(4,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); /* look at list data (Must be "Device" port#) */ if (2 != sscanf(temp,"%49s %d",temp2,&port)) { fprintf(stderr,"start_stop_interface:sscanf parsing error\n"); } /*fprintf(stderr,"Port to change %d\n",port);*/ do_w = atoi(which); if (do_w) { shutdown_all_active_or_defined_port(port); } else { /*fprintf(stderr,"DO port up\n");*/ if (port_data[port].active==DEVICE_IN_USE) { /*fprintf(stderr,"Device was up, Shutting down\n");*/ shutdown_all_active_or_defined_port(port); } /* now start port */ startup_all_or_defined_port(port); } /* rebuild list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // modify_device_list(3,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // Rebuild the interface control list update_interface_list(); XtFree(temp); } } void start_stop_all_interfaces( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *which = (char *)clientData; // Whether to start or stop the interfaces int do_w; busy_cursor(appshell); //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // modify_device_list(4,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); do_w = atoi(which); if (do_w) // We wish to shut down all ports { shutdown_all_active_or_defined_port(-1); } else // We wish to start up all ports { startup_all_or_defined_port(-2); } /* rebuild list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // modify_device_list(3,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // Rebuild the interface control list update_interface_list(); } void Control_interface_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&control_interface_dialog_lock, "interface_gui.c:Control_interface_destroy_shell" ); XtDestroyWidget(shell); control_interface_dialog = (Widget)NULL; end_critical_section(&control_interface_dialog_lock, "interface_gui.c:Control_interface_destroy_shell" ); } void control_interface( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget scrollwindow, rowcol, form, button_start, button_stop, button_start_all, button_stop_all, button_cancel; static Widget button_add, button_delete, button_properties; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!control_interface_dialog) { begin_critical_section(&control_interface_dialog_lock, "interface_gui.c:control_interface" ); control_interface_dialog = XtVaCreatePopupShell(langcode("IFPUPCT000"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, TRUE, XmNfontList, fontlist1, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, control_interface_dialog, XmNscrollingPolicy, XmAUTOMATIC, NULL); rowcol = XtVaCreateWidget("control_interface rowcol", xmRowColumnWidgetClass, scrollwindow, XmNorientation, XmVERTICAL, XmNnumColumns, 1, XmNpacking, XmPACK_TIGHT, XmNisAligned, TRUE, XmNentryAlignment, XmALIGNMENT_CENTER, XmNkeyboardFocusPolicy, XmEXPLICIT, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, MAX_IFACE_DEVICES); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; control_iface_list = XmCreateScrolledList(rowcol,"control_interface list",al,ac); /* build device list */ begin_critical_section(&devices_lock, "interface_gui.c:control_interface" ); modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:control_interface" ); form = XtVaCreateWidget("control_interface form",xmFormWidgetClass, rowcol, XmNfractionBase, 4, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); button_start = XtVaCreateManagedWidget(langcode("IFPUPCT001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbottomAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_start_all = XtVaCreateManagedWidget(langcode("IFPUPCT003"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbottomAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_add = XtVaCreateManagedWidget(langcode("UNIOP00007"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_delete = XtVaCreateManagedWidget(langcode("UNIOP00008"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_stop = XtVaCreateManagedWidget(langcode("IFPUPCT002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_stop_all = XtVaCreateManagedWidget(langcode("IFPUPCT004"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_properties = XtVaCreateManagedWidget(langcode("UNIOP00009"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_add, XmNactivateCallback, interface_option, "0"); XtAddCallback(button_delete, XmNactivateCallback, interface_option, "1"); XtAddCallback(button_properties, XmNactivateCallback, interface_option, "2"); XtAddCallback(button_cancel, XmNactivateCallback, Control_interface_destroy_shell, control_interface_dialog); XtAddCallback(button_start, XmNactivateCallback, start_stop_interface, "0"); XtAddCallback(button_stop, XmNactivateCallback, start_stop_interface, "1"); XtAddCallback(button_start_all, XmNactivateCallback, start_stop_all_interfaces, "0"); XtAddCallback(button_stop_all, XmNactivateCallback, start_stop_all_interfaces, "1"); delw = XmInternAtom(XtDisplay(control_interface_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(control_interface_dialog, delw, Control_interface_destroy_shell, (XtPointer)control_interface_dialog); XtVaSetValues(control_iface_list, XmNbackground, colors[0x0f], NULL); pos_dialog(control_interface_dialog); XtManageChild(control_iface_list); XtManageChild(form); XtManageChild(rowcol); resize_dialog(rowcol, control_interface_dialog); end_critical_section(&control_interface_dialog_lock, "interface_gui.c:control_interface" ); XtPopup(control_interface_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(control_interface_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(control_interface_dialog), XtWindow(control_interface_dialog)); } } void interface_status(Widget w) { int i; char s; char opt; int read_data; int write_data; read_data=0; write_data=0; s='\0'; begin_critical_section(&devices_lock, "interface_gui.c:interface_status" ); for (i=0; i < MAX_IFACE_DEVICES; i++) { read_data=0; write_data=0; opt='\0'; if (devices[i].device_type!=DEVICE_NONE) { switch(devices[i].device_type) { case DEVICE_SERIAL_TNC: s='0'; // Select icon for status bar break; case DEVICE_SERIAL_TNC_HSP_GPS: s='1'; // Select icon for status bar break; case DEVICE_SERIAL_GPS: s='2'; // Select icon for status bar break; case DEVICE_SERIAL_WX: case DEVICE_NET_WX: s='3'; // Select icon for status bar break; case DEVICE_SQL_DATABASE: s='8'; // Select icon for status bar break; case DEVICE_NET_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_AGWPE: s='4'; // Select icon for status bar break; case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: s='5'; // Select icon for status bar break; case DEVICE_NET_GPSD: s='6'; // Select icon for status bar break; case DEVICE_SERIAL_TNC_AUX_GPS: s='7'; // Select icon for status bar break; default: break; } if (port_data[i].active==DEVICE_IN_USE) { if (port_data[i].status==DEVICE_UP) { if (port_data[i].bytes_input_last != port_data[i].bytes_input) { if (begin_critical_section(&port_data_lock, "interface_gui.c:interface_status(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } port_data[i].bytes_input_last = port_data[i].bytes_input; port_data[i].port_activity = 1; if (end_critical_section(&port_data_lock, "interface_gui.c:interface_status(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } read_data=1; } if (port_data[i].bytes_output_last != port_data[i].bytes_output) { if (begin_critical_section(&port_data_lock, "interface_gui.c:interface_status(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } port_data[i].bytes_output_last = port_data[i].bytes_output; port_data[i].port_activity = 1; if (end_critical_section(&port_data_lock, "interface_gui.c:interface_status(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } write_data=1; } if (write_data) { opt='>'; } else { if (read_data) { opt='<'; } else { opt='^'; } } } else { opt='*'; } } else { opt='\0'; } symbol(w,0,'~',s,opt,XtWindow(iface_da),0,(i*10),0,' '); } else { symbol(w,0,'~','#','\0',XtWindow(iface_da),0,(i*10),0,' '); } } end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); } Xastir-Release-2.2.2/src/io-common.c000066400000000000000000000030341501463444000171760ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "io.h" #include // Must be last include file #include "leak_detection.h" int io_out_i4(struct io_file *f,int pos,int o) { unsigned char x[4]; x[0] = o >> 24; x[1] = o >> 16; x[2] = o >> 8; x[3] = o; return io_out(f,pos,x,sizeof x); } int io_out_i2(struct io_file *f,int pos,short int o) { unsigned char x[2]; x[0] = o >> 8; x[1] = o; return io_out(f,pos,x,sizeof x); } int io_out_i1(struct io_file *f,int pos,signed char o) { return io_out(f,pos,&o,sizeof o); } int io_in_i4(struct io_file *f,int pos,int *i) { unsigned char x[4]; const int r = io_in(f,pos,x,sizeof x); if (i) { *i = (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]; } return r; } int io_in_i2(struct io_file *f,int pos,short *i) { unsigned char x[2]; const int r = io_in(f,pos,x,sizeof x); if (i) { *i = (x[0] << 8) | x[1]; } return r; } int io_in_i1(struct io_file *f,int pos,signed char *i) { return io_in(f,pos,i,sizeof *i); } int io_strntoi(const char *str,int len) { int r = 0; int sign = 1; const char * const end = str + len; while (end != str && isspace((int)*str)) { ++str; } if (end != str && *str == '-') { (sign *= -1),++str; } if (end != str && *str == '+') { ++str; } while (end != str && isdigit((int)*str)) { r = *str++ - '0' + 10 * r; } return r * sign; } Xastir-Release-2.2.2/src/io-mmap.c000066400000000000000000000131121501463444000166360ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "io.h" #include #include #include #include #include #include #include #include #include #include "xastir.h" // Must be last include file #include "leak_detection.h" struct io_file { int fd; int prot; off_t file_size; void *map; off_t map_offset; size_t map_size,map_page; char buffer[4096]; off_t buffer_offset; size_t buffer_size; }; /* Writes any buffered append data. Returns nonzero iff failed. */ static int unbuffer(struct io_file *f) { int r; if (!f->buffer_size) { return 0; } r = write(f->fd,f->buffer,f->buffer_size); if (r > 0) { f->buffer_offset += r; f->buffer_size -= r; if (f->buffer_offset > f->file_size) { f->file_size = f->buffer_offset; } } if (0 != f->buffer_size) { perror("write"); return -1; } return 0; } /* Resets f->file_size to the actual size of the file. Returns nonzero iff failed. */ static int checksize(struct io_file *f) { struct stat buf; if (unbuffer(f)) { return -1; } if (fstat(f->fd,&buf)) { perror("fstat"); return -1; } f->file_size = buf.st_size; return 0; } struct io_file *io_open(const char *fname) { struct io_file * const f = malloc(sizeof *f); if (NULL == f) { return NULL; } f->fd = open(fname,O_RDWR|O_CREAT,0666); f->prot = PROT_READ|PROT_WRITE; if (f->fd < 0) { f->fd = open(fname,O_RDONLY); f->prot = PROT_READ; } if (f->fd < 0) { perror(fname); free(f); return NULL; } f->map = NULL; f->map_offset = 0; f->map_size = 0; f->map_page = getpagesize(); f->file_size = 0; f->buffer_offset = 0; f->buffer_size = 0; if (checksize(f)) { close(f->fd); free(f); return NULL; } return f; } void io_close(struct io_file *f) { if (NULL != f) { unbuffer(f); close(f->fd); if (NULL != f->map) { munmap(f->map,f->map_size); } free(f); } } /* Attempts to make the mapping cover [pos,pos+len), or at least [pos]. Returns nonzero iff failed. */ static int remap(struct io_file *f,int pos,int UNUSED(len) ) { if (pos < (int)f->map_offset || pos >= (int)(f->map_offset + f->map_size) ) { const int flags = MAP_SHARED; const off_t b1 = pos / f->map_page * f->map_page; const off_t e1 = b1 + f->map_page; off_t b2 = f->map_offset; off_t e2 = b2 + f->map_size; if (b2 > b1) { b2 = b1 - (b2 - b1); } if (b2 < 0) { b2 = 0; } if (e2 < e1) { e2 = e1 + (e1 - e2); } if (NULL != f->map) { munmap(f->map,f->map_size); } if (MAP_FAILED != (f->map = mmap(NULL,e2 - b2,f->prot,flags,f->fd,b2))) { f->map_size = e2 - b2; f->map_offset = b2; } else if (MAP_FAILED != (f->map = mmap(NULL,e1 - b1,f->prot,flags,f->fd,b1))) { f->map_size = e1 - b1; f->map_offset = b1; } else { perror("mmap"); f->map = NULL; f->map_size = 0; f->map_offset = 0; return -1; } } return 0; } int io_out(struct io_file *f,int pos,const void *o,int len) { int end = pos + len; if (0 == len) { return pos; } if (NULL == f || -1 == pos) { return -1; } if (NULL == o) { return pos + len; } if (remap(f,pos,len)) { return -1; } if (pos < f->file_size) { assert(pos >= f->map_offset); if (pos >= f->buffer_offset && unbuffer(f)) { return -1; } if (end > (int)(f->map_offset + f->map_size)) { end = f->map_offset + f->map_size; } if (end > f->file_size) { end = f->file_size; } memcpy(pos - f->map_offset + (char *) f->map,o,end - pos); } else { if (pos < f->buffer_offset || pos > (int)(f->buffer_offset + f->buffer_size)) { if (unbuffer(f)) { return -1; } if (lseek(f->fd,pos,SEEK_SET) == (off_t) -1) { perror("lseek"); return -1; } assert(0 == f->buffer_size); f->buffer_offset = pos; } else if (pos == (int)(f->buffer_offset + sizeof f->buffer)) if (unbuffer(f)) { return -1; } assert(pos >= f->buffer_offset && pos <= (int)(f->buffer_offset + f->buffer_size)); if (end > (int)(f->buffer_offset + sizeof f->buffer)) { end = f->buffer_offset + sizeof f->buffer; } memcpy(&f->buffer[pos - f->buffer_offset],o,end - pos); if ((int)(end - f->buffer_offset) > (int)f->buffer_size) { f->buffer_size = end - f->buffer_offset; } } return io_out(f,end,end - pos + (char *) o,len + pos - end); } int io_in(struct io_file *f,int pos,void *i,int len) { int end = pos + len; if (0 == len) { return pos; } if (NULL == f || -1 == pos) { return -1; } if (NULL == i) { return pos + len; } if (remap(f,pos,len)) { return -1; } if (unbuffer(f)) { return -1; } if (pos >= f->file_size && checksize(f)) { return -1; } if (pos >= f->file_size) { /* TODO: fill with zeroes instead */ fputs("read: EOF\n",stderr); return -1; } if (end > (int)(f->map_offset + f->map_size)) { end = f->map_offset + f->map_size; } if (end > f->file_size) { end = f->file_size; } memcpy(i,pos - f->map_offset + (char *) f->map,end - pos); return io_in(f,end,end - pos + (char *) i,len + pos - end); } Xastir-Release-2.2.2/src/io.h000066400000000000000000000043141501463444000157170ustar00rootroot00000000000000 /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2023 The Xastir Group * * This file defines the I/O interface used for access to index files. * There are two implementations of this interface; io-mmap.c uses Unix * mmap() and is quite efficient, and io-stdio.c uses C stdio and is slower * but more portable. Which one is used depends on which file is compiled. */ #ifndef GEOCODER_IO_H #define GEOCODER_IO_H struct io_file; /* Open a file. The file will be created if it did not exist. * It will be opened R/W if possible, R/O otherwise. * Returns NULL on error.*/ struct io_file *io_open(const char *fname); void io_close(struct io_file *); /* In general, all I/O is done with an offset ("pos") directly. There is * no "current position" associated with the file handle. This is really * a lot more convenient for random access. * * Functions almost always return the position just after the data that was * read or written, so they may be easily "chained" to read or write several * contiguous items; this makes it almost as easy to do this as it would be * with a file pointer, which keeping things more flexible. * * If an error occurs, the return value will be -1. If the input "pos" * is -1, these functions will silently return -1, so you can safely wait * until the end of a "chain" to check for errors, if you want. * * Integer values are written in byte-order-independent fashion. */ int io_out(struct io_file *,int pos,const void *o,int len); /* Write data */ int io_out_i4(struct io_file *,int pos,int o); /* Write an int */ int io_out_i2(struct io_file *,int pos,short o); /* Write a short */ int io_out_i1(struct io_file *,int pos,signed char o); /* Write a char */ int io_in(struct io_file *,int pos,void *i,int len); /* Read data */ int io_in_i4(struct io_file *,int pos,int *i); /* Read an int */ int io_in_i2(struct io_file *,int pos,short *i); /* Read a short */ int io_in_i1(struct io_file *,int pos,signed char *i); /* Read a char */ /* Convert a string to integer. Like strtol(), only with a count. * Kept here, 'cuz ... where else? */ int io_strntoi(const char *str,int len); #endif Xastir-Release-2.2.2/src/lang.c000066400000000000000000000203461501463444000162270ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include "xastir.h" #include "lang.h" // Must be last include file #include "leak_detection.h" char lang_code[MAX_LANG_ENTRIES][MAX_LANG_CODE+1]; char *lang_code_ptr[MAX_LANG_ENTRIES]; char lang_buffer[MAX_LANG_BUFFER]; char lang_hotkey[MAX_LANG_ENTRIES]; int lang_code_number; long buffer_len; char invalid_code[50]; char *langcode(char *code) { int i; // Create an invalid code string to return in case we can't find the proper string if (strlen(code) <= MAX_LANG_CODE) // Code is ok { xastir_snprintf(invalid_code, sizeof(invalid_code), "IC>%s", code); } else // Code is too long { xastir_snprintf(invalid_code, sizeof(invalid_code), "IC>TOO LONG:%s",code); fprintf(stderr,"IC>TOO LONG:%s\n",code); return(invalid_code); } if(lang_code_number>0) { for(i=0; i0) { for(i=0; i0) { /* data line */ if(lang_code_number < MAX_LANG_ENTRIES) { if(buffer_len < MAX_LANG_BUFFER) { if(strchr(line,'|')!=NULL) { temp_ptr=strtok(line,"|"); /* get code */ if (temp_ptr!=NULL) { if(strlen(temp_ptr)<=MAX_LANG_CODE) { lcok=1; for (lt=0; lt on line %d\n",temp_ptr,line_num); } } else { ok=0; fprintf(stderr,"Language code on line %d is too long\n",line_num); } } else { ok=0; fprintf(stderr,"Missing Language code data on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Language code parse error on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Language data buffer full error on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Too many Language codes error on line %d\n",line_num); } if (ok) { if (debug_level & 32) fprintf(stderr,"Code #%d <%s> data <%s> hotkey <%c>\n",lang_code_number, lang_code[lang_code_number],lang_code_ptr[lang_code_number], lang_hotkey[lang_code_number]); lang_code_number++; } line[0]='\0'; } line_num++; } } } (void)fclose(f); } else { ok=0; fprintf(stderr,"Could not read Language file: %s!\n",filename); } if (debug_level & 32) { fprintf(stderr,"LANG %d\n",lang_code_number); } return(ok); } Xastir-Release-2.2.2/src/lang.h000066400000000000000000000023531501463444000162320ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_LANG_H #define XASTIR_LANG_H #define MAX_LANG_LINE_SIZE 800 #define MAX_LANG_CODE 10 #define MAX_LANG_ENTRIES 3000 #define MAX_LANG_BUFFER 30000 extern int load_language_file(char *filename); extern char *langcode(char *code); extern char langcode_hotkey(char *code); #endif /* XASTIR_LANG_H */ Xastir-Release-2.2.2/src/lclint.script000077500000000000000000000127451501463444000176640ustar00rootroot00000000000000#!/usr/bin/perl # # This is for use with lclint 2.5 or later. # # http://lclint.cs.virginia.edu/ # #$options = "+forcehints +gnuextensions -warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include +trytorecover"; $options = "+D__LCLINT__ +forcehints -warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include -I../devel +trytorecover"; #$options = "-warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include +trytorecover -boolops -predboolint"; #$options = "-unqualifiedtrans -branchstate -mayaliasunique -exportlocal -linelength 1000 -predboolothers -nullassign -warnposix -I/usr/X11/LessTif/Motif1.2/include -I/usr/local/include -I/usr/X11/include +trytorecover -boolops -predboolint"; $grep = " \\ | grep -v \"Only storage\" \\ | grep -v \"New fresh\" \\ | grep -v \"Immediate address\" \\ | grep -v \"Fresh storage\" \\ | grep -v \"exported but not used\" \\ | grep -v Boolean \\ | grep -v \"in function\" \\ | grep -v \"used before definition\" \\ | grep -v \"comment inside comment\" \\ | grep -v \"Start comment inside comment\" \\ | grep -v \"declared unique\" \\ | grep -v \"used after being released\" \\ | grep -v \"referencing released storage\" \\ | grep -v \"Dereference\" \\ | grep -v \"Passed storage\" \\ | grep -v \"ossibly null\" \\ | grep -v \"Clauses\" \\ | grep -v \"may become null\" \\ | grep -v \"reachable from\" \\ | grep -v \"null storage derivable\" \\ | grep -v \"Implicitly\" \\ | grep -v \"Unqualified\" \\ | grep -v \"kept in true\" \\ | grep -v \"released in true branch\" "; #$grep = ""; `(nice splint $options ../callpass/callpass.c 2>&1) $grep >callpass.lint`; `echo "\n\nalert.c" > xastir.lint`; `(nice splint $options alert.c 2>&1) $grep >> xastir.lint`; `echo "\n\nbulletin_gui.c" >> xastir.lint`; `(nice splint $options bulletin_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\ncolor.c" >> xastir.lint`; `(nice splint $options color.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndatum.c" >> xastir.lint`; `(nice splint $options datum.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndb.c" >> xastir.lint`; `(nice splint $options db.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndb_gis.c" >> xastir.lint`; `(nice splint $options db_gis.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndraw_symbols.c" >> xastir.lint`; `(nice splint $options draw_symbols.c 2>&1) $grep >> xastir.lint`; `echo "\n\nfcc_data.c" >> xastir.lint`; `(nice splint $options fcc_data.c 2>&1) $grep >> xastir.lint`; `echo "\n\nfestival.c" >> xastir.lint`; `(nice splint $options festival.c 2>&1) $grep >> xastir.lint`; `echo "\n\ngps.c" >> xastir.lint`; `(nice splint $options gps.c 2>&1) $grep >> xastir.lint`; `echo "\n\nhostname.c" >> xastir.lint`; `(nice splint $options hostname.c 2>&1) $grep >> xastir.lint`; `echo "\n\nigate.c" >> xastir.lint`; `(nice splint $options igate.c 2>&1) $grep >> xastir.lint`; `echo "\n\ninterface.c" >> xastir.lint`; `(nice splint $options interface.c 2>&1) $grep >> xastir.lint`; `echo "\n\ninterface_gui.c" >> xastir.lint`; `(nice splint $options interface_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlang.c" >> xastir.lint`; `(nice splint $options lang.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlist_gui.c" >> xastir.lint`; `(nice splint $options list_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocate_gui.c" >> xastir.lint`; `(nice splint $options locate_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocation.c" >> xastir.lint`; `(nice splint $options location.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocation_gui.c" >> xastir.lint`; `(nice splint $options location_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmain.c" >> xastir.lint`; `(nice splint $options main.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmaps.c" >> xastir.lint`; `(nice splint $options maps.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmessages.c" >> xastir.lint`; `(nice splint $options messages.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmessages_gui.c" >> xastir.lint`; `(nice splint $options messages_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\npopup_gui.c" >> xastir.lint`; `(nice splint $options popup_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nrac_data.c" >> xastir.lint`; `(nice splint $options rac_data.c 2>&1) $grep >> xastir.lint`; `echo "\n\nrotated.c" >> xastir.lint`; `(nice splint $options rotated.c 2>&1) $grep >> xastir.lint`; `echo "\n\nsnprintf.c" >> xastir.lint`; `(nice splint $options snprintf.c 2>&1) $grep >> xastir.lint`; `echo "\n\nsound.c" >> xastir.lint`; `(nice splint $options sound.c 2>&1) $grep >> xastir.lint`; `echo "\n\ntrack_gui.c" >> xastir.lint`; `(nice splint $options track_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nutil.c" >> xastir.lint`; `(nice splint $options util.c 2>&1) $grep >> xastir.lint`; `echo "\n\nview_message_gui.c" >> xastir.lint`; `(nice splint $options view_message_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nwx.c" >> xastir.lint`; `(nice splint $options wx.c 2>&1) $grep >> xastir.lint`; `echo "\n\nwx_gui.c" >> xastir.lint`; `(nice splint $options wx_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nxa_config.c" >> xastir.lint`; `(nice splint $options xa_config.c 2>&1) $grep >> xastir.lint`; #'(nice splint $options alert.c bulletin_gui.c color.c datum.c db.c db_gis.c draw_symbols.c fcc_data.c festival.c gps.c hostname.c igate.c interface.c interface_gui.c lang.c list_gui.c locate_gui.c location.c location_gui.c main.c maps.c messages.c messages_gui.c popup_gui.c rac_data.c rotated.c snprintf.c sound.c track_gui.c util.c view_message_gui.c wx.c wx_gui.c xa_config.c 2>&1) $grep > xastir.lint`; Xastir-Release-2.2.2/src/leak_detection.h000066400000000000000000000061621501463444000202650ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* All of the misc entry points to be included for all packages */ #ifndef _LEAK_DETECTION_H #define _LEAK_DETECTION_H // If libgc is installed, uncomment this next line to enable memory // leak detection: #define DETECT_MEMORY_LEAKS // Defines for including the libgc garbage collection library. // This enables automatic garbage collection of unused memory, // very similar to the garbage collection in Java. Get libgc from // here: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ // // This will cause stats to be printed every 60 seconds, 'cuz we // call GC_collect via a macro from UpdateTime() once per minute: // export GC_PRINT_STATS=1; xastir & // // Compile libgc with this option for more debugging output. I // didn't do so: --enable-full_debug // // If we enable these thread options, Xastir won't link with the // library. Since we don't allocate dynamic memory in the child // threads anyway, skip them. // --enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark // // Call GC_gcollect at appropriate points to check for leaks. We do // this via the CHECK_LEAKS macro called from main.c:UpdateTime. // // // Note: The thread includes must be done before the libgc includes // as libgc redefines some thread stuff so that it cooperates with // the garbage collector routines. Any code module that does // malloc's/free's or thread operations should include // leak_detection.h as the last include if at all possible, and // should not include pthread.h themselves. // #include #include /* Where malloc/free definitions reside */ #ifdef HAVE_DMALLOC #include #endif // HAVE_DMALLOC // #ifdef HAVE_GC_H #ifdef HAVE_LIBGC // We use this define to enable code in *.c files #define USING_LIBGC // Set up for threads #define GC_THREADS #ifdef __LINUX__ #define GC_LINUX_THREADS #endif // __LINUX__ // #define _REENTRANT // Ask for more debugging #define GC_DEBUG #include #define malloc(n) GC_MALLOC(n) #define calloc(m,n) GC_MALLOC((m)*(n)) #define free(p) GC_FREE(p) #define realloc(p,n) GC_REALLOC((p),(n)) #define CHECK_LEAKS() GC_gcollect() #endif // HAVE_LIBGC #endif // HAVE_GC_H #endif /* LEAK_DETECTION_H */ Xastir-Release-2.2.2/src/list_gui.c000066400000000000000000003563731501463444000171410ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include "xastir.h" #include "main.h" #include "messages.h" #include "draw_symbols.h" #include "list_gui.h" #include "database.h" #include #include // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define SL_MAX 20 #define ROWS 17 // List Numbers (defined in list_gui.h) // 0: LST_ALL - all stations list // 1: LST_MOB - mobile stations list // 2: LST_WX - WX stations list // 3: LST_TNC - local stations list // 4: LST_TIM - last stations // 5: LST_OBJ - Objects/Items // 6: LST_MYOBJ - My Objects/Items // 7: LST_NUM - Number of lists; for use in array definitions below Widget station_list_dialog[LST_NUM]; // store list definitions static xastir_mutex station_list_dialog_lock; // Mutex lock for above Widget SL_list[LST_NUM][SL_MAX]; Widget SL_da[LST_NUM][SL_MAX]; Widget SL_call[LST_NUM][SL_MAX]; char * SL_callback[LST_NUM][SL_MAX]; Pixmap SL_icon[LST_NUM][SL_MAX]; // icons for different lists and list rows Pixmap blank_icon; // holds an empty icon Widget SL_scroll[LST_NUM]; Widget SL_wx_wind_course[LST_NUM][SL_MAX]; Widget SL_wx_wind_speed[LST_NUM][SL_MAX]; Widget SL_wx_wind_gust[LST_NUM][SL_MAX]; Widget SL_wx_temp[LST_NUM][SL_MAX]; Widget SL_wx_hum[LST_NUM][SL_MAX]; Widget SL_wx_baro[LST_NUM][SL_MAX]; Widget SL_wx_rain_h[LST_NUM][SL_MAX]; Widget SL_wx_rain_00[LST_NUM][SL_MAX]; Widget SL_wx_rain_24[LST_NUM][SL_MAX]; Widget SL_course[LST_NUM][SL_MAX]; Widget SL_speed[LST_NUM][SL_MAX]; Widget SL_alt[LST_NUM][SL_MAX]; Widget SL_lat_long[LST_NUM][SL_MAX]; Widget SL_packets[LST_NUM][SL_MAX]; Widget SL_sats[LST_NUM][SL_MAX]; Widget SL_my_course[LST_NUM][SL_MAX]; Widget SL_my_distance[LST_NUM][SL_MAX]; Widget SL_pos_time[LST_NUM][SL_MAX]; Widget SL_node_path[LST_NUM][SL_MAX]; Widget SL_power_gain[LST_NUM][SL_MAX]; Widget SL_comments[LST_NUM][SL_MAX]; int station_list_first = 1; int list_size_h[LST_NUM]; // height of entire list widget int list_size_w[LST_NUM]; // width of entire list widget int list_size_i[LST_NUM]; // size initialized, dirty hack, but works... int last_offset[LST_NUM]; char top_call[LST_NUM][MAX_CALLSIGN+1]; // call of first list entry or empty string for always first call time_t top_time; // time of first list entry or 0 for always newest station int top_sn; // serial number for unique time index time_t last_list_upd; // time of last list update int units_last; #define LIST_UPDATE_CYCLE 2 /* Minimum time between list updates in seconds, we want */ /* immediate update, but not in high traffic situations */ void list_gui_init(void) { init_critical_section( &station_list_dialog_lock ); } // get a valid list member, starting from current station in the desired direction // returns pointer to found member or NULL void get_list_member(int type, DataRow **p_station, int skip, int forward) { char found; if ((*p_station) == NULL) // default start value { if (type == LST_TIM) { (*p_station) = t_newest; } else { (*p_station) = n_first; } } if (skip == 1) // skip before searching { if (type != LST_TIM) { if (forward == 1) { (void)next_station_name(p_station); } else { (void)prev_station_name(p_station); } } else { if (forward == 1) { (void)prev_station_time(p_station); } else { (void)next_station_time(p_station); } } } found = (char)FALSE; switch (type) // DK7IN: here I'm trading code size for speed... { case LST_ALL: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) // ignore deleted objects { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_MOB: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->newest_trackpoint != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->newest_trackpoint != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_WX: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->weather_data != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->weather_data != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_TNC: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ((*p_station)->flag & ST_VIATNC) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ((*p_station)->flag & ST_VIATNC) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_TIM: if (forward == 1) // forward in list, backward in time while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) // ignore deleted objects { found = (char)TRUE; } else { (*p_station) = (*p_station)->t_older; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->t_newer; } } break; case LST_OBJ: if (forward == 1) while (!found && (*p_station) != NULL) { // Show deleted objects/items as well if ( ( (((*p_station)->flag & ST_OBJECT) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) ) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ( (((*p_station)->flag & ST_VIATNC) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) ) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_MYOBJ: // We should really show the active AND inactive objects. This is // so that inactive ones can be resurrected. Probably should do // this for all objects, not just ones we own. if (forward == 1) while (!found && (*p_station) != NULL) { // Show deleted objects/items as well if ( ( (((*p_station)->flag & ST_OBJECT) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) // && ( is_my_call( (*p_station)->origin,1)) ) // Exact match include SSID && ( is_my_object_item(*p_station)) ) // Exact match include SSID { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ( (((*p_station)->flag & ST_VIATNC) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) // && ( is_my_call( (*p_station)->origin,1)) ) // Exact match includes SSID && ( is_my_object_item(*p_station)) ) // Exact match include SSID { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; default: break; } } // initialization of station list at very first Station List call void init_station_lists(void) { int type,i; blank_icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); begin_critical_section(&station_list_dialog_lock, "list_gui.c:init_station_lists" ); for (type=0; typen_next) { if ((p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { switch (type) { case 0: // all stations list case 4: // last stations st++; break; case 1: // mobile stations list if (p_station->newest_trackpoint != NULL) { st++; } break; case 2: // WX stations list if (p_station->weather_data != NULL) { st++; } break; case 3: // local stations list if ((p_station->flag & ST_VIATNC) != 0) { st++; } break; case 5: // Object/Item list if ( ((p_station->flag & ST_OBJECT) != 0) || ((p_station->flag & ST_ITEM) != 0) ) { st++; } break; default: break; } } } if (st==0) { st=1; } return(st); } void station_list_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { int type; int i; type = atoi((char *)clientData); XtPopdown(station_list_dialog[type]); begin_critical_section(&station_list_dialog_lock, "list_gui.c:station_list_destroy_shell" ); for (i = 0; i < ROWS; i++) { if (SL_callback[type][i]) { XtFree(SL_callback[type][i]); SL_callback[type][i] = NULL; } } XtDestroyWidget(station_list_dialog[type]); station_list_dialog[type] = (Widget)NULL; // clear list definition end_critical_section(&station_list_dialog_lock, "list_gui.c:station_list_destroy_shell" ); } /* * Callback for station icon in list. * Calls a function to center the map on the selected station from the list. */ void Call_locate_station(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { if (clientData != NULL && strlen(clientData) > 0) { locate_station(w, clientData, 1,1,1); } } /* * *** This callback is not linked to a control on list yet. *** * Invokes the station information dialog for the selected station from the list. */ void Call_Station_data(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { if (clientData != NULL && strlen(clientData) > 0) { Station_data(w, clientData, NULL); } } /* * Fill list with new data */ void Station_List_fill(int type, int new_offset) { int row; char temp[11]; char *temp_ptr; Dimension w,h; // size of scrollbar in pixel Dimension ww,wh; // size of entire widget in pixel Dimension new_h; // overall height in pixel char stemp[400]; char stemp1[60]; char stemp2[60]; char temp_call[MAX_CALLSIGN+1]; long l_lat, l_lon; float value; WeatherRow *weather; DataRow *p_station; DataRow *p_name; int cur_offset; Dimension count, inview; int to_move, rows; int strwid; assert(ROWS <= SL_MAX); #define HGT 26 #define FUDGE 78 // type 0 all, 1: mobile, 2: WX, 3: local, 4: time, 5: Objects/Items // offset is the entry that should be displayed in the first line w = h = ww = wh = 0; if (station_list_dialog[type] != NULL) // if list is defined { // the list is first drawn very big then gets initialized to the correct size // I don't want the first wrong draw but don't know how to avoid it. DK7IN // there are wrong icons drawn on the first time... ???? if (list_size_i[type]) // we are initialized... { // ww, wh get width and height of entire widget: XtVaGetValues(station_list_dialog[type], XmNwidth, &ww, XmNheight, &wh, NULL); // w, h get width and height of scrollbar: XtVaGetValues(SL_scroll[type], XmNwidth, &w, XmNheight, &h, NULL); rows = (h+10) / HGT; // number of rows we can display, HGT pixel per row // fprintf(stderr,"fill: %d %d %d\n",wh, h, rows); } else { if (list_size_w[type] > 0 && list_size_h[type] > 0) { wh = list_size_h[type]; // restore size ww = list_size_w[type]; rows = (wh -FUDGE+10) / HGT; // Fudge Factor ??? // fprintf(stderr,"load: %d %d\n",wh, rows); } else { wh = 500; // start with this... ??? ww = 700; rows = (wh -FUDGE+10) / HGT; // Fudge Factor ??? // fprintf(stderr,"set: %d %d\n",wh, rows); } XtVaSetValues(station_list_dialog[type], XmNwidth, ww, NULL); // set widget width } if (rows > ROWS) // limit vertical size to data structure size for widgets { rows = ROWS; } if (rows < 1) { rows = 1; } // new_h = (rows*HGT) + (wh-h); // (rows + border) in pixel new_h = (rows*HGT) + FUDGE; // (rows + border) in pixel XtVaSetValues(station_list_dialog[type], XmNheight, new_h, NULL); // correct widget height list_size_h[type] = new_h; // remember current size list_size_w[type] = ww; list_size_i[type] = (int)TRUE; // don't init next time // look for the station to display on the first row... p_station = NULL; if (type == LST_TIM) { (void)search_station_time(&p_station,top_time,top_sn); // gives match or next station } else { (void)search_station_name(&p_station,top_call[type],1); // gives match or next station } get_list_member(type, &p_station, 0, 1); // get member in list for first row // get updated statistics, database may have changed since last call count = 0; cur_offset = 0; p_name = NULL; get_list_member(type, &p_name, 0, 1); // get first member in list while (p_name != NULL) { if (p_name == p_station) { cur_offset = count; // got offset of first row entry } count++; // count valid list member get_list_member(type, &p_name, 1, 1); // get next member in list } // check boundaries new_offset += cur_offset - last_offset[type]; // adjust for database changes if (count == 0) { count = 1; // empty } if (count - new_offset < rows) // bottom { new_offset = count - rows; // keep page filled, if possible } if (new_offset < 0) // top { new_offset = 0; } inview = rows; // number of stations in view if (inview > count) // partially filled { inview = count; } // update scrollbar parameters XtVaSetValues(SL_scroll[type], XmNmaximum, count, XmNpageIncrement, inview, XmNvalue, new_offset, XmNsliderSize, inview, NULL); if (new_offset == 0) // stay at first member { p_station = NULL; get_list_member(type, &p_station, 0, 1); // get first member in list } else { // if database changed, adjust first entry accordingly to_move = new_offset - cur_offset; while (to_move > 0) // move down, if necessary { if (p_station != 0) { get_list_member(type, &p_station, 1, 1); // gets next member in list } to_move--; } while (to_move < 0) // move up, if necessary { if (p_station != 0) { get_list_member(type, &p_station, 1, 0); // gets previous member in list } to_move++; } } // store current start position, we need a unique index for this to work (time?) if (new_offset == 0 || p_station == NULL) // keep it at top { if (type != LST_TIM) { top_call[type][0] = '\0'; } else { top_time = 0; top_sn = -1; } } else { if (type != LST_TIM) { xastir_snprintf(top_call[type], MAX_CALLSIGN+1, "%s", p_station->call_sign); // remember call at list top } else { top_time = p_station->sec_heard; // remember time station was heard top_sn = p_station->time_sn; // remember time serial number } } last_offset[type] = new_offset; // now fill the list rows xastir_snprintf(temp, sizeof(temp), "%d", (rows+new_offset)); // calculate needed string width strwid = (int)strlen(temp); // to keep it right justified begin_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List_fill" ); // Start filling in the rows of the widget for (row=0; rowflag & ST_ACTIVE) { ghost = 0; // Active object/item } else { ghost = 1; // Deleted object/item } } else { ghost = 0; // Not an object } // call (or object/item name) // Do this first as it is used for callback data later /* check to see if string changed and over write */ temp_ptr = XmTextFieldGetString(SL_call[type][row]); xastir_snprintf(temp_call, sizeof(temp_call), "%s", temp_ptr); XtFree(temp_ptr); if (strcmp(temp_call, p_station->call_sign) != 0) { XmTextFieldSetString(SL_call[type][row], p_station->call_sign); if (ghost) { XtSetSensitive(SL_call[type][row], FALSE); } else { XtSetSensitive(SL_call[type][row], TRUE); } XtManageChild(SL_call[type][row]); } // Blank out the icon first XtVaSetValues(SL_da[type][row],XmNlabelPixmap, blank_icon,NULL); XtManageChild(SL_da[type][row]); symbol(SL_da[type][row],0,'~','$','\0',SL_icon[type][row],0,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); // Now redraw it symbol(SL_da[type][row],ghost,p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay,SL_icon[type][row],ghost,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); if (SL_callback[type][row]) { XtRemoveCallback((XtPointer)SL_da[type][row], XmNactivateCallback, Call_locate_station, SL_callback[type][row]); XtFree(SL_callback[type][row]); } SL_callback[type][row] = XmTextFieldGetString(SL_call[type][row]); // Pressing the icon button centers the map on the station. XtAddCallback( (XtPointer)SL_da[type][row], XmNactivateCallback, Call_locate_station, SL_callback[type][row] ); // number in list xastir_snprintf(temp, sizeof(temp), "%*d", strwid, (row+1+new_offset)); XmTextFieldSetString(SL_list[type][row],temp); XtManageChild(SL_list[type][row]); switch (type) { case LST_TNC: // local stations list case LST_TIM: // last stations list case LST_ALL: // stations list case LST_OBJ: // objects/items case LST_MYOBJ: // my objects/items xastir_snprintf(stemp, sizeof(stemp), "%5d", (int)p_station->num_packets); XmTextFieldSetString(SL_packets[type][row],stemp); XtManageChild(SL_packets[type][row]); if (strlen(p_station->pos_time) > 13) { xastir_snprintf(stemp, sizeof(stemp), "%c%c/%c%c %c%c:%c%c", //sprintf(stemp,"%c%c/%c%c/%c%c%c%c %c%c:%c%c", p_station->pos_time[0], p_station->pos_time[1], p_station->pos_time[2], p_station->pos_time[3], //p_station->pos_time[4], //p_station->pos_time[5], //p_station->pos_time[6], //p_station->pos_time[7], p_station->pos_time[8], p_station->pos_time[9], p_station->pos_time[10], p_station->pos_time[11]); } else { xastir_snprintf(stemp, sizeof(stemp), " "); } XmTextFieldSetString(SL_pos_time[type][row],stemp); XtManageChild(SL_pos_time[type][row]); xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->node_path_ptr); XmTextFieldSetString(SL_node_path[type][row],stemp); XtManageChild(SL_node_path[type][row]); xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->power_gain); XmTextFieldSetString(SL_power_gain[type][row],stemp); XtManageChild(SL_power_gain[type][row]); // Should we display only the first comment field we have stored, or // concatenate all of them up to the limit of stemp? //xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->comments); if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->comment_data->text_ptr); } else { stemp[0] = '\0'; // Empty string } XmTextFieldSetString(SL_comments[type][row],stemp); XtManageChild(SL_comments[type][row]); break; case LST_MOB: // mobile stations list if (strlen(p_station->course)>0) { XmTextFieldSetString(SL_course[type][row],p_station->course); } else { XmTextFieldSetString(SL_course[type][row],""); } XtManageChild(SL_course[type][row]); if (strlen(p_station->speed)>0) { if (!english_units) xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->speed)*1.852); else xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->speed)*1.1508); XmTextFieldSetString(SL_speed[type][row],stemp); } else { XmTextFieldSetString(SL_speed[type][row],""); } XtManageChild(SL_speed[type][row]); if (strlen(p_station->altitude)>0) { if (!english_units) { xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->altitude); } else { xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->altitude)*3.28084); } XmTextFieldSetString(SL_alt[type][row],stemp); } else { XmTextFieldSetString(SL_alt[type][row],""); } XtManageChild(SL_alt[type][row]); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { // Create a UTM string from coordinates // in Xastir coordinate system. convert_xastir_to_UTM_str(stemp, sizeof(stemp), p_station->coord_lon, p_station->coord_lat); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } else if (coordinate_system == USE_MGRS) { // Create an MGRS string from // coordinates in Xastir coordinate // system. convert_xastir_to_MGRS_str(stemp, sizeof(stemp), p_station->coord_lon, p_station->coord_lat, 0); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } else { // Create lat/lon strings from coordinates // in Xastir coordinate system. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_DEC_DEG); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_DMS_NORMAL); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_HP_NORMAL); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_HP_NORMAL); } xastir_snprintf(stemp, sizeof(stemp), "%s %s", stemp1, stemp2); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } xastir_snprintf(stemp, sizeof(stemp), "%d", (int)p_station->num_packets); XmTextFieldSetString(SL_packets[type][row],stemp); XtManageChild(SL_packets[type][row]); if (strlen(p_station->sats_visible)>0) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(p_station->sats_visible)); XmTextFieldSetString(SL_sats[type][row],stemp); } else { XmTextFieldSetString(SL_sats[type][row],""); } XtManageChild(SL_sats[type][row]); l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles value = (float)calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,stemp,sizeof(stemp)); if (english_units) { xastir_snprintf(stemp1, sizeof(stemp1), "%0.1f", (value * 1.15078)); } else { xastir_snprintf(stemp1, sizeof(stemp1), "%0.1f", (value * 1.852)); } XmTextFieldSetString(SL_my_course[type][row],stemp); XtManageChild(SL_my_course[type][row]); XmTextFieldSetString(SL_my_distance[type][row],stemp1); XtManageChild(SL_my_distance[type][row]); break; case LST_WX: // weather stations list weather = p_station->weather_data; if ((int)(((sec_old + weather->wx_sec_time)) < sec_now())) { break; // Weather data is too old } if (strlen(weather->wx_course) > 0) { XmTextFieldSetString(SL_wx_wind_course[type][row],weather->wx_course); } else { XmTextFieldSetString(SL_wx_wind_course[type][row],""); } XtManageChild(SL_wx_wind_course[type][row]); if (strlen(weather->wx_speed) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)atoi(weather->wx_speed)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(atof(weather->wx_speed)*1.6094)); } XmTextFieldSetString(SL_wx_wind_speed[type][row],stemp); } else { XmTextFieldSetString(SL_wx_wind_speed[type][row],""); } XtManageChild(SL_wx_wind_speed[type][row]); if (strlen(weather->wx_gust) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(weather->wx_gust)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(atof(weather->wx_gust)*1.6094)); } XmTextFieldSetString(SL_wx_wind_gust[type][row],stemp); } else { XmTextFieldSetString(SL_wx_wind_gust[type][row],""); } XtManageChild(SL_wx_wind_gust[type][row]); if (strlen(weather->wx_temp) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(weather->wx_temp)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(((atof(weather->wx_temp)-32)*5.0)/9.0)); } XmTextFieldSetString(SL_wx_temp[type][row],stemp); } else { XmTextFieldSetString(SL_wx_temp[type][row],""); } XtManageChild(SL_wx_temp[type][row]); if (strlen(weather->wx_hum) > 0) { XmTextFieldSetString(SL_wx_hum[type][row],weather->wx_hum); } else { XmTextFieldSetString(SL_wx_hum[type][row],""); } XtManageChild(SL_wx_hum[type][row]); //WE7U // Change this to inches mercury when English Units is selected if (strlen(weather->wx_baro) > 0) { if (!english_units) // hPa { XmTextFieldSetString(SL_wx_baro[type][row], weather->wx_baro); } else // Inches Mercury { float tempf; char temp2[15]; tempf = atof(weather->wx_baro)*0.02953; xastir_snprintf(temp2, sizeof(temp2), "%0.2f", tempf); XmTextFieldSetString(SL_wx_baro[type][row], temp2); } } else { XmTextFieldSetString(SL_wx_baro[type][row],""); } XtManageChild(SL_wx_baro[type][row]); if (strlen(weather->wx_rain) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_rain)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_rain)*.254); } XmTextFieldSetString(SL_wx_rain_h[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_h[type][row],""); } XtManageChild(SL_wx_rain_h[type][row]); if (strlen(weather->wx_prec_00) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_00)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_00)*.254); } XmTextFieldSetString(SL_wx_rain_00[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_00[type][row],""); } XtManageChild(SL_wx_rain_00[type][row]); if (strlen(weather->wx_prec_24) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_24)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_24)*.254); } XmTextFieldSetString(SL_wx_rain_24[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_24[type][row],""); } XtManageChild(SL_wx_rain_24[type][row]); break; default: break; } } else // no data, empty row { XtVaSetValues(SL_da[type][row],XmNlabelPixmap, blank_icon,NULL); XtManageChild(SL_da[type][row]); symbol(SL_da[type][row],0,'~','$','\0',SL_icon[type][row],0,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); xastir_snprintf(temp, sizeof(temp), "%*d", strwid, (row+1+new_offset)); XmTextFieldSetString(SL_list[type][row],temp); XtManageChild(SL_list[type][row]); XmTextFieldSetString(SL_call[type][row],""); XtManageChild(SL_call[type][row]); switch (type) { case LST_TNC: // local stations list case LST_TIM: case LST_ALL: // stations list case LST_OBJ: // Objects/Items list case LST_MYOBJ: // My objects/Items XmTextFieldSetString(SL_packets[type][row],""); XtManageChild(SL_packets[type][row]); XmTextFieldSetString(SL_pos_time[type][row],""); XtManageChild(SL_pos_time[type][row]); XmTextFieldSetString(SL_node_path[type][row],""); XtManageChild(SL_node_path[type][row]); XmTextFieldSetString(SL_power_gain[type][row],""); XtManageChild(SL_power_gain[type][row]); XmTextFieldSetString(SL_comments[type][row],""); XtManageChild(SL_comments[type][row]); break; case LST_MOB: // mobile stations list XmTextFieldSetString(SL_course[type][row],""); XtManageChild(SL_course[type][row]); XmTextFieldSetString(SL_speed[type][row],""); XtManageChild(SL_speed[type][row]); XmTextFieldSetString(SL_alt[type][row],""); XtManageChild(SL_alt[type][row]); XmTextFieldSetString(SL_lat_long[type][row],""); XtManageChild(SL_lat_long[type][row]); XmTextFieldSetString(SL_packets[type][row],""); XtManageChild(SL_packets[type][row]); XmTextFieldSetString(SL_sats[type][row],""); XtManageChild(SL_sats[type][row]); XmTextFieldSetString(SL_my_course[type][row],""); XtManageChild(SL_my_course[type][row]); XmTextFieldSetString(SL_my_distance[type][row],""); XtManageChild(SL_my_distance[type][row]); break; case LST_WX: /*WX stations list */ XmTextFieldSetString(SL_wx_wind_course[type][row],""); XtManageChild(SL_wx_wind_course[type][row]); XmTextFieldSetString(SL_wx_wind_speed[type][row],""); XtManageChild(SL_wx_wind_speed[type][row]); XmTextFieldSetString(SL_wx_wind_gust[type][row],""); XtManageChild(SL_wx_wind_gust[type][row]); XmTextFieldSetString(SL_wx_temp[type][row],""); XtManageChild(SL_wx_temp[type][row]); XmTextFieldSetString(SL_wx_hum[type][row],""); XtManageChild(SL_wx_hum[type][row]); XmTextFieldSetString(SL_wx_baro[type][row],""); XtManageChild(SL_wx_baro[type][row]); XmTextFieldSetString(SL_wx_rain_h[type][row],""); XtManageChild(SL_wx_rain_h[type][row]); XmTextFieldSetString(SL_wx_rain_00[type][row],""); XtManageChild(SL_wx_rain_00[type][row]); XmTextFieldSetString(SL_wx_rain_24[type][row],""); XtManageChild(SL_wx_rain_24[type][row]); break; default: break; } } // empty line if (p_station != NULL) { get_list_member(type, &p_station, 1, 1); // get next member in list } } // loop over display lines end_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List_fill" ); } // if list is defined } /* * Check if we have to update an active list, do it if necessary */ void update_station_scroll_list(void) // called from UpdateTime() [main.c] in timing loop { int i; int pos; Dimension last_h, last_w; int last; int ok; last_h = last_w = 0; ok = 0; for (i=0; i LIST_UPDATE_CYCLE)) || (last_h!=list_size_h[i]) || (last_w!=list_size_w[i]) || units_last!=english_units) { Station_List_fill(i,pos); // update list contents ok = 1; } } } if (ok == 1) { last_list_upd = sec_now(); redo_list = FALSE; } units_last = english_units; } void dragCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); // DK7IN: // todo: We should only do the update if no other list navigation command is // waiting, otherwise we only should update the offset value. // Same with all other callbacks below... Station_List_fill(i,cbs->value); } void decrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void incrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void pageDecrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void pageIncrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void mouseScrollHandler(Widget UNUSED(w), XtPointer clientData, XButtonEvent* event, Boolean * UNUSED(continueToDispatch)) { int i = atoi((char*)clientData); int lines = 2; // no modifier moves 2 lines // shift moves 1 line // control moves 10 lines if (event->type == ButtonRelease) { if (event->state & ControlMask) { lines = 10; } else if (event->state & ShiftMask) { lines = 1; } if (event->button == Button4) // Scroll up { if (last_offset[i] > 0) { if ((last_offset[i] - lines) < 0) { Station_List_fill(i, 0); } else { Station_List_fill(i, last_offset[i] - lines); } } } else if (event->button == Button5) // Scroll down { Station_List_fill(i, last_offset[i] + lines); } } } void valueChangedCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } /* * Setup the various list layouts */ void Station_List(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int i; Widget pane, form, win_list, form2, button_close; Widget numl,call,sep,sep2; Widget it1, it2, it3, it4, it5, it6, it7, it8, it9; Widget seps[40]; Atom delw; int type; char temp[400]; if (station_list_first) { memset(&SL_scroll, 0, sizeof(SL_scroll)); init_station_lists(); // init icons at very first list call station_list_first=0; } type=atoi((char *)clientData); switch(type) { case LST_ALL: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI000")); // All Stations break; case LST_MOB: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI001")); // Mobile Stations break; case LST_WX: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI002")); // Weather Stations break; case LST_TNC: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI003")); // Local Stations break; case LST_TIM: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI004")); // Last Stations break; case LST_OBJ: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI005")); // Objects/Items break; case LST_MYOBJ: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI006")); // My Objects/Items break; default: return; } if (!station_list_dialog[type]) // setup list area if not previously done { // DK7IN: we should destroy those Widgets to get the // memory back, and rebuild it on the next call. ???? // I don't exactly know what's going on, but we lose memory // every time we call it. begin_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List" ); station_list_dialog[type]= XtVaCreatePopupShell(temp, xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 274, XmNmaxHeight, ROWS*HGT+FUDGE, XmNminHeight, 95, // XmNheight, 230, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station_List pane",xmPanedWindowWidgetClass, station_list_dialog[type], XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Station_List form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNshadowType, XmSHADOW_OUT, XmNshadowThickness, 1, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // station number in list numl = XtVaCreateManagedWidget(langcode("LHPUPNI010"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(numl,langcode("LHPUPNI010")); // # // icon // call call = XtVaCreateManagedWidget(langcode("LHPUPNI011"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 9, // 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, numl, XmNleftOffset, 23, // 22, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(call,langcode("LHPUPNI011")); // Call Sign switch (type) { case LST_ALL: // All Stations case LST_TNC: // Local Stations [via TNC] case LST_TIM: // Last Stations case LST_OBJ: // Objects/Item case LST_MYOBJ: // My objects/items // number of packets heard it1 = XtVaCreateManagedWidget(langcode("LHPUPNI012"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI012")); // #Pack // Last time of position it2 = XtVaCreateManagedWidget(langcode("LHPUPNI013"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 11, //16, //17, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI013")); // Last Position Time // Path it3 = XtVaCreateManagedWidget(langcode("LHPUPNI014"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 30, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI014")); // Path // PHG it4 = XtVaCreateManagedWidget(langcode("LHPUPNI015"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 7, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI015")); // PHG // Comments it5 = XtVaCreateManagedWidget(langcode("LHPUPNI016"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 40, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it5,langcode("LHPUPNI016")); // Comments break; case LST_MOB: /*mobile list */ it1 = XtVaCreateManagedWidget(langcode("LHPUPNI100"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI100")); // CSE it2 = XtVaCreateManagedWidget(langcode("LHPUPNI101"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI101")); // SPD it3 = XtVaCreateManagedWidget(langcode("LHPUPNI102"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 8, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI102")); // ALT. it4 = XtVaCreateManagedWidget(langcode("LHPUPNI103"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 25, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI209")); // Lat/Lon or UTM it6 = XtVaCreateManagedWidget(langcode("LHPUPNI105"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it6,langcode("LHPUPNI105")); // #Pack it7 = XtVaCreateManagedWidget(langcode("LHPUPNI106"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it6, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it7,langcode("LHPUPNI106")); // LSV it8 = XtVaCreateManagedWidget(langcode("LHPUPNI107"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it7, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it8,langcode("LHPUPNI107")); // CFMS it9 = XtVaCreateManagedWidget(langcode("LHPUPNI108"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it8, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it9,langcode("LHPUPNI108")); // DFMS break; case LST_WX: /*wx list */ it1 = XtVaCreateManagedWidget(langcode("LHPUPNI200"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI200")); // CSE it2 = XtVaCreateManagedWidget(langcode("LHPUPNI201"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI201")); // SPD it3 = XtVaCreateManagedWidget(langcode("LHPUPNI202"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI202")); // GST it4 = XtVaCreateManagedWidget(langcode("LHPUPNI203"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI203")); // Temp it5 = XtVaCreateManagedWidget(langcode("LHPUPNI204"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it5,langcode("LHPUPNI204")); // Hum it6 = XtVaCreateManagedWidget(langcode("LHPUPNI205"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it5, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it6,langcode("LHPUPNI205")); // Baro it7 = XtVaCreateManagedWidget(langcode("LHPUPNI206"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it6, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it7,langcode("LHPUPNI206")); // RN-H it8 = XtVaCreateManagedWidget(langcode("LHPUPNI207"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it7, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it8,langcode("LHPUPNI207")); // RNSM it9 = XtVaCreateManagedWidget(langcode("LHPUPNI208"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it8, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it9,langcode("LHPUPNI208")); // RN24 break; default: break; } // if (!station_list_dialog[type])... from some kilometers above... ;-) sep = XtVaCreateManagedWidget("Station_List sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, numl, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, NULL); SL_scroll[type] = XtVaCreateManagedWidget("Station_List SL_scroll", xmScrollBarWidgetClass,form, XmNorientation, XmVERTICAL, XmNtraversalOn, TRUE, XmNmaximum, 10, // XmNmaximum, stations_types(type), // XmNsliderSize, rows, // // XmNpageIncrement, rows, // was 18 XmNheight, 145, // test XmNsliderSize, 10, // XmNpageIncrement, 10, // was 18 XmNprocessingDirection, XmMAX_ON_BOTTOM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 42, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddEventHandler(SL_scroll[type], ButtonReleaseMask, FALSE, (XtEventHandler)mouseScrollHandler, (char*)clientData); win_list = XtVaCreateWidget("Station_List win_list",xmFormWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 42, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 2, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, SL_scroll[type], XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddEventHandler(win_list, ButtonReleaseMask, FALSE, (XtEventHandler)mouseScrollHandler, (char*)clientData); for (i=0; i key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(station_list_dialog[type]); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); // Note: If adding new lists, make sure to tweak xa_config.c to // increment the number. If not, you'll get an X-Windows error at // this point when trying to resize the window: /* set last size if there was one */ // done in list_fill if (list_size_w[type] > 0 && list_size_h[type] > 0) XtVaSetValues(station_list_dialog[type], XmNwidth, list_size_w[type], XmNheight, list_size_h[type], NULL); if (type != LST_TIM) { top_call[type][0] = '\0'; // start at top } else { top_time = 0; top_sn = -1; } last_offset[type] = 0; last_list_upd = sec_now(); list_size_i[type] = FALSE; redo_list = (int)TRUE; Station_List_fill(type,0); // start with top of list } else // if (!station_list_dialog[type]) // we already have an initialized widget { (void)XRaiseWindow(XtDisplay(station_list_dialog[type]), XtWindow(station_list_dialog[type])); } } Xastir-Release-2.2.2/src/list_gui.h000066400000000000000000000026571501463444000171370ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_LIST_GUI_H #define __XASTIR_LIST_GUI_H // different list types: #define LST_ALL 0 #define LST_MOB 1 #define LST_WX 2 #define LST_TNC 3 #define LST_TIM 4 #define LST_OBJ 5 #define LST_MYOBJ 6 #define LST_NUM 7 extern int list_size_h[]; extern int list_size_w[]; /* from list_gui.c */ extern void list_gui_init(void); extern void update_station_scroll_list(void); extern int stations_types(int type); extern void Station_List_fill(int type, int new_offset); #endif // __XASTIR_LIST_GUI_H Xastir-Release-2.2.2/src/locate_gui.c000066400000000000000000001443121501463444000174210ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include "xastir.h" #include "main.h" #include "lang.h" #include "maps.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget locate_station_dialog = (Widget)NULL; Widget locate_station_data = (Widget)NULL; char locate_station_call[30]; static xastir_mutex locate_station_dialog_lock; Widget locate_place_dialog = (Widget)NULL; Widget locate_place_data = (Widget)NULL; Widget locate_state_data = (Widget)NULL; Widget locate_county_data = (Widget)NULL; Widget locate_quad_data = (Widget)NULL; Widget locate_type_data = (Widget)NULL; Widget locate_gnis_file_data = (Widget)NULL; char locate_place_name[50]; char locate_state_name[50]; char locate_county_name[50]; char locate_quad_name[50]; char locate_type_name[50]; char locate_gnis_filename[200]; static xastir_mutex locate_place_dialog_lock; /* locate station values */ Widget locate_case_data, locate_match_data; /* locate place values */ Widget locate_place_case_data, locate_place_match_data; Widget locate_place_list; Widget locate_place_chooser = (Widget)NULL; static xastir_mutex locate_place_chooser_lock; char match_array_name[50][200]; long match_array_lat[50]; long match_array_long[50]; int match_quantity = 0; void locate_gui_init(void) { init_critical_section( &locate_station_dialog_lock ); init_critical_section( &locate_place_dialog_lock ); init_critical_section( &locate_place_chooser_lock ); locate_station_call[0] = '\0'; locate_place_name[0] = '\0'; locate_state_name[0] = '\0'; locate_county_name[0] = '\0'; locate_quad_name[0] = '\0'; locate_type_name[0] = '\0'; } /**** LOCATE STATION ******/ void Locate_station_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station_destroy_shell" ); XtDestroyWidget(shell); locate_station_dialog = (Widget)NULL; end_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station_destroy_shell" ); } /* * Look up detailed FCC/RAC info about the station */ // Determine whether it is a U.S. or Canadian callsign then search // through the appropriate database and present the results. void fcc_rac_lookup(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char station_call[200]; char temp[1000]; char temp2[300]; char *temp_ptr; FccAppl my_fcc_data; rac_record my_rac_data; // Snag station call temp_ptr = XmTextFieldGetString(locate_station_data); xastir_snprintf(station_call, sizeof(station_call), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(station_call); (void)remove_trailing_dash_zero(station_call); to_upper(station_call); switch (station_call[0]) { case 'A': case 'K': case 'N': case 'W': if (search_fcc_data_appl(station_call, &my_fcc_data) == 1) { xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s %s %s\n%s %s, %s %s, %s %s\n\n", langcode("STIFCC0001"), langcode("STIFCC0003"), my_fcc_data.name_licensee, langcode("STIFCC0004"), my_fcc_data.text_street, my_fcc_data.text_pobox, langcode("STIFCC0005"), my_fcc_data.city, langcode("STIFCC0006"), my_fcc_data.state, langcode("STIFCC0007"), my_fcc_data.zipcode); popup_message_always(langcode("WPUPLSP007"),temp); } else { xastir_snprintf(temp2, sizeof(temp2), "Callsign Not Found!\n"); popup_message_always(langcode("POPEM00001"),temp2); } break; case 'V': if (search_rac_data(station_call, &my_rac_data) == 1) { xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s\n%s, %s\n%s\n", langcode("STIFCC0002"), my_rac_data.first_name, my_rac_data.last_name, my_rac_data.address, my_rac_data.city, my_rac_data.province, my_rac_data.postal_code); if (my_rac_data.qual_a[0] == 'A') strncat(temp, langcode("STIFCC0008"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_d[0] == 'D') strncat(temp, langcode("STIFCC0009"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_b[0] == 'B' && my_rac_data.qual_c[0] != 'C') strncat(temp, langcode("STIFCC0010"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_c[0] == 'C') strncat(temp, langcode("STIFCC0011"), sizeof(temp) - 1 - strlen(temp)); strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); if (strlen(my_rac_data.club_name) > 1) { xastir_snprintf(temp2, sizeof(temp2), "%s\n%s\n%s, %s\n%s\n", my_rac_data.club_name, my_rac_data.club_address, my_rac_data.club_city, my_rac_data.club_province, my_rac_data.club_postal_code); strncat(temp, temp2, sizeof(temp) - 1 - strlen(temp)); } popup_message_always(langcode("WPUPLSP007"),temp); } else { // RAC code does its own popup in this case? //fprintf(stderr, "Callsign not found\n"); } break; default: xastir_snprintf(temp2, sizeof(temp2), "Not an FCC or RAC callsign!\n"); popup_message_always(langcode("POPEM00001"),temp2); break; } // Don't enable this as then we can't click on the Locate button // later. //Locate_station_destroy_shell(w, clientData, callData); } /* * Locate a station by centering the map at its position */ void Locate_station_now(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp2[200]; char *temp_ptr; /* find station and go there */ temp_ptr = XmTextFieldGetString(locate_station_data); xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(locate_station_call); (void)remove_trailing_dash_zero(locate_station_call); /*fprintf(stderr,"looking for %s\n",locate_station_call);*/ if (locate_station(da, locate_station_call, (int)XmToggleButtonGetState(locate_case_data), (int)XmToggleButtonGetState(locate_match_data),1) ==0) { xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00002"), locate_station_call); popup_message_always(langcode("POPEM00001"),temp2); } // Don't enable this as then we can't click on the FCC/RAC // button later, and we'll lose the callsign info if we want to // see it again. //Locate_station_destroy_shell(w, clientData, callData); } // Here we pass in a 1 in callData if it's an emergency locate, // for when we've received a Mic-E emergency packet. // void Locate_station(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { static Widget pane, scrollwindow, form, button_locate, button_cancel, call, button_lookup, sep; Atom delw; int emergency_flag = XTPOINTER_TO_INT(callData); if (!locate_station_dialog) { begin_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station" ); // Check whether it is an emergency locate function if (emergency_flag == 1) { locate_station_dialog = XtVaCreatePopupShell(langcode("WPUPLSP006"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); } else // Non-emergency locate { locate_station_dialog = XtVaCreatePopupShell(langcode("WPUPLSP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); } pane = XtVaCreateWidget("Locate_station pane",xmPanedWindowWidgetClass, locate_station_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Locate_station form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); call = XtVaCreateManagedWidget(langcode("WPUPLSP002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_station_data = XtVaCreateManagedWidget("Locate_station data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_case_data = XtVaCreateManagedWidget(langcode("WPUPLSP003"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_match_data = XtVaCreateManagedWidget(langcode("WPUPLSP004"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locate_case_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Locate_station sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,locate_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_lookup = XtVaCreateManagedWidget(langcode("WPUPLSP007"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_locate = XtVaCreateManagedWidget(langcode("WPUPLSP005"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_lookup, XmNactivateCallback, fcc_rac_lookup, locate_station_dialog); XtAddCallback(button_locate, XmNactivateCallback, Locate_station_now, locate_station_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Locate_station_destroy_shell, locate_station_dialog); XmToggleButtonSetState(locate_case_data,FALSE,FALSE); XmToggleButtonSetState(locate_match_data,TRUE,FALSE); XmTextFieldSetString(locate_station_data,locate_station_call); pos_dialog(locate_station_dialog); delw = XmInternAtom(XtDisplay(locate_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_station_dialog, delw, Locate_station_destroy_shell, (XtPointer)locate_station_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, locate_station_dialog); end_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station" ); XtPopup(locate_station_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(locate_station_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(locate_station_dialog), XtWindow(locate_station_dialog)); } } /*******************************************************************/ /* Locate Place Chooser routines */ /* * Locate Place Chooser PopUp window: Cancelled */ void Locate_place_chooser_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_destroy_shell" ); XtDestroyWidget(shell); locate_place_chooser = (Widget)NULL; end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_destroy_shell" ); } /* * Locate Place Selection PopUp window: Map selected place */ void Locate_place_chooser_select(Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int ii, xx; char *temp; XmString *list; int found = 0; int index = 0; begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_select" ); if (locate_place_chooser) { XtVaGetValues(locate_place_list, XmNitemCount, &ii, XmNitems, &list, NULL); for (xx=1; xx<=ii; xx++) { if (XmListPosSelected(locate_place_list, xx)) { found = 1; index = xx; if (XmStringGetLtoR(list[(xx-1)], XmFONTLIST_DEFAULT_TAG, &temp)) { xx=ii+1; } } } if (found) { // Center the map at the chosen location set_map_position(widget, match_array_lat[index-1], match_array_long[index-1]); XtFree(temp); } } end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_select" ); } void Locate_place_chooser(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, form, button_ok, button_cancel; Arg al[50]; register unsigned int ac = 0; int ii, nn; XmString str_ptr; Atom delw; if (locate_place_chooser != NULL) { Locate_place_chooser_destroy_shell(locate_place_chooser, locate_place_chooser, NULL); } begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser"); if (locate_place_chooser == NULL) { // Set up a selection box: locate_place_chooser = XtVaCreatePopupShell(langcode("WPUPCFS028"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Locate_place_chooser pane",xmPanedWindowWidgetClass, locate_place_chooser, XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Locate_place_chooser form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Attach buttons first to the bottom of the form, // so that we'll be able to stretch this thing // vertically to see all of the entries. // button_ok = XtVaCreateManagedWidget(langcode("WPUPCFS028"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Locate_place_chooser_select, locate_place_chooser); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Locate_place_chooser_destroy_shell, locate_place_chooser); // set args for color ac = 0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 6); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNbottomWidget, button_ok); ac++; XtSetArg(al[ac], XmNbottomOffset, 5); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; locate_place_list = XmCreateScrolledList(form,"Locate_place_chooser list",al,ac); nn = 1; for (ii = 0; ii < match_quantity; ii++) { XmListAddItem(locate_place_list, str_ptr = XmStringCreateLtoR(match_array_name[ii], XmFONTLIST_DEFAULT_TAG), (int)nn++); XmStringFree(str_ptr); } pos_dialog(locate_place_chooser); delw = XmInternAtom(XtDisplay(locate_place_chooser), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_place_chooser, delw, Locate_place_chooser_destroy_shell, (XtPointer)locate_place_chooser); XtManageChild(form); XtManageChild(locate_place_list); XtVaSetValues(locate_place_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XtPopup(locate_place_chooser,XtGrabNone); // Move focus to the Cancel button. This appears to // highlight t // button fine, but we're not able to hit the // key to // have that default function happen. Note: We // _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser" ); } /*******************************************************************/ /**** LOCATE PLACE ******/ void Locate_place_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place_destroy_shell" ); XtDestroyWidget(shell); locate_place_dialog = (Widget)NULL; end_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place_destroy_shell" ); } /* * Locate a place by centering the map at its position */ void Locate_place_now(Widget w, XtPointer clientData, XtPointer callData) { char *temp_ptr; // int ii; /* find place and go there */ temp_ptr = XmTextFieldGetString(locate_place_data); xastir_snprintf(locate_place_name, sizeof(locate_place_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_state_data); xastir_snprintf(locate_state_name, sizeof(locate_state_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_county_data); xastir_snprintf(locate_county_name, sizeof(locate_county_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_quad_data); xastir_snprintf(locate_quad_name, sizeof(locate_quad_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_type_data); xastir_snprintf(locate_type_name, sizeof(locate_type_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_gnis_file_data); xastir_snprintf(locate_gnis_filename, sizeof(locate_gnis_filename), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(locate_place_name); (void)remove_trailing_spaces(locate_state_name); (void)remove_trailing_spaces(locate_county_name); (void)remove_trailing_spaces(locate_quad_name); (void)remove_trailing_spaces(locate_type_name); /*fprintf(stderr,"looking for %s\n",locate_place_name);*/ match_quantity = gnis_locate_place(da, locate_place_name, locate_state_name, locate_county_name, locate_quad_name, locate_type_name, locate_gnis_filename, (int)XmToggleButtonGetState(locate_place_case_data), (int)XmToggleButtonGetState(locate_place_match_data), match_array_name, match_array_lat, match_array_long); if (0 == match_quantity) // Try population centers. match_quantity = pop_locate_place(da, locate_place_name, locate_state_name, locate_county_name, locate_quad_name, locate_type_name, locate_gnis_filename, (int)XmToggleButtonGetState(locate_place_case_data), (int)XmToggleButtonGetState(locate_place_match_data), match_array_name, match_array_lat, match_array_long); if (match_quantity) { // Found some matches! // Have a Chooser dialog if more than one match is found, // plus the associated callbacks. Don't center the map // unless the user chooses one of the matches. Leave the // chooser dialog up so that the user can click on the // matches one at a time until the correct one is found, // then he/she can hit the Close button on that dialog to // make it go away. // Bring up a chooser dialog with the results from the // match_array and a close button. Allow the user to choose // which one to center the map to. Could also allow the // user to find out more about each match if we fill the // array with more data from the GNIS file. // Debug: Print out the contents of the match arrays. //fprintf(stderr,"Found %d matches!\n", match_quantity); /* set_dangerous("printing"); for (ii = 0; ii < match_quantity; ii++) { fprintf(stderr, "%d, %s, %ld, %ld\n", ii, match_array_name[ii], match_array_lat[ii], match_array_long[ii]); } clear_dangerous(); */ // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), match_array_name[0]); // Bring up the new Chooser dialog (void)Locate_place_chooser(w, clientData, callData); } else { // No matches found. popup_message_always(langcode("POPEM00025"),locate_place_name); } Locate_place_destroy_shell(w, clientData, callData); } void Locate_place(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_cancel, sep, place, state, county, quad, place_type, gnis_file; Atom delw; if (!locate_place_dialog) { begin_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place" ); locate_place_dialog = XtVaCreatePopupShell(langcode("PULDNMP014"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Locate_place pane",xmPanedWindowWidgetClass, locate_place_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Locate_place form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); place = XtVaCreateManagedWidget(langcode("FEATURE001"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_place_data = XtVaCreateManagedWidget("Locate_place_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, place, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); state = XtVaCreateManagedWidget(langcode("FEATURE002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, place, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_state_data = XtVaCreateManagedWidget("Locate_state_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((4*7)+2), XmNmaxLength, 2, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, place, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, state, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); county = XtVaCreateManagedWidget(langcode("FEATURE003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_county_data = XtVaCreateManagedWidget("Locate_county_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, county, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); quad = XtVaCreateManagedWidget(langcode("FEATURE004"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, county, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_quad_data = XtVaCreateManagedWidget("Locate_quad_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, county, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, quad, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); place_type = XtVaCreateManagedWidget(langcode("FEATURE005"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, quad, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_type_data = XtVaCreateManagedWidget("Locate_type_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, quad, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, place_type, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); gnis_file = XtVaCreateManagedWidget(langcode("FEATURE006"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, place_type, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_gnis_file_data = XtVaCreateManagedWidget("locate_gnis_file_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, place_type, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, gnis_file, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_place_case_data = XtVaCreateManagedWidget(langcode("WPUPLSP003"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gnis_file, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_place_match_data = XtVaCreateManagedWidget(langcode("WPUPLSP004"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gnis_file, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locate_place_case_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Locate_place sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,locate_place_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPLSP005"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Locate_place_now, locate_place_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Locate_place_destroy_shell, locate_place_dialog); XmToggleButtonSetState(locate_place_case_data,FALSE,FALSE); XmToggleButtonSetState(locate_place_match_data,FALSE,FALSE); // XtSetSensitive(locate_place_match_data,FALSE); XmTextFieldSetString(locate_place_data,locate_place_name); XmTextFieldSetString(locate_state_data,locate_state_name); XmTextFieldSetString(locate_county_data,locate_county_name); XmTextFieldSetString(locate_quad_data,locate_quad_name); XmTextFieldSetString(locate_type_data,locate_type_name); XmTextFieldSetString(locate_gnis_file_data,locate_gnis_filename); pos_dialog(locate_place_dialog); delw = XmInternAtom(XtDisplay(locate_place_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_place_dialog, delw, Locate_place_destroy_shell, (XtPointer)locate_place_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, locate_place_dialog); end_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place" ); XtPopup(locate_place_dialog,XtGrabNone); // Move focus to the Locate Now! button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(locate_place_dialog); XmProcessTraversal(button_ok, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(locate_place_dialog), XtWindow(locate_place_dialog)); } } Xastir-Release-2.2.2/src/location.c000066400000000000000000000063111501463444000171120ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "track_gui.h" // Must be last include file #include "leak_detection.h" static long last_center_longitude; // remember last screen settings static long last_center_latitude; static long last_scale_x; static long last_scale_y; /***********************************************************/ /* set last map position */ /* store lat long and zoom */ /***********************************************************/ void set_last_position(void) { last_center_longitude=center_longitude; last_center_latitude=center_latitude; last_scale_x = scale_x; // we don't restore this... last_scale_y = scale_y; } /***********************************************************/ /* reset map to last position */ /* */ /***********************************************************/ void map_pos_last_position(void) { map_pos(last_center_latitude,last_center_longitude,last_scale_y); } /***********************************************************/ /* Jump map to position */ /* */ /***********************************************************/ void map_pos(long mid_y, long mid_x, long sz) { // see also set_map_position() in db.c // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; set_last_position(); center_longitude = mid_x; center_latitude = mid_y; scale_y = sz; scale_x = get_x_scale(mid_x,mid_y,scale_y); setup_in_view(); // flag all stations in screen view // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // // We don't care whether or not this succeeds? // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // display_zoom_status(); // } } Xastir-Release-2.2.2/src/location_gui.c000066400000000000000000000527361501463444000177720ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "xastir.h" #include "main.h" #include "xa_config.h" #include "util.h" #include "lang.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget location_dialog = (Widget)NULL; Widget location_list; static xastir_mutex location_dialog_lock; void location_gui_init(void) { init_critical_section( &location_dialog_lock ); } /************************************************/ /* button function for last location */ /************************************************/ void Last_location(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { map_pos_last_position(); } /************************************************/ /* manage jump locations */ /************************************************/ void location_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); XtDestroyWidget(shell); location_dialog = (Widget)NULL; end_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); } /************************************************/ /* jump to chosen location/zoom */ /************************************************/ void location_view(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *location; XmString *list; int found,done; FILE *f; char temp[200]; char name[100]; char pos[100]; char *temp_ptr; char s_lat[20]; char s_long[20]; char s_sz[10]; char location_file_path[MAX_VALUE]; found=0; XtVaGetValues(location_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(location_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&location)) { x=i+1; } } } get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); if (found) { f=fopen(location_file_path,"r"); if (f!=NULL) { done=0; while (!feof(f) & !done) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string temp_ptr=strtok(NULL,"|"); /* get the pos */ xastir_snprintf(pos, sizeof(pos), "%s", temp_ptr); if (strcmp(location,name)==0) { if (3 != sscanf(pos,"%19s %19s %9s", s_lat, s_long, s_sz)) { fprintf(stderr,"location_view:sscanf parsing error\n"); } map_pos(convert_lat_s2l(s_lat),convert_lon_s2l(s_long),atol(s_sz)); done=1; } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } XtFree(location); } } /************************************************/ /* sort and jump locations */ /************************************************/ void jump_sort(void) { char temp[200]; char name[100]; char *temp_ptr; FILE *f; char location_file_path[MAX_VALUE]; char location_db_file_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("data/locations_db.dat", location_db_file_path, sizeof(location_db_file_path)); f=fopen(location_file_path,"r"); if (f!=NULL) { while (!feof(f)) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string (void)sort_input_database(location_db_file_path,name,200); } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } } /************************************************/ /* delete location/zoom */ /************************************************/ void location_delete(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *location; XmString *list; int found,ok; FILE *f,*fout; char temp[200]; char name[100]; char pos[100]; char *temp_ptr; char filen[400]; char filen_bak[400]; char location_file_path[MAX_VALUE]; char location_sys_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("config/locations.sys-tmp", location_sys_path, sizeof(location_sys_path)); found=0; ok=0; XtVaGetValues(location_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(location_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&location)) { XmListDeletePos(location_list,x); x=i+1; } } } if(found) { f=fopen(location_file_path,"r"); if (f!=NULL) { fout=fopen(location_sys_path,"a"); if (fout!=NULL) { while (!feof(f)) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string temp_ptr=strtok(NULL,"|"); /* get the pos */ xastir_snprintf(pos, sizeof(pos), "%s", temp_ptr); if (strcmp(location,name)!=0) { fprintf(fout,"%s|%s\n",name,pos); } } } } (void)fclose(fout); ok=1; } else { fprintf(stderr,"Couldn't open file: %s\n", location_sys_path ); } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } XtFree(location); } if (ok==1) { xastir_snprintf(filen, sizeof(filen), "%s", location_file_path); xastir_snprintf(filen_bak, sizeof(filen_bak), "%s", location_sys_path); (void)unlink(filen); (void)rename(filen_bak,filen); } } /************************************************/ /* add location/zoom */ /************************************************/ void location_add(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char name[100]; char s_long[20]; char s_lat[20]; FILE *f, *fout; char temp[200]; char *temp_ptr; Widget my_text = (Widget) clientData; int len,n,found; char location_file_path[MAX_VALUE]; char location_db_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("data/locations_db.dat", location_db_path, sizeof(location_db_path)); temp_ptr = XmTextFieldGetString(my_text); xastir_snprintf(name, sizeof(name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(name); XmTextFieldSetString(my_text,""); /* should check for name used already */ found=0; f=fopen(location_file_path,"r"); if (f!=NULL) { while (!feof(f) && !found) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { if (strcmp(name,temp)==0) { found=1; } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } if (!found) { /* delete entire list available */ XmListDeleteAllItems(location_list); len = (int)strlen(name); if (len>0 && len<100) { fout = fopen(location_file_path,"a"); if (fout!=NULL) { convert_lat_l2s(center_latitude, s_lat, sizeof(s_lat), CONVERT_HP_NOSP); convert_lon_l2s(center_longitude, s_long, sizeof(s_long), CONVERT_HP_NOSP); fprintf(fout,"%s|%s %s %ld\n",name,s_lat,s_long,scale_y); (void)fclose(fout); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } } else { popup_message_always(langcode("POPEM00022"),langcode("POPEM00023")); } /* resort the list and put it back up */ n=1; clear_sort_file(location_db_path); jump_sort(); sort_list(location_db_path,200,location_list,&n); } else { popup_message_always(langcode("POPEM00022"),langcode("POPEM00024")); /* dupe name */ } } /************************************************/ /* manage jump locations */ /************************************************/ void Jump_location(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_add, button_delete, button_cancel, locdata, location_name; int n; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ Atom delw; char location_db_path[MAX_VALUE]; get_user_base_dir("data/locations_db.dat", location_db_path, sizeof(location_db_path)); if(!location_dialog) { begin_critical_section(&location_dialog_lock, "location_gui.c:Jump_location" ); location_dialog = XtVaCreatePopupShell(langcode("JMLPO00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, location_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0ff]); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; location_list = XmCreateScrolledList(form, "Jump_location list", al, ac); n=1; clear_sort_file(location_db_path); jump_sort(); sort_list(location_db_path,200,location_list,&n); locdata = XtVaCreateManagedWidget(langcode("JMLPO00003"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(location_list), XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); location_name = XtVaCreateManagedWidget("Jump_location Location_name", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, XtParent(location_list), XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locdata, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_add = XtVaCreateManagedWidget(langcode("UNIOP00007"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_delete = XtVaCreateManagedWidget(langcode("UNIOP00008"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 5, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, location_destroy_shell, location_dialog); XtAddCallback(button_ok, XmNactivateCallback, location_view, NULL); XtAddCallback(button_add, XmNactivateCallback, location_add, location_name); XtAddCallback(button_delete, XmNactivateCallback, location_delete, NULL); pos_dialog(location_dialog); delw = XmInternAtom(XtDisplay(location_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(location_dialog, delw, location_destroy_shell, (XtPointer)location_dialog); XtManageChild(form); XtManageChild(location_list); XtVaSetValues(location_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(form, location_dialog); end_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); XtPopup(location_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(location_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(location_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(location_dialog), XtWindow(location_dialog)); } } Xastir-Release-2.2.2/src/macspeech.c000066400000000000000000000101341501463444000172300ustar00rootroot00000000000000/* Copyright (C) 2000-2023 The Xastir Group */ /* */ /* */ /* First draft */ /* KB3EGH 03/24/2004 */ /* needs -I/Developer/Headers/FlatCarbon */ /*=======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include /* can't include this or X11's Cursor conflicts */ /* #include "xastir.h"*/ #include "snprintf.h" // Must be last include file #include "leak_detection.h" static char last_speech_text[8000]; static time_t last_speech_time = (time_t)0; static SpeechChannel channel; int macspeech_processes = 0; int SayText(char *text) { OSErr err; pid_t child_pid; //if (debug_level & 2) //fprintf(stderr,"SayText: %s\n",text); // Check whether the last text was the same and it hasn't been // enough time between them (30 seconds). if ( (strcmp(last_speech_text,text) == 0) // Strings match && (last_speech_time + 30 > sec_now()) ) { //fprintf(stderr,"Same text, skipping speech: %d seconds, %s\n", // (int)(sec_now() - last_speech_time), // text); return(1); } //fprintf(stderr,"Speaking: %s\n",text); xastir_snprintf(last_speech_text, sizeof(last_speech_text), "%s", text); last_speech_time = sec_now(); // Check for the variable going out-of-bounds if (macspeech_processes < 0) { macspeech_processes = 0; } // Allow only so many processes to be queued up ready to send // text to the speech subsystem. // if (macspeech_processes > 10) // Too many processes queued up! { return(1); // Don't send this string, return to calling program } // Create a separate process to handle the speech so that our // main process can continue processing packets and displaying // maps. // child_pid = fork(); if (child_pid == -1) // The fork failed { return(1); } if (child_pid == 0) // Child process { macspeech_processes++; // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Wait for the speech system to be freed up. Note that if // we have multiple processes queued up we don't know in // which order they'll get access to the speech subsystem. // while (SpeechBusy() == true) { usleep(1000000); } // The speech system is free, so send it our text. Right // now we ignore any errors. // err = SpeakText(channel, text, strlen(text)); macspeech_processes--; // Exit this child process. We don't need it anymore. exit(0); } else // Parent process { // Drop through to the return } return(0); // Return to the calling program } int SayTextInit(void) { OSErr err; long response; long mask; VoiceSpec defaultVoiceSpec; VoiceDescription voiceDesc; err = Gestalt(gestaltSpeechAttr, &response); if (err != noErr) { fprintf(stderr,"can't init Mac Speech Synthesis\n"); return(1); } mask = 1 << gestaltSpeechMgrPresent; if ((response & mask) == 0) { fprintf(stderr,"Mac Speech not supported\n"); return(1); } err = GetVoiceDescription(nil, &voiceDesc, sizeof(voiceDesc)); defaultVoiceSpec = voiceDesc.voice; err = NewSpeechChannel( &defaultVoiceSpec, &channel ); if (err != noErr) { DisposeSpeechChannel(channel); fprintf(stderr,"Failed to open a speech channel\n"); return(1); } last_speech_text[0] = '\0'; last_speech_time = (time_t)0; return(0); } /* cleanup should err = DisposeSpeechChannel( channel ); */ Xastir-Release-2.2.2/src/main.c000066400000000000000000040615241501463444000162410ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // This is for debug. If defined to 1, Xastir will display // coordinates in the Xastir coordinate system inside the text2 // widget. // static int DISPLAY_XASTIR_COORDINATES = 0; #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR -- stupid, stupid ImageMagick char *xastir_package=PACKAGE; char *xastir_version=VERSION; #undef PACKAGE #undef VERSION #ifdef HAVE_MAGICK #include /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK //#ifdef HAVE_NETAX25_AXLIB_H //#include //#endif // HAVE_NETAX25_AXLIB_H #ifdef HAVE_LIBCURL #include #endif #include "xastir.h" #include "draw_symbols.h" #include "main.h" #include "xa_config.h" #include "maps.h" #include "alert.h" #include "interface.h" #include "wx.h" #include "popup.h" #include "track_gui.h" #include "list_gui.h" #include "util.h" #include "color.h" #include "gps.h" #include "bulletin_gui.h" #include "rotated.h" #include "datum.h" #include "igate.h" #include "objects.h" #include "db_gis.h" #include "map_OSM.h" #ifdef HAVE_LIBSHP #include "shp_hash.h" #endif // HAVE_LIBSHP #include "x_spider.h" #include "map_cache.h" #include #include #include // Must be last include file #include "leak_detection.h" // Copyright 2016. // Added the above "Copyright" just so that grep would find these // lines and we could update the years in the Help->About message // each time. Otherwise it often gets missed when we're updating // the years. #define ABOUT_MSG "X Amateur Station Tracking and Information Reporting\n\n http://www.xastir.org\n\nCopyright (C) 2000-2023 The Xastir Group\nSee the \"LICENSE\" file for other applicable copyrights" // OpenStreetMap attribution #define ABOUT_OSM "Maps, tiles, and data from the OpenStreetMap project are\nCopyright OpenStreetMap and contributors, CC-BY-SA.\nMaps and tiles from CloudMade are Copyright CloudMade, CC-BY-SA.\n http://www.openstreetmap.org/\n http://creativecommons.org/licenses/by-sa/2.0/\n http://www.cloudmade.com/\n" // Define this if you want an xastir.pid file created in the // ~/.xastir directory and want to check that there's not another // copy of Xastir running before a new one starts up. You can also // use this to send SIGHUP or SIGUSR1 signals to a running Xastir // from scripts. #define USE_PID_FILE_CHECK 1 #define DOS_HDR_LINES 8 #define STATUSLINE_ACTIVE 10 /* status line is cleared after 10 seconds */ #define REPLAY_DELAY 0 /* delay between replayed packets in sec, 0 is ok */ //#define REDRAW_WAIT 3 /* delay between consecutive redraws in seconds (file load) */ #define REDRAW_WAIT 0 /* delay between consecutive redraws in seconds (file load) */ // FONTS FONTS FONTS FONTS FONTS // // NOTE: See the main() function at the bottom of this module for // the default font definition. xa_config.c is where fonts get // saved/restored for user-defined fonts. // This one is not used anymore: //#define XmFONTLIST_DEFAULT_MY "-misc-fixed-*-r-*-*-10-*-*-*-*-*-*-*" // This one goes right along with smaller system fonts on fixed-size // LCD screens. Fix new dialogs to the upper left of the main // window, don't have them cycle through multiple possible positions // as each new dialog is drawn. // //#define FIXED_DIALOG_STARTUP // Yet another useful item: Puts the mouse menu on button 1 instead // of button3. Useful for one-button devices like touchscreens. // //#define SWAP_MOUSE_BUTTONS // If next line uncommented, Xastir will display the status line // in 2 rows instead of the normal single row. Formatted especially // for 640 pixel wide screens. It also gives a little extra room for // the number of stations and the Zoom factor. // #define USE_TWO_STATUS_LINES // Enable this next line to set all flags properly for a 640x480 // touch-screen: Makes the main window smaller due to the reduced // font sizes, makes all dialogs come up at the upper-left of the // main Xastir screen, reverses buttons 1 and 3 so that the more // important mouse menus are accessible via the touch-screen, and // sets it for 2 status lines. Make sure to change the system font // size smaller than the default. // //#define LCD640x480TOUCH // #ifdef LCD640x480TOUCH #define FIXED_DIALOG_STARTUP #define SWAP_MOUSE_BUTTONS #define USE_TWO_STATUS_LINES #endif #define LINE_WIDTH 1 #define ARROWS 1 // Arrow buttons on menubar // TVR 26 July 2005 // Moved this magic number to a #define --- there were numerous places // where this constant was hard coded, making it difficult to change the // map properties line format without breaking something. Now it can live // in one place that needs to be updated when the properties line is changed. // At the time of writing, the properties line had the following format: // min max lyr fil drg amap name // %5d %5d %5d %5c %5c %5c %s // placing the name at offset 37 #define MPD_FILENAME_OFFSET 37 // Define the ICON, created with the "bitmap" editor: #include "icon.xbm" // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX int geometry_x, geometry_y; unsigned int geometry_width, geometry_height; int geometry_flags; static int initial_load = 1; int first_time_run = 0; /* JMT - works under FreeBSD */ uid_t euid; gid_t egid; int my_argc; char **my_argv; char **my_envp; int restart_xastir_now = 0; // A count of the stations currently on the screen. Counted by // db.c:display_file() routine. int currently_selected_stations = 0; int currently_selected_stations_save = 0; // If my_trail_diff_color is 0, all my calls (SSIDs) will use MY_TRAIL_COLOR. // If my_trail_diff_color = 1 then each different ssid for my callsign will use a different color. int my_trail_diff_color = 0; // Used in segfault handler char dangerous_operation[200]; FILE *file_wx_test; int tcp_server_pid = 0; int udp_server_pid = 0; int serial_char_pacing; // Inter-char delay in ms for serial ports. int dtr_on = 1; time_t sec_last_dtr = (time_t)0; time_t last_updatetime = (time_t)0; int time_went_backwards = 0; /* language in use */ char lang_to_use[30]; /* version info in main.h */ int altnet; char altnet_call[MAX_CALLSIGN+1]; static void Window_Quit(Widget w, XtPointer client, XtPointer call); static void save_state(Widget w, XtPointer client, XtPointer call); void da_input(Widget w, XtPointer client_data, XtPointer call_data); void da_resize(Widget w, XtPointer client_data, XtPointer call_data); void da_expose(Widget w, XtPointer client_data, XtPointer call_data); void BuildPredefinedSARMenu_UI(Widget *parent_menu); Widget *predefined_object_menu_parent; Widget sar_object_sub; Widget predefined_object_menu_items[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; int debug_level; //Widget hidden_shell; Widget appshell; Widget form; Widget da; Widget text; Widget text2; Widget text3; Widget text4; Widget log_indicator; Widget iface_da; Widget menubar; Widget toolbar; Widget configure_station_dialog = (Widget)NULL; Widget right_menu_popup = (Widget)NULL; // Button one or left mouse button //Widget middle_menu_popup=(Widget)NULL; // Button two or middle mouse button //Widget right_menu_popup=(Widget)NULL; // Button three or right mouse button Widget trackme_button; Widget measure_button; Widget move_button; Widget cad_draw_button; Widget CAD_close_polygon_menu_item; int Station_transmit_type; int Igate_type; Widget Display_data_dialog = (Widget)NULL; Widget Display_data_text; int Display_packet_data_type; int show_only_station_capabilities = 0; int Display_packet_data_mine_only = 0; Widget configure_defaults_dialog = (Widget)NULL; Widget configure_timing_dialog = (Widget)NULL; Widget configure_coordinates_dialog = (Widget)NULL; Widget coordinate_calc_button_ok = (Widget)NULL; Widget change_debug_level_dialog = (Widget)NULL; Widget coordinate_calc_dialog = (Widget)NULL; Widget coordinate_calc_zone = (Widget)NULL; Widget coordinate_calc_latitude_easting = (Widget)NULL; Widget coordinate_calc_longitude_northing = (Widget)NULL; Widget coordinate_calc_result_text = (Widget)NULL; static char coordinate_calc_lat_deg[5]; static char coordinate_calc_lat_min[15]; static char coordinate_calc_lat_dir[5]; static char coordinate_calc_lon_deg[5]; static char coordinate_calc_lon_min[15]; static char coordinate_calc_lon_dir[5]; coordinate_calc_array_type coordinate_calc_array; // --------------------------- help menu ----------------------------- Widget help_list; Widget help_index_dialog = (Widget)NULL; Widget help_view_dialog = (Widget)NULL; Widget emergency_beacon_toggle; int emergency_beacon = 0; static void Help_About(Widget w, XtPointer clientData, XtPointer callData); static void Help_Index(Widget w, XtPointer clientData, XtPointer callData); void Emergency_beacon_toggle( Widget widget, XtPointer clientData, XtPointer callData); // ----------------------------- map --------------------------------- Widget map_list; Widget map_properties_list; void map_index_update_temp_select(char *filename, map_index_record **current); void map_index_temp_select_clear(void); void map_chooser_fill_in (void); int map_chooser_expand_dirs = 0; void map_chooser_init (void); Widget map_chooser_dialog = (Widget)NULL; Widget map_chooser_button_ok = (Widget)NULL; Widget map_chooser_button_cancel = (Widget)NULL; Widget map_properties_dialog = (Widget)NULL; static void Map_chooser(Widget w, XtPointer clientData, XtPointer callData); Widget map_chooser_maps_selected_data = (Widget)NULL; int re_sort_maps = 1; #ifdef HAVE_LIBGEOTIFF static void Config_DRG(Widget w, XtPointer clientData, XtPointer callData); #endif // HAVE_LIBGEOTIFF Widget grid_on, grid_off; static void Grid_toggle( Widget w, XtPointer clientData, XtPointer calldata); int long_lat_grid; // Switch for Map Lat and Long grid display void Map_border_toggle( Widget w, XtPointer clientData, XtPointer callData); int draw_labeled_grid_border = FALSE; // Toggle labeled border around map. static void CAD_draw_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_lock_pan_zoom = 0; static void Map_lock_pan_zoom_toggle( Widget w, XtPointer clientData, XtPointer calldata); int disable_all_maps = 0; static void Map_disable_toggle( Widget w, XtPointer clientData, XtPointer calldata); static void Map_auto_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_auto_maps; /* toggle use of auto_maps */ static void Map_auto_skip_raster_toggle( Widget w, XtPointer clientData, XtPointer calldata); int auto_maps_skip_raster; Widget map_auto_skip_raster_button; Widget map_border_button; Widget map_levels_on, map_levels_off; static void Map_levels_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_color_levels; /* toggle use of map_color_levels */ Widget map_labels_on, map_labels_off; static void Map_labels_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_labels; // toggle use of map_labels */ Widget map_fill_on, map_fill_off; static void Map_fill_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_color_fill; /* Whether or not to fill in map polygons with solid color */ int index_maps_on_startup; // Index maps on startup static void Index_maps_on_startup_toggle(Widget w, XtPointer clientData, XtPointer calldata); Widget map_bgcolor[12]; static void Map_background(Widget w, XtPointer clientData, XtPointer calldata); int map_background_color; /* Background color for maps */ #if !defined(NO_GRAPHICS) Widget raster_intensity[11]; static void Raster_intensity(Widget w, XtPointer clientData, XtPointer calldata); #if defined(HAVE_MAGICK) Widget gamma_adjust_dialog = (Widget)NULL; Widget gamma_adjust_text; #endif // HAVE_MAGICK #endif // NO_GRAPHICS Widget map_font_dialog = (Widget)NULL; Widget map_font_text[FONT_MAX]; Widget map_station_label0,map_station_label1,map_station_label2,map_station_label3; static void Map_station_label(Widget w, XtPointer clientData, XtPointer calldata); int letter_style; /* Station Letter style */ Widget map_icon_outline0,map_icon_outline1,map_icon_outline2,map_icon_outline3; static void Map_icon_outline(Widget w, XtPointer clientData, XtPointer calldata); int icon_outline_style; /* Icon Outline style */ Widget map_wx_alerts_0,map_wx_alerts_1; static void Map_wx_alerts_toggle(Widget w, XtPointer clientData, XtPointer calldata); int wx_alert_style; /* WX alert map style */ time_t map_refresh_interval = 0; /* how often to refresh maps, seconds */ time_t map_refresh_time = 0; /* when to refresh maps next, seconds */ // ------------------------ Filter and Display menus ----------------------------- Selections Select_ = { 0, // none 1, // mine 1, // tnc 1, // direct 1, // via_digi 1, // net 0, // tactical 1, // old_data 1, // stations 1, // fixed_stations 1, // moving_stations 1, // weather_stations 1, // CWOP_wx_stations 1, // objects 1, // weather_objects 1, // gauge_objects 1, // other_objects 1, // aircraft_objects 1, // vessel_objects }; What_to_display Display_ = { 1, // callsign 1, // label_all_trackpoints 1, // symbol 1, // symbol_rotate 1, // trail 1, // course 1, // speed 1, // speed_short 1, // altitude 1, // weather 1, // weather_text 1, // temperature_only 1, // wind_barb 1, // aloha_circle 1, // ambiguity 1, // phg 1, // default_phg 1, // phg_of_moving 1, // df_data 1, // df_beamwidth_data 1, // df_bearing_data 1, // dr_data 1, // dr_arc 1, // dr_course 1, // dr_symbol 1, // dist_bearing 1, // last_heard }; Widget select_none_button; Widget select_mine_button; Widget select_tnc_button; Widget select_direct_button; Widget select_via_digi_button; Widget select_net_button; Widget select_tactical_button; Widget select_old_data_button; Widget select_stations_button; Widget select_fixed_stations_button; Widget select_moving_stations_button; Widget select_weather_stations_button; Widget select_CWOP_wx_stations_button; Widget select_objects_button; Widget select_weather_objects_button; Widget select_gauge_objects_button; Widget select_other_objects_button; Widget select_aircraft_objects_button; Widget select_vessel_objects_button; Widget display_callsign_button; Widget display_label_all_trackpoints_button; Widget display_symbol_button; Widget display_symbol_rotate_button; Widget display_trail_button; Widget display_course_button; Widget display_speed_button; Widget display_speed_short_button; Widget display_altitude_button; Widget display_weather_button; Widget display_weather_text_button; Widget display_temperature_only_button; Widget display_wind_barb_button; Widget display_aloha_circle_button; Widget display_ambiguity_button; Widget display_phg_button; Widget display_default_phg_button; Widget display_phg_of_moving_button; Widget display_df_data_button; Widget display_df_beamwidth_data_button; Widget display_df_bearing_data_button; Widget display_dr_data_button; Widget display_dr_arc_button; Widget display_dr_course_button; Widget display_dr_symbol_button; Widget display_dist_bearing_button; Widget display_last_heard_button; static void Select_none_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_mine_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_tnc_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_direct_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_via_digi_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_net_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_tactical_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_old_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_fixed_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_moving_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_weather_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_CWOP_wx_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_weather_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_other_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_gauge_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_aircraft_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_vessel_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_callsign_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_label_all_trackpoints_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_symbol_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_symbol_rotate_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_trail_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_course_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_speed_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_speed_short_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_altitude_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_weather_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_weather_text_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_temperature_only_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_wind_barb_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_aloha_circle_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_ambiguity_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_phg_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_default_phg_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_phg_of_moving_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_beamwidth_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_bearing_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_arc_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_course_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_symbol_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dist_bearing_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_last_heard_toggle(Widget w, XtPointer clientData, XtPointer calldata); // ------------------------ Interfaces -------------------------- static void Transmit_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Posit_tx_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Object_tx_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Server_port_toggle( Widget widget, XtPointer clientData, XtPointer callData); int transmit_disable; int posit_tx_disable; int object_tx_disable; int enable_server_port = 0; Widget iface_transmit_now, posit_tx_disable_toggle, object_tx_disable_toggle; Widget server_port_toggle; #ifdef HAVE_GPSMAN Widget Fetch_gps_track, Fetch_gps_route, Fetch_gps_waypoints; Widget Fetch_RINO_waypoints; Widget Send_gps_track, Send_gps_route, Send_gps_waypoints; int gps_got_data_from = 0; // We got data from a GPS int gps_operation_pending = 0; // A GPS transfer is happening int gps_details_selected = 0; // Whether name/color have been selected yet Widget gpsfilename_text; // Short name of gps map (no color/type) char gps_map_filename[MAX_FILENAME];// Chosen name of gps map (including color) char gps_map_filename_base[MAX_FILENAME]; // Same minus ".shp" char gps_map_filename_base2[MAX_FILENAME]; // Same minus ".shp" and color char gps_temp_map_filename[MAX_FILENAME]; char gps_temp_map_filename_base[MAX_FILENAME]; // Same minus ".shp" char gps_dbfawk_format[]="BEGIN_RECORD {key=\"\"; lanes=3; color=%d; name=\"%s\"; filled=0; pattern=1; display_level=65536; label_level=128; label_color=8; symbol=\"\"}\n"; int gps_map_color = 0; // Chosen color of gps map int gps_map_color_offset; // offset into colors array of that color. char gps_map_type[30]; // Type of GPS download void check_for_new_gps_map(int curr_sec); Widget GPS_operations_dialog = (Widget)NULL; #endif // HAVE_GPSMAN // ------------------------ unit conversion -------------------------- static void Units_choice_toggle(Widget w, XtPointer clientData, XtPointer calldata); // 0: metric, 1: english, (2: nautical, not fully implemented) int english_units; char un_alt[2+1]; // m / ft char un_dst[2+1]; // mi / km (..nm) char un_spd[4+1]; // mph / km/h (..kn) double cvt_m2len; // from meter double cvt_kn2len; // from knots double cvt_mi2len; // from miles double cvt_dm2len; // from decimeter double cvt_hm2len; // from hectometer void update_units(void); // dist/bearing on status line static void Dbstatus_choice_toggle(Widget w, XtPointer clientData, XtPointer calldata); int do_dbstatus; // Coordinate System int coordinate_system = USE_DDMMMM; // Default, used for most APRS systems // ------------------------- audio alarms ---------------------------- Widget configure_audio_alarm_dialog = (Widget)NULL; Widget audio_alarm_config_play_data, audio_alarm_config_play_on_new_station, audio_alarm_config_play_ons_data, audio_alarm_config_play_on_new_message, audio_alarm_config_play_onm_data, audio_alarm_config_play_on_prox, audio_alarm_config_play_onpx_data, audio_alarm_config_play_on_bando, audio_alarm_config_play_onbo_data, prox_min_data, prox_max_data, bando_min_data, bando_max_data, audio_alarm_config_play_on_wx_alert, audio_alarm_config_wx_alert_data; static void Configure_audio_alarms(Widget w, XtPointer clientData, XtPointer callData); // ---------------------------- speech ------------------------------- Widget configure_speech_dialog = (Widget)NULL; Widget speech_config_play_on_new_station, speech_config_play_on_new_message_alert, speech_config_play_on_new_message_body, speech_config_play_on_prox, speech_config_play_on_trak, speech_config_play_on_bando, speech_config_play_on_new_wx_alert; static void Configure_speech(Widget w, XtPointer clientData, XtPointer callData); //#ifdef HAVE_FESTIVAL /* WARNING - new station is initialized to FALSE for a reason */ /* If you're tempted to make it something that can be saved and restored */ /* beware, Speech cannot keep up with the initial flow of data from an */ /* Internet connection that has buffered data. An unbuffered connection */ /* yes, but not a buffered one. Ken, N7IPB */ int festival_speak_new_station = FALSE; int festival_speak_proximity_alert; int festival_speak_tracked_proximity_alert; int festival_speak_band_opening; int festival_speak_new_message_alert; int festival_speak_new_message_body; int festival_speak_new_weather_alert; int festival_speak_ID; //#endif // HAVE_FESTIVAL int ATV_screen_ID; #ifdef HAVE_LIBGEOTIFF Widget configure_DRG_dialog = (Widget) NULL; Widget DRG_XOR, DRG_color0, DRG_color1, DRG_color2, DRG_color3, DRG_color4, DRG_color5, DRG_color6, DRG_color7, DRG_color8, DRG_color9, DRG_color10, DRG_color11, DRG_color12; int DRG_XOR_colors = 0; int DRG_show_colors[13]; #endif // HAVE_LIBGEOTIFF // ------------------------------------------------------------------- Widget read_selection_dialog = (Widget)NULL; // config station values Widget station_config_call_data, station_config_slat_data_deg, station_config_slat_data_min, station_config_slat_data_ns, station_config_slong_data_deg, station_config_slong_data_min, station_config_slong_data_ew, station_config_group_data, station_config_symbol_data, station_config_icon, station_config_comment_data; Pixmap CS_icon0, CS_icon; /* defaults*/ #ifdef TRANSMIT_RAW_WX Widget raw_wx_tx; #endif // TRANSMIT_RAW_WX Widget compressed_posit_tx; Widget compressed_objects_items_tx; Widget new_bulletin_popup_enable; Widget zero_bulletin_popup_enable; Widget warn_about_mouse_modifiers_enable; Widget my_trail_diff_color_enable; Widget load_predefined_objects_menu_from_file_enable; #ifdef USE_COMBO_BOX Widget load_predefined_objects_menu_from_file; // combo box widget #else int lpomff_value; // replacement value for predefined menu file combo box #endif // USE_COMBO_BOX int pop_up_new_bulletins = 0; int view_zero_distance_bulletins = 0; int warn_about_mouse_modifiers = 1; Widget altnet_active; Widget altnet_text; Widget disable_dupe_check; Widget new_map_layer_text = (Widget)NULL; Widget new_max_zoom_text = (Widget)NULL; Widget new_min_zoom_text = (Widget)NULL; Widget debug_level_text; static int sec_last_dr_update = 0; FILE *f_xfontsel_pipe[FONT_MAX]; int xfontsel_query = 0; // ------------------------------------------------------------------- static void UpdateTime( XtPointer clientData, XtIntervalId id ); void pos_dialog(Widget w); static void Zoom_in(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_in_no_pan(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_out(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_out_no_pan(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_level(Widget w, XtPointer clientData, XtPointer calldata); static void display_zoom_image(int recenter); static void Track_Me( Widget w, XtPointer clientData, XtPointer calldata); static void Measure_Distance( Widget w, XtPointer clientData, XtPointer calldata); static void SetMyPosition( Widget w, XtPointer clientData, XtPointer calldata); static void Pan_ctr(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_up(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_up_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_down(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_down_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_left(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_left_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_right(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_right_less(Widget w, XtPointer clientData, XtPointer calldata); void Center_Zoom(Widget w, XtPointer clientData, XtPointer calldata); void Go_Home(Widget w, XtPointer clientData, XtPointer calldata); int center_zoom_override = 0; Widget center_zoom_dialog = (Widget)NULL; Widget custom_zoom_dialog = (Widget)NULL; static void Menu_Quit(Widget w, XtPointer clientData, XtPointer calldata); static void TNC_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void TNC_Transmit_now(Widget w, XtPointer clientData, XtPointer calldata); #ifdef HAVE_GPSMAN static void GPS_operations(Widget w, XtPointer clientData, XtPointer calldata); #endif // HAVE_GPSMAN static void Net_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void IGate_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Message_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void WX_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void WX_Alert_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); void on_off_switch(int switchpos, Widget first, Widget second); void sel3_switch(int switchpos, Widget first, Widget second, Widget third); void sel4_switch(int switchpos, Widget first, Widget second, Widget third, Widget fourth); static void Configure_station(Widget w, XtPointer clientData, XtPointer callData); static void Configure_defaults(Widget w, XtPointer clientData, XtPointer callData); static void Configure_timing(Widget w, XtPointer clientData, XtPointer callData); static void Configure_coordinates(Widget w, XtPointer clientData, XtPointer callData); static void Stations_Clear(Widget w, XtPointer clientData, XtPointer callData); static void Test(Widget w, XtPointer clientData, XtPointer callData); static void Save_Config(Widget w, XtPointer clientData, XtPointer callData); static void Read_File_Selection(Widget w, XtPointer clientData, XtPointer callData); static void Display_data(Widget w, XtPointer clientData, XtPointer callData); static void Auto_msg_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Satellite_msg_ack_toggle( Widget widget, XtPointer clientData, XtPointer callData); Widget auto_msg_toggle; Widget satellite_msg_ack_toggle; Widget posamb0,posamb1,posamb2,posamb3,posamb4; //////////////////////////////////////////////////////////////////////////////////////////////////// /* GLOBAL DEFINES */ GC gc=0; // Used for drawing maps GC gc2=0; // Used for drawing symbols GC gc_tint=0; // Used for tinting maps & symbols GC gc_stipple=0; // Used for drawing symbols GC gc_bigfont=0; Pixmap pixmap; Pixmap pixmap_alerts; Pixmap pixmap_final; // Global variable, so we can set it up once check it from then on, // preventing memory leaks from repeatedly setting up the same // XFontStruct. XFontStruct *station_font = NULL; // Station font XFontStruct *font1; // Menu/System font XmFontList fontlist1; // Menu/System fontlist Pixmap pixmap_50pct_stipple; // 50% pixels used for position ambiguity, DF circle, etc. Pixmap pixmap_25pct_stipple; // 25% pixels used for large position ambiguity Pixmap pixmap_13pct_stipple; // 12.5% pixels used for larger position ambiguity Pixmap pixmap_wx_stipple; // Used for weather alerts int interrupt_drawing_now = 0; // Flag used to interrupt map drawing int request_resize = 0; // Flag used to request a resize operation int request_new_image = 0; // Flag used to request a create_image operation //time_t last_input_event = (time_t)0; // Time of last mouse/keyboard event void new_image(Widget da); typedef struct XastirGlobal { Widget top; // top level shell } XastirGlobal; XastirGlobal Global; char *database_ptr; /* database pointers */ //--------------------------------------------------------------------------------------------- // // These describe the current map window. They must be kept // up-to-date when we zoom/pan/resize the window. // float f_center_longitude; // Floating point map center longitude, updated by new_image() float f_center_latitude; // Floating point map center latitude , updated by new_image() float f_NW_corner_longitude; // longitude of NW corner, updated by create_image(), refresh_image() float f_NW_corner_latitude; // latitude of NW corner, updated by create_image(), refresh_image() float f_SE_corner_longitude; // longitude of SE corner, updated by create_image(), refresh_image() float f_SE_corner_latitude; // latitude of SE corner, updated by create_image(), refresh_image() long center_longitude; // Longitude at center of map, updated by display_zoom_image() long center_latitude; // Latitude at center of map, updated by display_zoom_image() long NW_corner_longitude; // Longitude at NW corner, updated by create_image(), refresh_image() long NW_corner_latitude; // Latitude at NW corner, updated by create_image(), refresh_image() long SE_corner_longitude; // Longitude at SE corner, updated by create_image(), refresh_image() long SE_corner_latitude; // Latitude at SE corner, updated by create_image(), refresh_image() long scale_x; // x scaling in 1/100 sec per pixel, calculated from scale_y long scale_y; // y scaling in 1/100 sec per pixel long new_mid_x, new_mid_y; // Check values used before applying real change long new_scale_x; long new_scale_y; long screen_width; // Screen width, map area without border (in pixels) long screen_height; // Screen height, map area without border (in pixels) Position screen_x_offset; Position screen_y_offset; float d_screen_distance; // Diag screen distance float x_screen_distance; // x screen distance //--------------------------------------------------------------------------------------------- char user_dir[1000]; /* user directory file */ int delay_time; /* used to delay display data */ time_t last_weather_cycle; // Time of last call to cycle_weather() Pixel colors[256]; /* screen colors */ Pixel trail_colors[MAX_TRAIL_COLORS]; /* station trail colors, duh */ int current_trail_color; /* what color to draw station trails with */ Pixel_Format visual_type = NOT_TRUE_NOR_DIRECT; int install_colormap; /* if visual_type == NOT_TRUE..., should we install priv cmap */ Colormap cmap; /* current colormap */ int redo_list; // Station List update request int redraw_on_new_data; // Station redraw request int wait_to_redraw; /* wait to redraw until system is up */ int display_up = 0; /* display up? */ int display_up_first = 0; /* display up first */ time_t max_transmit_time; /* max time between transmits */ time_t last_alert_redraw; /* last time alert caused a redraw */ time_t sec_next_gps; /* next gps check */ time_t gps_time; /* gps delay time */ char gprmc_save_string[MAX_LINE_SIZE+1]; char gpgga_save_string[MAX_LINE_SIZE+1]; int gps_port_save; time_t POSIT_rate; // Posit TX rate timer time_t OBJECT_rate; // Object/Item TX rate timer time_t update_DR_rate; // How often to call draw_symbols if DR enabled time_t remove_ID_message_time; // Time to get rid of large msg on screen. int pending_ID_message = 0; // Variable turning on/off this function // SmartBeaconing(tm) stuff. If enabled, POSIT_rate won't be used // for timing posits. sb_POSIT_rate computed via SmartBeaconing(tm) // will be used instead. int smart_beaconing; // Master enable/disable for SmartBeaconing(tm) mode int sb_POSIT_rate = 30 * 60; // Computed SmartBeaconing(tm) posit rate (secs) int sb_last_heading = -1; // Heading at time of last posit int sb_current_heading = -1; // Most recent heading parsed from GPS sentence int sb_turn_min = 20; // Min threshold for corner pegging (degrees) int sb_turn_slope = 25; // Threshold slope for corner pegging (degrees/mph) int sb_turn_time = 5; // Time between other beacon & turn beacon (secs) int sb_posit_fast = 90; // Fast beacon rate (secs) int sb_posit_slow = 30; // Slow beacon rate (mins) int sb_low_speed_limit = 2; // Speed below which SmartBeaconing(tm) is disabled & // we'll beacon at the POSIT_slow rate (mph) int sb_high_speed_limit = 60; // Speed above which we'll beacon at the // POSIT_fast rate (mph) Widget smart_beacon_dialog = (Widget)NULL; Widget smart_beacon_enable = (Widget)NULL; Widget sb_hi_rate_data = (Widget)NULL; Widget sb_hi_mph_data = (Widget)NULL; Widget sb_lo_rate_data = (Widget)NULL; Widget sb_lo_mph_data = (Widget)NULL; Widget sb_min_turn_data = (Widget)NULL; Widget sb_turn_slope_data = (Widget)NULL; Widget sb_wait_time_data = (Widget)NULL; Widget ghosting_time = (Widget)NULL; Widget clearing_time = (Widget)NULL; Widget aircraft_clearing_time = (Widget)NULL; Widget removal_time = (Widget)NULL; Widget posit_interval = (Widget)NULL; Widget gps_interval = (Widget)NULL; Widget dead_reckoning_time = (Widget)NULL; Widget object_item_interval = (Widget)NULL; Widget serial_pacing_time = (Widget)NULL; Widget trail_segment_timeout = (Widget)NULL; Widget trail_segment_distance_max = (Widget)NULL; Widget RINO_download_timeout = (Widget)NULL; Widget net_map_slider = (Widget)NULL; Widget snapshot_interval_slider = (Widget)NULL; int net_map_timeout = 120; time_t GPS_time; /* gps time out */ time_t last_statusline; // last update of statusline or 0 if inactive time_t last_id_time; // Time of last ID message to statusline time_t sec_old; /* station old after */ time_t sec_clear; /* station cleared after */ time_t aircraft_sec_clear; /* aircraft cleared after */ time_t sec_remove; /* Station removed after */ int trail_segment_time; // Segment missing if above this time (mins) int trail_segment_distance; // Segment missing if greater distance int RINO_download_interval; // Interval at which to download RINO waypoints, // creating APRS Objects from them. time_t last_RINO_download = (time_t)0; time_t sec_next_raw_wx; /* raw wx transmit data */ int dead_reckoning_timeout = 60 * 10; // 10 minutes; #ifdef TRANSMIT_RAW_WX int transmit_raw_wx; /* transmit raw wx data? */ #endif // TRANSMIT_RAW_WX int transmit_compressed_posit; // transmit location in compressed format? int transmit_compressed_objects_items; // Same for objects & items int output_station_type; /* Broadcast station type */ int Configure_station_pos_amb; /* Broadcast station position ambiguity */ long max_vectors_allowed; /* max map vectors allowed */ long max_text_labels_allowed; /* max map text labels allowed */ long max_symbol_labels_allowed; /* max map symbol labels allowed */ time_t net_last_time; /* reconnect last time in seconds */ time_t net_next_time; /* reconnect Next update delay time */ #ifdef USING_LIBGC time_t gc_next_time = 0L; // Garbage collection next time #endif // USING_LIBGC time_t posit_last_time; time_t posit_next_time; /* time at which next posit TX will occur */ time_t last_time; /* last time in seconds */ time_t next_time; /* Next update delay time */ time_t next_redraw; /* Next update time */ time_t last_redraw; /* Time of last redraw */ char aprs_station_message_type = '='; // station message-capable or not int transmit_now; /* set to transmit now (push on moment) */ int my_position_valid = 1; /* Don't send posits if this is zero */ int using_gps_position = 0; /* Set to one if a GPS port is active */ int operate_as_an_igate; /* toggle igate operations for net connections */ unsigned igate_msgs_tx; /* current total of igate messages transmitted */ int log_tnc_data; /* log data */ int log_net_data; /* log data */ int log_igate; /* toggle to allow igate logging */ int log_wx; /* toggle to allow wx logging */ int log_message_data; /* toggle to allow message logging */ int log_wx_alert_data; /* toggle to allow wx alert logging */ int snapshots_enabled = 0; // toggle to allow creating .png snapshots on a regular basis int kmlsnapshots_enabled = 0; // toggle to allow creating .kml snapshots on a regular basis time_t WX_ALERTS_REFRESH_TIME; /* Minimum WX alert map refresh time in seconds */ /* button zoom */ int menu_x; int menu_y; int possible_zoom_function = 0; int zoom_box_x1 = -1; // Stores one corner of zoom box int zoom_box_y1 = -1; int zoom_box_x2 = -1; // Stores one corner of zoom box int zoom_box_y2 = -1; int mouse_zoom = 0; // log file replay int read_file; FILE *read_file_ptr; time_t next_file_read; // Data for own station char my_callsign[MAX_CALLSIGN+1]; char my_lat[MAX_LAT]; char my_long[MAX_LONG]; char my_group; char my_symbol; char my_phg[MAX_PHG+1]; char my_comment[MAX_COMMENT+1]; int my_last_course; int my_last_speed; long my_last_altitude; time_t my_last_altitude_time; /* Symbols */ SymbolData symbol_data[MAX_SYMBOLS]; /* sound run */ pid_t last_sound_pid; /* Default directories */ char AUTO_MAP_DIR[400]; char ALERT_MAP_DIR[400]; char SELECTED_MAP_DIR[400]; char SELECTED_MAP_DATA[400]; char MAP_INDEX_DATA[400]; char SYMBOLS_DIR[400]; char HELP_FILE[400]; char SOUND_DIR[400]; char LOGFILE_TNC[400]; char LOGFILE_NET[400]; char LOGFILE_IGATE[400]; char LOGFILE_MESSAGE[400]; char LOGFILE_WX[400]; char LOGFILE_WX_ALERT[400]; /* sound data */ char sound_command[90]; int sound_play_new_station; char sound_new_station[90]; int sound_play_new_message; char sound_new_message[90]; int sound_play_prox_message; char sound_prox_message[90]; char prox_min[30]; char prox_max[30]; int sound_play_band_open_message; char sound_band_open_message[90]; char bando_min[30]; char bando_max[30]; int sound_play_wx_alert_message; char sound_wx_alert_message[90]; int input_x = 0; int input_y = 0; XtAppContext app_context; Display *display; /* Display */ /* dialog popup last */ int last_popup_x; int last_popup_y; int disable_all_popups = 0; char temp_tracking_station_call[30] = ""; time_t program_start_time; int measuring_distance = 0; int moving_object = 0; ///////////////////////////////////////////////////////////////////////// void Smart_Beacon_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); smart_beacon_dialog = (Widget)NULL; } // Still need to do some bounds checking on the values here. // // If the user enters 0's or non-numeric data, this function sets the // values to reasonable defaults. // // Another thing that'd be good to do is to recalculate the next // beacon time if one of the posit rates is shortened. Otherwise we // might be waiting a while to get into the "right rhythm". // void Smart_Beacon_change_data(Widget widget, XtPointer clientData, XtPointer callData) { // Snag the XmTextString data and write it into the variables if (smart_beacon_dialog != NULL) { char *str_ptr1; int i; smart_beaconing = (int)XmToggleButtonGetState(smart_beacon_enable); str_ptr1 = XmTextGetString(sb_hi_rate_data); i = atoi(str_ptr1); if (i == 0) { i = 90; } sb_posit_fast = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_hi_mph_data); i = atoi(str_ptr1); switch (english_units) { case 0: // Metric: Convert from KPH to MPH for storage i = (int)((i * 0.62137) + 0.5); break; case 1: // English case 2: // Nautical default: // No conversion necessary break; } if (i == 0) { i = 60; } sb_high_speed_limit = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_lo_rate_data); i = atoi(str_ptr1); if (i == 0) { i = 30; } sb_posit_slow = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_lo_mph_data); i = atoi(str_ptr1); switch (english_units) { case 0: // Metric: Convert from KPH to MPH for storage i = (int)((i * 0.62137) + 0.5); break; case 1: // English case 2: // Nautical default: // No conversion necessary break; } if (i == 0) { i = 2; } sb_low_speed_limit = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_min_turn_data); i = atoi(str_ptr1); if (i == 0) { i = 20; } sb_turn_min = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_turn_slope_data); i = atoi(str_ptr1); if (i == 0) { i = 25; } sb_turn_slope = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_wait_time_data); i = atoi(str_ptr1); if (i == 0) { i = 5; } sb_turn_time = i; // Free the space. XtFree(str_ptr1); Smart_Beacon_destroy_shell(widget,clientData,callData); } } void Smart_Beacon(Widget w, XtPointer UNUSED(clientData), XtPointer callData) { static Widget pane, scrollwindow, form, label1, label2, label3, label4, label5, label6, button_ok, button_cancel; // static Widget label7; Atom delw; char temp_string[10]; char temp_label_string[100]; // Destroy the dialog if it exists. This is to make sure the // title is correct based on the last dialog that called us. if (smart_beacon_dialog) { Smart_Beacon_destroy_shell( w, smart_beacon_dialog, callData); } if (!smart_beacon_dialog) { smart_beacon_dialog = XtVaCreatePopupShell(langcode("SMARTB001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Smart_Beacon pane", xmPanedWindowWidgetClass, smart_beacon_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Smart_Beacon form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); smart_beacon_enable = XtVaCreateManagedWidget(langcode("SMARTB011"), xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label1 = XtVaCreateManagedWidget(langcode("SMARTB002"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, smart_beacon_enable, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_hi_rate_data = XtVaCreateManagedWidget("Smart_Beacon hi_rate_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, smart_beacon_enable, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); switch (english_units) { case 0: // Metric xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB004") ); break; case 1: // English case 2: // Nautical default: xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB003") ); break; } // High Speed (mph) / (kph) label2 = XtVaCreateManagedWidget(temp_label_string, xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_hi_mph_data = XtVaCreateManagedWidget("Smart_Beacon hi_mph_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label1, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label3 = XtVaCreateManagedWidget(langcode("SMARTB005"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_lo_rate_data = XtVaCreateManagedWidget("Smart_Beacon lo_rate_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); switch (english_units) { case 0: // Metric xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB007") ); break; case 1: // English case 2: // Nautical default: xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB006") ); break; } // Low Speed (mph) / (kph) label4 = XtVaCreateManagedWidget(temp_label_string, xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_lo_mph_data = XtVaCreateManagedWidget("Smart_Beacon lo_mph_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label3, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label5 = XtVaCreateManagedWidget(langcode("SMARTB008"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label4, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_min_turn_data = XtVaCreateManagedWidget("Smart_Beacon min_turn_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label6 = XtVaCreateManagedWidget(langcode("SMARTB009"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_turn_slope_data = XtVaCreateManagedWidget("Smart_Beacon turn_slope_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); //label7 XtVaCreateManagedWidget(langcode("SMARTB010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label6, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_wait_time_data = XtVaCreateManagedWidget("Smart_Beacon wait_time_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label6, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sb_wait_time_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Smart_Beacon_change_data, smart_beacon_dialog); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sb_wait_time_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Smart_Beacon_destroy_shell, smart_beacon_dialog); pos_dialog(smart_beacon_dialog); delw = XmInternAtom(XtDisplay(smart_beacon_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(smart_beacon_dialog, delw, Smart_Beacon_destroy_shell, (XtPointer)smart_beacon_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, smart_beacon_dialog); XtPopup(smart_beacon_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(smart_beacon_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(smart_beacon_dialog), XtWindow(smart_beacon_dialog)); } // Fill in the current values if (smart_beacon_dialog != NULL) { if(smart_beaconing) { XmToggleButtonSetState(smart_beacon_enable,TRUE,FALSE); } else { XmToggleButtonSetState(smart_beacon_enable,FALSE,FALSE); } xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_posit_fast); XmTextSetString(sb_hi_rate_data, temp_string); switch (english_units) { case 0: // Metric: Convert from MPH to KPH for display xastir_snprintf(temp_string, sizeof(temp_string), "%d", (int)((sb_high_speed_limit * 1.6094) + 0.5) ); break; case 1: // English case 2: // Nautical default: // No conversion necessary xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_high_speed_limit); break; } XmTextSetString(sb_hi_mph_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_posit_slow); XmTextSetString(sb_lo_rate_data, temp_string); switch (english_units) { case 0: // Metric: Convert from MPH to KPH for display xastir_snprintf(temp_string, sizeof(temp_string), "%d", (int)((sb_low_speed_limit * 1.6094) + 0.5) ); break; case 1: // English case 2: // Nautical default: // No conversion necessary xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_low_speed_limit); break; } XmTextSetString(sb_lo_mph_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_min); XmTextSetString(sb_min_turn_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_slope); XmTextSetString(sb_turn_slope_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_time); XmTextSetString(sb_wait_time_data, temp_string); } } ///////////////////////////////////////////////////////////////////////// // Causes the current set of internet-based maps to be snagged from // the 'net instead of from cache. Once downloaded they get written // to the cache, overwriting possibly corrupted maps already in the // cache (why else would you invoke this function?). This is a // method of getting rid of corrupted maps without having to wipe // out the entire cache. // void Re_Download_Maps_Now(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef USE_MAP_CACHE // Disable reads from the map cache map_cache_fetch_disable = 1; #endif // Show a busy cursor while the map is being downloaded busy_cursor(appshell); // Cause maps to be refreshed new_image(da); #ifdef USE_MAP_CACHE //Enable reads from the map cache map_cache_fetch_disable = 0; #endif } // Removes all files in the ~/.xastir/map_cache directory. Does not // recurse down into subdirectories, but it shouldn't have to. // void Flush_Entire_Map_Queue(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { struct dirent *dl = NULL; DIR *dm; char fullpath[MAX_FILENAME]; char dir[MAX_FILENAME]; struct stat nfile; get_user_base_dir("map_cache", dir, sizeof(dir)); dm = opendir(dir); if (!dm) // Couldn't open directory { fprintf(stderr,"Flush_Entire_Map_Queue: Couldn't open directory\n"); return; } // Read the directory contents, delete each file found, skip // directories. // while ((dl = readdir(dm))) { //Construct the entire path/filename strcpy(fullpath, dir); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string strcat(fullpath, "/"); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string strcat(fullpath, dl->d_name); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string if (stat(fullpath, &nfile) == 0) { if ((nfile.st_mode & S_IFMT) == S_IFREG) { // It's a regular file // Remove the file if (debug_level & 512) { fprintf(stderr,"Deleting file: %s\n", fullpath); } unlink(fullpath); } } } (void)closedir(dm); } // Find the extents of every map we have. This is the callback for // the "Re-Index Maps" button. // // If passed a NULL in the callback, we do a smart reindexing: Only // reindex the files that are new or have changed. // If passed a "1" in the callback, we do a full reindexing: Delete // the in-memory index and start indexing from scratch. // void Index_Maps_Now(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int parameter = 0; // Default: Smart timestamp-checking indexing if (clientData != NULL) { parameter = atoi((char *)clientData); if (parameter != 1) // Our only option { parameter = 0; } } // Update the list and write it to file. map_indexer(parameter); } void check_weather_symbol(void) { // Check for weather station, if so, make sure symbol is proper type if ( (output_station_type == 4) || (output_station_type == 5) ) { // Need one of these symbols if a weather station: /_ \_ /W \W if ( ( (my_symbol != '_') && (my_symbol != 'W') ) || ( (my_group != '\\') && (my_group != '/') ) ) { // Force it to '/_' my_group = '/'; my_symbol = '_'; // Update my station data with the new symbol my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; // Notify the operator that the symbol has been changed // "Weather Station", "Changed to WX symbol '/_', other option is '\\_'" popup_message_always( langcode("POPEM00030"), langcode("POPEM00031") ); } } } void check_nws_weather_symbol(void) { if ( (my_symbol == 'W') && ( (my_group == '\\') || (my_group == '/') ) ) { // Notify the operator that they're trying to be an NWS // weather station. popup_message_always( langcode("POPEM00030"), langcode("POPEM00032") ); } } void Coordinate_calc_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); coordinate_calc_dialog = (Widget)NULL; } // Clears out the dialog's input textFields void Coordinate_calc_clear_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { XmTextSetString(coordinate_calc_zone, ""); XmTextSetString(coordinate_calc_latitude_easting, ""); XmTextSetString(coordinate_calc_longitude_northing, ""); XmTextSetString(coordinate_calc_result_text, ""); XtSetSensitive(coordinate_calc_button_ok,FALSE); } // Computes all five coordinate representations for displaying in // the "result" textField. Also fills in the global variables for // possible later use when passing results back to the calling // dialog. We can't use the util.c:*_l2s routines for the // conversions here because the util.c routines use Xastir // coordinate system as inputs instead of normal lat/lon. Had to // home-grow our solution here. // // Inputs: full_zone, northing, easting, latitude, longitude. UTM // inputs are output directly. Latitude/longitude are converted to // the various different lat/lon representations. // // Outputs: global variables and "result" textField, full_zone. // full_zone should be a string of at least size 4. // void Coordinate_calc_output(char *full_zone, long northing, long easting, double latitude, double longitude) { char temp_string[1024]; int south = 0; int west = 0; double lat_min,lon_min,lat_sec,lon_sec; int lat_deg_int,lat_min_int; int lon_deg_int,lon_min_int; char maidenhead_grid[50]; long temp; long xastir_lat; long xastir_lon; char MGRS_str[50]; double double_easting, double_northing; // Latitude: Switch to integer arithmetic to avoid // floating-point rounding errors. // We _do_ need to round it first though so that we don't lose // accuracy. xastir_snprintf(temp_string,sizeof(temp_string),"%8.0f",latitude * 100000.0); temp = atol(temp_string); if (temp < 0) { south++; temp = labs(temp); } lat_deg_int = (int)temp / 100000; lat_min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(lat_min * 1000); lat_min_int = (int)(temp / 1000); lat_sec = (temp % 1000) * 60.0 / 1000.0; // Longitude: Switch to integer arithmetic to avoid // floating-point rounding errors. // We _do_ need to round it first though so that we don't lose // accuracy. xastir_snprintf(temp_string,sizeof(temp_string),"%9.0f",longitude * 100000.0); temp = atol(temp_string); if (temp < 0) { west++; temp = labs(temp); } lon_deg_int = (int)temp / 100000; lon_min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(lon_min * 1000); lon_min_int = (int)(temp / 1000); lon_sec = (temp % 1000) * 60.0 / 1000.0; double_easting = (double)easting; double_northing = (double)northing; convert_UTM_to_xastir(double_easting, double_northing, full_zone, &xastir_lon, &xastir_lat); //fprintf(stderr,"%s %f %f\t\t%lu %lu\n", //full_zone, //double_easting, //double_northing, //xastir_lat, //xastir_lon); // Compute MGRS coordinates. convert_xastir_to_MGRS_str(MGRS_str, sizeof(MGRS_str), xastir_lon, xastir_lat, 1); // Format with leading spaces plus spaces between // easting and northing, so that it lines up with UTM // strings. // Compute Maidenhead Grid Locator. Note that the sec_to_loc() // function expects lat/lon in Xastir coordinate system. xastir_snprintf(maidenhead_grid, sizeof(maidenhead_grid), "%s", sec_to_loc( xastir_lon, xastir_lat ) ); if (strlen(full_zone) == 1) { xastir_snprintf(temp_string, sizeof(temp_string), " %s", full_zone); memcpy(full_zone, temp_string, sizeof(&full_zone)); full_zone[sizeof(full_zone)-1] = '\0'; // Terminate string } else if (strlen(full_zone) == 2) { xastir_snprintf(temp_string, sizeof(temp_string), " %s", full_zone); memcpy(full_zone, temp_string, sizeof(&full_zone)); full_zone[sizeof(full_zone)-1] = '\0'; // Terminate string } // Put the four different representations of the coordinate into // the "result" textField. xastir_snprintf(temp_string, sizeof(temp_string), "%s%8.5f%c %9.5f%c\n%s%02d %06.3f%c %03d %06.3f%c\n%s%02d %02d %04.1f%c %03d %02d %04.1f%c\n%s%3s %07lu %07lu\n%s%s\n%s%s", langcode("COORD011"), // "Decimal Degrees:", lat_deg_int+lat_min/60.0, (south) ? 'S':'N', lon_deg_int+lon_min/60.0, (west) ? 'W':'E', langcode("COORD012"), // "Degrees/Decimal Minutes:", lat_deg_int, lat_min, (south) ? 'S':'N', lon_deg_int, lon_min, (west) ? 'W':'E', langcode("COORD013"), // "Degrees/Minutes/Dec. Seconds:", lat_deg_int, lat_min_int, lat_sec, (south) ? 'S':'N', lon_deg_int, lon_min_int, lon_sec, (west) ? 'W':'E', langcode("COORD014"), // "Universal Transverse Mercator:", full_zone, easting, northing, langcode("COORD015"), // "Military Grid Reference System:", MGRS_str, langcode("COORD016"), // "Maidenhead Grid Locator:", maidenhead_grid); XmTextSetString(coordinate_calc_result_text, temp_string); // Fill in the global dd mm.mmm values in case we wish to write // the result back to the calling dialog. // Changing to double to make "%02.0f" formatting work / get rid of compiler warning xastir_snprintf(coordinate_calc_lat_deg, sizeof(coordinate_calc_lat_deg), "%02.0f", (double)lat_deg_int); xastir_snprintf(coordinate_calc_lat_min, sizeof(coordinate_calc_lat_min), "%06.3f", lat_min); xastir_snprintf(coordinate_calc_lat_dir, sizeof(coordinate_calc_lat_dir), "%c", (south) ? 'S':'N'); // Changing to double to make "%03.0f" formatting work / get rid of compiler warning xastir_snprintf(coordinate_calc_lon_deg, sizeof(coordinate_calc_lon_deg), "%03.0f", (double)lon_deg_int); xastir_snprintf(coordinate_calc_lon_min, sizeof(coordinate_calc_lon_min), "%06.3f", lon_min); xastir_snprintf(coordinate_calc_lon_dir, sizeof(coordinate_calc_lon_dir), "%c", (west) ? 'W':'E'); } // Coordinate_calc_compute // // Inputs: coordinate_calc_zone textField // coordinate_calc_latitude_easting textField // coordinate_calc_longitude_northing textField // // Output: coordinate_calc_result_text only if the inputs are not // recognized, then it outputs help text to the textField. If // inputs are good it calls Coordinate_calc_output() to format and // save/output the results. // void Coordinate_calc_compute(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *str_ptr; char zone_letter; int zone_number = 0; char full_zone[5]; int i; int have_utm; int have_lat_lon; long easting = 0; long northing = 0; double double_easting; double double_northing; double latitude; double longitude; char temp_string[1024]; // Goal is to suck in the format provided, figure out what // format it is, then convert to the four major formats we // support and put all four into the output window, each on a // different line. // These are the formats that I'd like to be able to // auto-recognize and support: // ddN dddW IMPLEMENTED // dd N ddd W IMPLEMENTED // -dd -ddd IMPLEMENTED // dd.ddddN ddd.ddddW IMPLEMENTED // dd.dddd N ddd.dddd W IMPLEMENTED // -dd.dddd -ddd.dddd IMPLEMENTED // dd mmN ddd mmW IMPLEMENTED // dd mm N ddd mm W IMPLEMENTED // -dd mm -ddd mm IMPLEMENTED // dd mm.mmmN ddd mm.mmmW IMPLEMENTED // dd mm.mmm N ddd mm.mmm W IMPLEMENTED // -dd mm.mmm -ddd mm.mmm IMPLEMENTED // dd mm ssN ddd mm ssW IMPLEMENTED // dd mm ss N ddd mm ss W IMPLEMENTED // -dd mm ss -ddd mm ss IMPLEMENTED // dd mm ss.sN ddd mm ss.sW IMPLEMENTED // dd mm ss.s N ddd mm ss.s W IMPLEMENTED // -dd mm ss.s -ddd mm ss.s IMPLEMENTED // 10T 0123456 1234567 IMPLEMENTED // 10T 123456 1234567 IMPLEMENTED // 10T 012 3456 123 4567 // 10T 12 3456 123 4567 // Once the four major formats are created and written to the // output test widget, the dd mm.mmmN/ddd mm.mmmW formatted // output should also be saved for later pasting into the // calling dialog's input fields. DONE! // // Must also make sure that the calling dialog is still up and // active before we try to write to it's widgets. DONE! // Check for something in the zone field that looks like a valid // UTM zone. str_ptr = XmTextGetString(coordinate_calc_zone); i = strlen(str_ptr); have_utm = 1; // Wishful thinking. We'll zero it later if not. if ( (i >= 1) && (i <= 3) ) { // String is the correct length. Can have just A/B/Y/Z, or // else one or two digits plus one letter. int j; for (j = 0; j < (i-1); j++) { if ( (str_ptr[j] < '0') && (str_ptr[j] > '9') ) { // Not UTM, need either one or two digits first if // we have 2 or 3 chars. have_utm = 0; } } if ( ( (str_ptr[i-1] < 'A') || (str_ptr[i-1] > 'Z') ) && ( (str_ptr[i-1] < 'a') || (str_ptr[i-1] > 'z') ) ) { // Not UTM, zone character isn't correct have_utm = 0; } } else // Not a valid UTM zone, wrong length. { have_utm = 0; } // If we've made it to this point and have_utm == 1, then zone looks // like a UTM zone. if (have_utm) { zone_letter = toupper(str_ptr[i-1]); zone_number = atoi(str_ptr); //fprintf(stderr,"Zone Number: %d, Zone Letter: %c\n", zone_number, zone_letter); // Save it away for later use if (zone_number == 0) // We're in a UPS area { xastir_snprintf(full_zone, sizeof(full_zone), " %c", zone_letter); } else // UTM area { xastir_snprintf(full_zone, sizeof(full_zone), "%02d%c", zone_number, zone_letter); } have_lat_lon = 0; } else { //fprintf(stderr,"Bad zone, not a UTM coordinate\n"); // Skip zone widget for lat/lon, it's not used. have_lat_lon = 1; // Wishful thinking. We'll zero it later if not. } // We're done with that variable. Free the space. XtFree(str_ptr); str_ptr = XmTextGetString(coordinate_calc_latitude_easting); i = strlen(str_ptr); // Check for exactly six or seven chars. If seven, first one must // be a zero (Not true! UPS coordinates have digits there!). if ( have_utm && (i != 6) && (i != 7) ) { have_utm = 0; //fprintf(stderr,"Bad Easting value: Not 6 or 7 chars\n"); } // if ( have_utm && (i == 7) && (str_ptr[0] != '0') ) { // have_utm = 0; // //fprintf(stderr,"Bad Easting value: 7 chars but first one not 0\n"); // } if (have_utm) { int j; // Might be good to get rid of spaces at this point as we think // it's a UTM number. Might have to put it in our own string // first though to do that. for (j = 0; j < i; j++) { if ( (str_ptr[j] < '0') || (str_ptr[j] > '9') ) { // Not UTM, found a non-number have_utm = 0; } } if (have_utm) // If we still think it's a valid UTM number { easting = atol(str_ptr); //fprintf(stderr,"Easting: %lu\n",easting); } else { //fprintf(stderr,"Bad Easting value\n"); } } else if (have_lat_lon) { // Process the string to see if it's a valid latitude value. // Convert it into a double if so and store it in // "latitude". int j, substring; int south = 0; int temp[10]; // indexes to substrings char *ptr; char temp_string[30]; int piece; // Copy the string so we can change it. xastir_snprintf(temp_string,sizeof(temp_string),"%s",str_ptr); for (j = 0; j < i; j++) { temp_string[j] = toupper(temp_string[j]); } // Search for 'N' or 'S'. ptr = rindex(temp_string, 'N'); if (ptr != NULL) // Found an 'N' { *ptr = ' '; // Convert it to a space //fprintf(stderr,"Found an 'N', converted to %s\n", temp_string); } ptr = rindex(temp_string, 'S'); if (ptr != NULL) // Found an 'S' { *ptr = ' '; // Convert it to a space south++; //fprintf(stderr,"Found an 'S', converted to %s\n", temp_string); } ptr = rindex(temp_string, '-'); if (ptr != NULL) // Found an '-' { *ptr = ' '; // Convert it to a space south++; //fprintf(stderr,"Found an '-', converted to %s\n", temp_string); } // Tokenize the string // Find the space characters temp[0] = 0; // First index is to start of entire string substring = 1; for (j = 1; j < i; j++) { if (temp_string[j] == ' ') // Found a space { temp_string[j] = '\0'; // Terminate the substring if ( (j + 1) < i) // If not at the end { temp[substring++] = j + 1; // Save an index to the new substring //fprintf(stderr,"%s",&temp_string[j+1]); } } } // temp[] array now contains indexes into all of the // substrings. Some may contain empty strings. //fprintf(stderr,"Substrings: %d\n", substring); //fprintf(stderr,"temp_string: %s\n",temp_string); //for (j = 0; j < substring; j++) { // if (strlen(&temp_string[temp[j]]) > 0) { // fprintf(stderr,"%s\n", &temp_string[temp[j]]); // } //} piece = 0; have_lat_lon = 0; for (j = 0; j < substring; j++) { if (strlen(&temp_string[temp[j]]) > 0) { double kk; piece++; // Found the next piece kk = atof(&temp_string[temp[j]]); switch (piece) { case (1) : // Degrees latitude = kk; have_lat_lon = 1; break; case (2) : // Minutes if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad latitude minutes value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { latitude = latitude + ( kk / 60.0 ); } break; case (3) : // Seconds if ( (kk < 0.0) || (kk >= 60.0)) { fprintf(stderr,"Warning: Bad latitude seconds value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { latitude = latitude + ( kk / 3600.0 ); } break; default : break; } } } if (south) { latitude = -latitude; } //fprintf(stderr,"%f\n", latitude); // Test for valid values of latitude if ( have_lat_lon && ((latitude < -90.0) || (latitude > 90.0)) ) { have_lat_lon = 0; } if (strlen(str_ptr) == 0) { have_lat_lon = 0; } } // We're done with that variable. Free the space. XtFree(str_ptr); str_ptr = XmTextGetString(coordinate_calc_longitude_northing); i = strlen(str_ptr); // Check for exactly seven chars. if (have_utm && (i != 7) ) { have_utm = 0; //fprintf(stderr,"Bad Northing value: Not 7 chars\n"); } if (have_utm) { int j; // Might be good to get rid of spaces at this point as we think // it's a UTM number. Might have to put it in our own string // first though to do that. for (j = 0; j< i; j++) { if ( (str_ptr[j] < '0') || (str_ptr[j] > '9') ) { // Not UTM, found a non-number have_utm = 0; } } if (have_utm) // If we still think it's a valid UTM number { northing = atol(str_ptr); //fprintf(stderr,"Northing: %lu\n",northing); } else { //fprintf(stderr,"Bad Northing value\n"); } } else if (have_lat_lon) { // Process the string to see if it's a valid longitude // value. Convert it into a double if so and store it in // "longitude". int j, substring; int west = 0; int temp[10]; // indexes to substrings char *ptr; char temp_string[30]; int piece; // Copy the string so we can change it. xastir_snprintf(temp_string,sizeof(temp_string),"%s",str_ptr); for (j = 0; j < i; j++) { temp_string[j] = toupper(temp_string[j]); } // Search for 'W' or 'E'. ptr = rindex(temp_string, 'W'); if (ptr != NULL) // Found an 'W' { *ptr = ' '; // Convert it to a space west++; //fprintf(stderr,"Found an 'W', converted to %s\n", temp_string); } ptr = rindex(temp_string, 'E'); if (ptr != NULL) // Found an 'E' { *ptr = ' '; // Convert it to a space //fprintf(stderr,"Found an 'E', converted to %s\n", temp_string); } ptr = index(temp_string, '-'); if (ptr != NULL) // Found an '-' { *ptr = ' '; // Convert it to a space west++; //fprintf(stderr,"Found an '-', converted to %s\n", temp_string); } // Tokenize the string // Find the space characters temp[0] = 0; // First index is to start of entire string substring = 1; for (j = 1; j < i; j++) { if (temp_string[j] == ' ') // Found a space { temp_string[j] = '\0'; // Terminate the substring if ( (j + 1) < i) // If not at the end { temp[substring++] = j + 1; // Save an index to the new substring //fprintf(stderr,"%s",&temp_string[j+1]); } } } // temp[] array now contains indexes into all of the // substrings. Some may contain empty strings. //fprintf(stderr,"Substrings: %d\n", substring); //fprintf(stderr,"temp_string: %s\n",temp_string); //for (j = 0; j < substring; j++) { // if (strlen(&temp_string[temp[j]]) > 0) { // fprintf(stderr,"%s\n", &temp_string[temp[j]]); // } //} piece = 0; have_lat_lon = 0; for (j = 0; j < substring; j++) { if (strlen(&temp_string[temp[j]]) > 0) { double kk; piece++; // Found the next piece kk = atof(&temp_string[temp[j]]); switch (piece) { case (1) : // Degrees longitude = kk; have_lat_lon = 1; break; case (2) : // Minutes if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad longitude minutes value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { longitude = longitude + ( kk / 60.0 ); } break; case (3) : // Seconds if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad longitude seconds value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { longitude = longitude + ( kk / 3600.0 ); } break; default : break; } } } if (west) { longitude = -longitude; } //fprintf(stderr,"%f\n", longitude); // Test for valid values of longitude if (have_lat_lon && ((longitude < -180.0) || (longitude > 180.0)) ) { have_lat_lon = 0; } if (strlen(str_ptr) == 0) { have_lat_lon = 0; } } // We're done with that variable. Free the space. XtFree(str_ptr); // If we get to this point and have_utm == 1, then we're fairly sure // we have a good value and can convert it to the other formats for // display. if (have_utm) { //fprintf(stderr,"Processing 'good' UTM values\n"); // Process UTM values utm_ups_to_ll(E_WGS_84, (double)northing, (double)easting, full_zone, &latitude, &longitude); if (debug_level & 1) { fprintf(stderr,"Latitude: %f, Longitude: %f\n",latitude,longitude); } Coordinate_calc_output(full_zone, northing, easting, latitude, longitude); XtSetSensitive(coordinate_calc_button_ok,TRUE); } else if (have_lat_lon) { // Process lat/lon values double_northing = (double)northing; double_easting = (double)easting; ll_to_utm_ups(E_WGS_84, (double)latitude, (double)longitude, &double_northing, &double_easting, full_zone, sizeof(full_zone)); if (debug_level & 1) { fprintf(stderr,"Zone: %s, Easting: %f, Northing: %f\n", full_zone, double_easting, double_northing); } // Round the UTM values as we convert them to longs xastir_snprintf(temp_string,sizeof(temp_string),"%7.0f",double_northing); northing = atof(temp_string); xastir_snprintf(temp_string,sizeof(temp_string),"%7.0f",double_easting); easting = atof(temp_string); Coordinate_calc_output(full_zone, (long)northing, (long)easting, latitude, longitude); XtSetSensitive(coordinate_calc_button_ok,TRUE); } else // Dump out some helpful text { xastir_snprintf(temp_string, sizeof(temp_string), "%s\n%s\n%s\n%s", // " ** Sorry, your input was not recognized! **", langcode("COORD017"), // " ** Please use one of the following input formats: **", langcode("COORD018"), " ** 47.99999N 121.99999W, 47 59.999N 121 59.999W **", " ** 10T 0574599 5316887, 47 59 59.9N 121 59 59.9W **"); XmTextSetString(coordinate_calc_result_text, temp_string); XtSetSensitive(coordinate_calc_button_ok,FALSE); } } // Input: Values from the coordinate_calc_array struct. // // Output: Writes data back to the calling dialog's input fields if // the calling dialog still exists at this point. // // Make sure that if an error occurs during computation we don't // write a bad value back to the calling widget. DONE. // void Coordinate_calc_change_data(Widget widget, XtPointer clientData, XtPointer callData) { // Write output directly to the XmTextStrings pointed to by our array if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_deg != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_deg, coordinate_calc_lat_deg); } //fprintf(stderr,"%s\n",coordinate_calc_lat_deg); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_min != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_min, coordinate_calc_lat_min); } //fprintf(stderr,"%s\n",coordinate_calc_lat_min); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_dir != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_dir, coordinate_calc_lat_dir); } //fprintf(stderr,"%s\n",coordinate_calc_lat_dir); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_deg != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_deg, coordinate_calc_lon_deg); } //fprintf(stderr,"%s\n",coordinate_calc_lon_deg); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_min != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_min, coordinate_calc_lon_min); } //fprintf(stderr,"%s\n",coordinate_calc_lon_min); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_dir != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_dir, coordinate_calc_lon_dir); } //fprintf(stderr,"%s\n",coordinate_calc_lon_dir); Coordinate_calc_destroy_shell(widget,clientData,callData); } // Coordinate Calculator // // Change the title based on what dialog is calling us? // // We want all four possible coordinate formats displayed // simultaneously. DONE. // // Hitting enter or "Calculate" will cause all of the fields to be // updated. DONE (for Calculate button). // // The fields should be filled in when this is first called. // When done, this routine will pass back values via a static array // of Widget pointers to the calling dialog's fields. DONE. // // We could grey-out the OK button until we have a successful // calculation, and when the "Clear" button is pressed. This // would make sure that an invalid location doesn't // get written to the calling dialog. Would have to have a // successful conversion before we could write the value back. // void Coordinate_calc(Widget w, XtPointer clientData, XtPointer callData) { static Widget pane, scrollwindow, form, label1, label4, button_clear, button_calculate, button_cancel; // static Widget label2, label3, label5, label6; Atom delw; Arg args[50]; // Arg List register unsigned int n = 0; // Arg Count char temp_string[50]; // Destroy the dialog if it exists. This is to make sure the // title is correct based on the last dialog that called us. if (coordinate_calc_dialog) { Coordinate_calc_destroy_shell( w, coordinate_calc_dialog, callData); } if (!coordinate_calc_dialog) { // We change the title based on who's calling us. // clientData supplies the string we use for the label, and // is sent to us by the calling dialog. xastir_snprintf( temp_string, sizeof(temp_string), "%s %s", (char *)clientData, langcode("COORD001") ); coordinate_calc_dialog = XtVaCreatePopupShell(temp_string, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Coordinate_calc pane", xmPanedWindowWidgetClass, coordinate_calc_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Coordinate_calc form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 4, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); label1 = XtVaCreateManagedWidget(langcode("COORD005"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label2 XtVaCreateManagedWidget(langcode("COORD006"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 70, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label3 XtVaCreateManagedWidget(langcode("COORD007"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 200, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label4 = XtVaCreateManagedWidget(langcode("COORD008"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label5 XtVaCreateManagedWidget(langcode("COORD009"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 70, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label6 XtVaCreateManagedWidget(langcode("COORD010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 200, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ n=0; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; coordinate_calc_zone = XtVaCreateManagedWidget("Coordinate_calc zone", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((5*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); coordinate_calc_latitude_easting = XtVaCreateManagedWidget("Coordinate_calc lat", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 13, XmNwidth, ((13*7)+2), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 65, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); coordinate_calc_longitude_northing = XtVaCreateManagedWidget("Coordinate_calc lon", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 13, XmNwidth, ((14*7)+2), XmNmaxLength, 13, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 195, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // xastir_snprintf(temp_string, sizeof(temp_string), "%d", temp); // XmTextSetString(coordinate_calc_text, temp_string); coordinate_calc_result_text = NULL; coordinate_calc_result_text = XtVaCreateManagedWidget("Coordinate_calc results", xmTextWidgetClass, form, XmNrows, 6, XmNcolumns, 58, XmNeditable, FALSE, XmNtraversalOn, FALSE, XmNeditMode, XmMULTI_LINE_EDIT, XmNwordWrap, TRUE, // XmNscrollHorizontal, FALSE, XmNcursorPositionVisible, FALSE, XmNautoShowCursorPosition, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_zone, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_clear = XtVaCreateManagedWidget(langcode("COORD004"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear, XmNactivateCallback, Coordinate_calc_clear_data, coordinate_calc_dialog); button_calculate = XtVaCreateManagedWidget(langcode("COORD003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_calculate, XmNactivateCallback, Coordinate_calc_compute, coordinate_calc_dialog); coordinate_calc_button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coordinate_calc_button_ok, XmNactivateCallback, Coordinate_calc_change_data, coordinate_calc_dialog); XtSetSensitive(coordinate_calc_button_ok,FALSE); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Coordinate_calc_destroy_shell, coordinate_calc_dialog); pos_dialog(coordinate_calc_dialog); delw = XmInternAtom(XtDisplay(coordinate_calc_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(coordinate_calc_dialog, delw, Coordinate_calc_destroy_shell, (XtPointer)coordinate_calc_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, coordinate_calc_dialog); XtPopup(coordinate_calc_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(coordinate_calc_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(coordinate_calc_dialog), XtWindow(coordinate_calc_dialog)); } // Fill in the latitude values if they're available if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_deg != NULL) && (coordinate_calc_array.input_lat_min != NULL) && (coordinate_calc_array.input_lat_dir != NULL) ) { char *str_ptr1; char *str_ptr2; char *str_ptr3; str_ptr1 = XmTextGetString(coordinate_calc_array.input_lat_deg); str_ptr2 = XmTextGetString(coordinate_calc_array.input_lat_min); str_ptr3 = XmTextGetString(coordinate_calc_array.input_lat_dir); xastir_snprintf(temp_string, sizeof(temp_string), "%s %s%s", str_ptr1, str_ptr2, str_ptr3); XmTextSetString(coordinate_calc_latitude_easting, temp_string); //fprintf(stderr,"String: %s\n", temp_string); // We're done with these variables. Free the space. XtFree(str_ptr1); XtFree(str_ptr2); XtFree(str_ptr3); } // Fill in the longitude values if they're available if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_deg != NULL) && (coordinate_calc_array.input_lon_min != NULL) && (coordinate_calc_array.input_lon_dir != NULL) ) { char *str_ptr1; char *str_ptr2; char *str_ptr3; str_ptr1 = XmTextGetString(coordinate_calc_array.input_lon_deg); str_ptr2 = XmTextGetString(coordinate_calc_array.input_lon_min); str_ptr3 = XmTextGetString(coordinate_calc_array.input_lon_dir); xastir_snprintf(temp_string, sizeof(temp_string), "%s %s%s", str_ptr1, str_ptr2, str_ptr3); XmTextSetString(coordinate_calc_longitude_northing, temp_string); //fprintf(stderr,"String: %s\n", temp_string); // We're done with these variables. Free the space. XtFree(str_ptr1); XtFree(str_ptr2); XtFree(str_ptr3); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void HandlePendingEvents( XtAppContext app) { XEvent event; while(XtAppPending(app)) { XtAppNextEvent(app,&event); (void)XtDispatchEvent(&event); } } Boolean unbusy_cursor(XtPointer clientdata) { Widget w = (Widget)clientdata; (void)XUndefineCursor(XtDisplay(w),XtWindow(w)); return((Boolean)TRUE); } static Cursor cs = (Cursor)NULL; void busy_cursor(Widget w) { if(!cs) { cs=XCreateFontCursor(XtDisplay(w),XC_watch); } (void)XDefineCursor(XtDisplay(w),XtWindow(w),cs); (void)XFlush(XtDisplay(w)); // This X11 function gets invoked when X11 decides that it has // some free time. We use that to advantage in making the busy // cursor go away "magically" when we're not so busy. // (void)XtAppAddWorkProc(XtWidgetToApplicationContext(w),unbusy_cursor,(XtPointer)w); } // This function: // Draws the map data into "pixmap", copies "pixmap" to // "pixmap_alerts", draws alerts into "pixmap_alerts", copies // "pixmap_alerts" to "pixmap_final", draws symbols/tracks into // "pixmap_final" via a call to display_file(). // // Other functions which call this function are responsible for // copying the image from pixmap_final() to the screen's drawing // area. // // We check for interrupt_drawing_now flag being set, and exit // nicely if so. That flag means that some other drawing operation // needs to happen. // // Returns 0 if it gets interrupted, 1 if it completes. // int create_image(Widget w) { Dimension width, height, margin_width, margin_height; long lat_offset_temp; long long_offset_temp; char temp_course[20]; unsigned char unit_type; char medium_dashed[2] = {(char)5,(char)5}; long pos1_lat, pos1_lon, pos2_lat, pos2_lon; //busy_cursor(w); busy_cursor(appshell); if (debug_level & 4) { fprintf(stderr,"Create image start\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); screen_width = (long)width; screen_height = (long)height; long_offset_temp = NW_corner_longitude = center_longitude - (screen_width * scale_x / 2); // NW corner lat_offset_temp = NW_corner_latitude = center_latitude - (screen_height * scale_y / 2); SE_corner_longitude = center_longitude + (screen_width * scale_x / 2); SE_corner_latitude = center_latitude + (screen_height * scale_y / 2); // Set up floating point lat/long values to match Xastir // coordinates. convert_from_xastir_coordinates(&f_NW_corner_longitude, &f_NW_corner_latitude, NW_corner_longitude, NW_corner_latitude); convert_from_xastir_coordinates(&f_SE_corner_longitude, &f_SE_corner_latitude, SE_corner_longitude, SE_corner_latitude); /* map default background color */ switch (map_background_color) { case 0 : colors[0xfd] = GetPixelByName(appshell,"gray73"); break; case 1 : colors[0xfd] = GetPixelByName(w,"MistyRose"); break; case 2 : colors[0xfd] = GetPixelByName(w,"NavyBlue"); break; case 3 : colors[0xfd] = GetPixelByName(w,"SteelBlue"); break; case 4 : colors[0xfd] = GetPixelByName(w,"MediumSeaGreen"); break; case 5 : colors[0xfd] = GetPixelByName(w,"PaleGreen"); break; case 6 : colors[0xfd] = GetPixelByName(w,"PaleGoldenrod"); break; case 7 : colors[0xfd] = GetPixelByName(w,"LightGoldenrodYellow"); break; case 8 : colors[0xfd] = GetPixelByName(w,"RosyBrown"); break; case 9 : colors[0xfd] = GetPixelByName(w,"firebrick"); break; case 10 : colors[0xfd] = GetPixelByName(w,"white"); break; case 11 : colors[0xfd] = GetPixelByName(w, "black"); break; default: colors[0xfd] = GetPixelByName(appshell,"gray73"); map_background_color=0; break; } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } (void)XSetForeground(XtDisplay(w),gc,colors[0xfd]); (void)XSetBackground(XtDisplay(w),gc,colors[0xfd]); (void)XFillRectangle(XtDisplay(w), pixmap, gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } statusline(langcode("BBARSTA003"),1); // Loading Maps HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } if (display_up_first != 0) { // clear the OSM function keys. If an OSM // map is selected they will get re-initialized when // the map is loaded. init_OSM_values(); if (map_auto_maps && !disable_all_maps) { load_auto_maps(w,AUTO_MAP_DIR); } else if (!disable_all_maps) { load_maps(w); } } if (!wx_alert_style) { statusline(langcode("BBARSTA034"),1); } // Update to screen // (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* copy map data to alert pixmap */ (void)XCopyArea(XtDisplay(w),pixmap,pixmap_alerts,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } if (!wx_alert_style && !disable_all_maps) { load_alert_maps(w, ALERT_MAP_DIR); // These write onto pixmap_alerts } // Update to screen // (void)XCopyArea(XtDisplay(da),pixmap_alerts,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* copy map and alert data to final pixmap */ (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } wx_alert_update_list(); /* Compute distance */ if (lat_offset_temp<0l) { lat_offset_temp=0l; // max 90°N } else if (lat_offset_temp>64800000l) { lat_offset_temp=64800000l; // max 90°S } if(long_offset_temp<0l) { long_offset_temp=0l; // max 180°W } else if (long_offset_temp>129600000l) { long_offset_temp=129600000l; // max 180°E } pos1_lat = lat_offset_temp; pos1_lon = long_offset_temp; pos2_lat = lat_offset_temp; // ?? pos2_lon = long_offset_temp+(50.0*scale_x); // long_offset_temp = long_offset_temp+(50*scale_x); // ?? if(pos2_lat < 0l) // ?? { pos2_lat = 0l; } else if (pos2_lat > 64799999l) { pos2_lat = 64799999l; } if (pos2_lon < 0l) { pos2_lon = 0l; } else if (pos2_lon > 129599999l) { pos2_lon = 129599999l; } // Get distance in nautical miles x_screen_distance = (float)calc_distance_course(pos1_lat, pos1_lon, pos2_lat, pos2_lon, temp_course, sizeof(temp_course) ); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } draw_grid(w); // Draw grid if enabled HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } display_file(w); // display stations (symbols, info, trails) last_alert_redraw=sec_now(); // set last time of screen redraw if (debug_level & 4) { fprintf(stderr,"Create image stop\n"); } return(1); } // Routine used to refresh image WITHOUT reading regular map files // from disk. It starts with the map data already in "pixmap", // copies "pixmap" to "pixmap_alerts", draws alerts into // "pixmap_alerts", copies "pixmap_alerts" to "pixmap_final", draws // symbols/tracks into "pixmap_final" via a call to display_file(). // // Other functions which call this function are responsible for // copying the image from pixmap_final() to the screen's drawing // area. // void refresh_image(Widget w) { Dimension width, height, margin_width, margin_height; long lat_offset_temp; long long_offset_temp; char temp_course[20]; unsigned char unit_type; char medium_dashed[2] = {(char)5,(char)5}; long pos1_lat, pos1_lon, pos2_lat, pos2_lon; //busy_cursor(w); busy_cursor(appshell); if (debug_level & 4) { fprintf(stderr,"Refresh image start\n"); } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); screen_width = (long)width; screen_height = (long)height; long_offset_temp = NW_corner_longitude = center_longitude - (screen_width * scale_x / 2); NW_corner_latitude = center_latitude - (screen_height * scale_y / 2); lat_offset_temp = center_latitude; SE_corner_longitude = center_longitude + (screen_width * scale_x / 2); SE_corner_latitude = center_latitude + (screen_height * scale_y / 2); // Set up floating point lat/long values to match Xastir // coordinates. convert_from_xastir_coordinates(&f_NW_corner_longitude, &f_NW_corner_latitude, NW_corner_longitude, NW_corner_latitude); convert_from_xastir_coordinates(&f_SE_corner_longitude, &f_SE_corner_latitude, SE_corner_longitude, SE_corner_latitude); (void)XSetForeground(XtDisplay(w),gc,colors[0xfd]); (void)XSetBackground(XtDisplay(w),gc,colors[0xfd]); /* copy over map data to alert pixmap */ (void)XCopyArea(XtDisplay(w),pixmap,pixmap_alerts,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); if (!wx_alert_style && !disable_all_maps) { statusline(langcode("BBARSTA034"),1); load_alert_maps(w, ALERT_MAP_DIR); // These write onto pixmap_alerts } /* copy over map and alert data to final pixmap */ (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // statusline("Weather Alert Maps Loaded",1); wx_alert_update_list(); /* Compute distance */ if (lat_offset_temp<0l) { lat_offset_temp=0l; // max 90°N } else if (lat_offset_temp>64800000l) { lat_offset_temp=64800000l; // max 90°S } if(long_offset_temp<0l) { long_offset_temp=0l; // max 180°W } else if (long_offset_temp>129600000l) { long_offset_temp=129600000l; // max 180°E } pos1_lat = lat_offset_temp; pos1_lon = long_offset_temp; pos2_lat = lat_offset_temp; // ?? pos2_lon = long_offset_temp+(50.0*scale_x); // long_offset_temp = long_offset_temp+(50*scale_x); // ?? if(pos2_lat < 0l) // ?? { pos2_lat = 0l; } else if (pos2_lat > 64799999l) { pos2_lat = 64799999l; } if (pos2_lon < 0l) { pos2_lon = 0l; } else if (pos2_lon > 129599999l) { pos2_lon = 129599999l; } // Get distance in nautical miles x_screen_distance = (float)calc_distance_course(pos1_lat, pos1_lon, pos2_lat, pos2_lon, temp_course, sizeof(temp_course) ); // Draw grid if enabled draw_grid(w); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } /* display icons */ display_file(w); /* set last time of screen redraw*/ last_alert_redraw=sec_now(); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; if (debug_level & 4) { fprintf(stderr,"Refresh image stop\n"); } } // And this function is even faster yet. It snags "pixmap_alerts", // which already has map and alert data drawn into it, copies it to // pixmap_final, then draws symbols and tracks on top of it. When // done it copies the image to the drawing area, making it visible. void redraw_symbols(Widget w) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } /* copy over map and alert data to final pixmap */ if(!wait_to_redraw) { (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); draw_grid(w); // draw grid if enabled HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } display_file(w); // display stations (symbols, info, trails) (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); } else { fprintf(stderr,"wait_to_redraw\n"); } // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; } static void TrackMouse( Widget UNUSED(w), XtPointer clientData, XEvent *event, Boolean * UNUSED(flag) ) { char my_text[70]; char str_lat[20]; char str_long[20]; long x, y; //beg char temp_my_distance[20]; char temp_my_course[20]; char temp1_my_course[20]; long ml_lat, ml_lon; float value; //end Widget textarea = (Widget) clientData; x = (center_longitude - ((screen_width * scale_x)/2) + (event->xmotion.x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (event->xmotion.y * scale_y)); if (x < 0) // x = 0l; // 180°W { return; } if (x > 129600000l) // x = 129600000l; // 180°E { return; } if (y < 0) // y = 0l; // 90°N { return; } if (y > 64800000l) // y = 64800000l; // 90°S { return; } if (DISPLAY_XASTIR_COORDINATES) { xastir_snprintf(my_text, sizeof(my_text), "%ld %ld", y, x); } else if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { // Create a UTM string from coordinate in Xastir coordinate // system. convert_xastir_to_UTM_str(my_text, sizeof(my_text), x, y); } else if (coordinate_system == USE_MGRS) { // Create an MGRS string from coordinate in Xastir // coordinate system. convert_xastir_to_MGRS_str(my_text, sizeof(my_text), x, y, 0); } else { // Create a lat/lon string from coordinate in Xastir // coordinate system. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DEC_DEG); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DMS_NORMAL_FORMATED); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DMS_NORMAL_FORMATED); //str_lat[2]='\xB0'; str_long[3]='\xB0'; //str_lat[5]='\''; str_long[6]='\''; } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_HP_NORMAL_FORMATED); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_HP_NORMAL_FORMATED); //str_lat[2]='\xB0'; str_long[3]='\xB0'; } xastir_snprintf(my_text, sizeof(my_text), "%s %s", str_lat, str_long); } strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, sec_to_loc(x,y), sizeof(my_text) - 1 - strlen(my_text)); // begin dist/bearing if ( do_dbstatus ) { ml_lat = convert_lat_s2l(my_lat); ml_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(ml_lat,ml_lon,y,x, temp1_my_course,sizeof(temp1_my_course)); // n7tap: This is a quick hack to get some more useful values for // distance to near objects. // (copied from db.c:station_data_fill_in) if (english_units) { if (value*1.15078 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.15078*1760), langcode("SPCHSTR004")); // yards } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI020"), // miles value*1.15078); } } else { if (value*1.852 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.852*1000), langcode("UNIOP00031")); // 'm' as in meters } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI021"), // km value*1.852); } } strcpy(temp_my_course, temp1_my_course); temp_my_course[sizeof(temp_my_course)-1] = '\0'; // Terminate string strcat(temp_my_course, "\xB0"); temp_my_course[sizeof(temp_my_course)-1] = '\0'; // Terminate string strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, temp_my_distance, sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, temp_my_course, sizeof(my_text) - 1 - strlen(my_text)); } XmTextFieldSetString(textarea, my_text); XtManageChild(textarea); } static void ClearTrackMouse( Widget UNUSED(w), XtPointer UNUSED(clientData), XEvent * UNUSED(event), Boolean * UNUSED(flag) ) { // N7TAP: In my opinion, it is handy to have the cursor position still displayed // in the xastir window when I switch to another (like to write it down...) // Widget textarea = (Widget) clientData; // XmTextFieldSetString(textarea," "); // XtManageChild(textarea); } /* * Delete tracks of all stations */ void Tracks_All_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { DataRow *p_station; p_station = n_first; while (p_station != 0) { if (delete_trail(p_station)) { redraw_on_new_data=2; } p_station = p_station->n_next; } } // Get a pointer to the first station record. Loop through all // station records and clear out the tactical_call_sign fields in // each. // void clear_all_tactical(void) { DataRow *p_station = n_first; // Run through the name-ordered list of records while (p_station != 0) { if (p_station->tactical_call_sign) { // One found. Free it. free(p_station->tactical_call_sign); p_station->tactical_call_sign = NULL; } p_station = p_station->n_next; } fprintf(stderr,"Cleared all tactical calls\n"); } /* * Clear all tactical callsigns from the station records. Comment * out the active records in the log file. */ void Tactical_Callsign_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char file[200]; char file_temp[200]; FILE *f; FILE *f_temp; char line[300]; int ret; // Loop through all station records and clear out the // tactical_call_sign fields in each. clear_all_tactical(); // Get rid of the tactical callsign hash here destroy_tactical_hash(); get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); get_user_base_dir("config/tactical_calls-temp.log", file_temp, sizeof(file_temp)); // Our own internal function from util.c ret = copy_file(file, file_temp); if (ret) { fprintf(stderr,"\n\nCouldn't create temp file %s!\n\n\n", file_temp); return; } // Comment out all active lines in the log file via a '#' mark. // Read one line at a time from the temp file. Add a '#' // mark to the line if it doesn't already have it, then write // that line to the original file. f_temp=fopen(file_temp,"r"); f=fopen(file,"w"); if (f == NULL) { fprintf(stderr,"Couldn't open %s\n",file); return; } if (f_temp == NULL) { fprintf(stderr,"Couldn't open %s\n",file_temp); return; } // Read lines from the temp file and write them to the standard // file, modifying them as necessary. while (fgets(line, 300, f_temp) != NULL) { if (line[0] != '#') { fprintf(f,"#%s",line); } else { fprintf(f,"%s",line); } } fclose(f); fclose(f_temp); } /* * Clear out tactical callsign log file */ void Tactical_Callsign_History_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char file[MAX_VALUE]; FILE *f; // Loop through all station records and clear out the // tactical_call_sign fields in each. clear_all_tactical(); // Get rid of the tactical callsign hash here destroy_tactical_hash(); // Wipe out the log file. get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"w"); if (f!=NULL) { (void)fclose(f); if (debug_level & 1) { fprintf(stderr,"Clearing tactical callsign file...\n"); } } else { fprintf(stderr,"Couldn't open file for writing: %s\n", file); } fprintf(stderr,"Cleared tactical call history file\n"); } /* * Display text in the status line, text is removed after timeout */ void statusline(char *status_text,int UNUSED(update) ) { XmTextFieldSetString (text, status_text); last_statusline = sec_now(); // Used for auto-ID timeout // if (update != 0) // XmUpdateDisplay(text); // do an immediate update } /* print a message on standard error and display the same message * on the status line of the user interface. */ void stderr_and_statusline(char *message) { fprintf(stderr,"%s",message); if (message[strlen(message)-1]=='\n') { // if there is a terminal new line character remove it. message[strlen(message)-1]='\0'; } statusline(message,1); XmUpdateDisplay(text); // force an immediate update } // // Check for statusline timeout and replace statusline text with a // station identification message. // // ID was requested so that Xastir could be used for a live fast-scan // TV display over amateur radio without having to identify the // station in some other manner. As long as we guarantee that we'll // see this line for a few seconds each 10 minutes (30 minutes for // Canada), we should be within the ID rules. // void check_statusline_timeout(int curr_sec) { char status_text[100]; int id_interval = (int)(9.5 * 60); // int id_interval = (int)(1 * 5); // Debug if ( (last_statusline != 0 && (last_statusline < curr_sec - STATUSLINE_ACTIVE)) || (last_id_time < curr_sec - id_interval) ) { // We save last_id_time and identify for a few seconds if // we haven't identified for the last nine minutes or so. xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA040"), my_callsign); XmTextFieldSetString(text, status_text); if (last_id_time < curr_sec - id_interval) { popup_ID_message(langcode("BBARSTA040"),status_text); #ifdef HAVE_FESTIVAL if (festival_speak_ID) { char my_speech_callsign[100]; xastir_snprintf(my_speech_callsign, sizeof(my_speech_callsign), "%s", my_callsign); spell_it_out(my_speech_callsign, 100); xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA040"), my_speech_callsign); SayText(status_text); } #endif // HAVE_FESTIVAL } last_statusline = 0; // now inactive // Guarantee that the ID text will be viewable for a few // seconds if we haven't identified recently. Note that the // sleep statement puts the entire main thread to sleep for // that amount of time. The application will be unresponsive // during that time. if (last_id_time < (curr_sec - (9 * 60))) { //fprintf(stderr,"Identifying at nine minutes\n"); //sleep(1); } last_id_time = curr_sec; } } /* * Display current zoom factor * * DK7IN: we should find a new measure, we now have different x/y scaling! * I now only use the y value */ void display_zoom_status(void) { char zoom[30]; char siz_str[6]; if (scale_y < 9000) { xastir_snprintf(siz_str, sizeof(siz_str), "%5.0f", (float)scale_y); } else { char temp_scale[20]; xastir_snprintf(temp_scale, sizeof(temp_scale), "%ldk", scale_y/1024); memcpy(siz_str, temp_scale, sizeof(siz_str)); siz_str[sizeof(siz_str)-1] = '\0'; // Terminate string } if (track_station_on == 1) { xastir_snprintf(zoom, sizeof(zoom), langcode("BBARZM0002"), siz_str); } else { xastir_snprintf(zoom, sizeof(zoom), langcode("BBARZM0001"), siz_str); \ } XmTextFieldSetString(text4,zoom); } void Change_debug_level_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); change_debug_level_dialog = (Widget)NULL; } void Change_debug_level_reset(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { debug_level = 0; XmTextSetString(debug_level_text, "0"); // Change_debug_level_destroy_shell(widget,clientData,callData); } void Change_debug_level_change_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp; char temp_string[10]; temp = XmTextGetString(debug_level_text); debug_level = atoi(temp); if ( (debug_level < 0) || (debug_level > 32767) ) { debug_level = 0; } XtFree(temp); // Fill in the current value of debug_level xastir_snprintf(temp_string, sizeof(temp_string), "%d", debug_level); XmTextSetString(debug_level_text, temp_string); // Change_debug_level_destroy_shell(widget,clientData,callData); } void Change_Debug_Level(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close, button_reset; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ char temp_string[10]; if (!change_debug_level_dialog) { change_debug_level_dialog = XtVaCreatePopupShell(langcode("PULDNFI007"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Change Debug Level pane", xmPanedWindowWidgetClass, change_debug_level_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Change Debug Level my_form", xmFormWidgetClass, pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; debug_level_text = XtVaCreateManagedWidget("Change_Debug_Level debug text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((5*7)+2), XmNmaxLength, 4, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // Fill in the current value of debug_level xastir_snprintf(temp_string, sizeof(temp_string), "%d", debug_level); XmTextSetString(debug_level_text, temp_string); button_reset = XtVaCreateManagedWidget(langcode("UNIOP00033"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_reset, XmNactivateCallback, Change_debug_level_reset, change_debug_level_dialog); XtAddCallback(button_ok, XmNactivateCallback, Change_debug_level_change_data, change_debug_level_dialog); XtAddCallback(button_close, XmNactivateCallback, Change_debug_level_destroy_shell, change_debug_level_dialog); pos_dialog(change_debug_level_dialog); delw = XmInternAtom(XtDisplay(change_debug_level_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(change_debug_level_dialog, delw, Change_debug_level_destroy_shell, (XtPointer)change_debug_level_dialog); XtManageChild(my_form); XtManageChild(pane); XtPopup(change_debug_level_dialog,XtGrabNone); fix_dialog_size(change_debug_level_dialog); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(change_debug_level_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(change_debug_level_dialog), XtWindow(change_debug_level_dialog)); } } #if !defined(NO_GRAPHICS) && defined(HAVE_MAGICK) void Gamma_adjust_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); gamma_adjust_dialog = (Widget)NULL; } void Gamma_adjust_change_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp; char temp_string[10]; temp = XmTextGetString(gamma_adjust_text); imagemagick_gamma_adjust = atof(temp); if (imagemagick_gamma_adjust < -9.9) { imagemagick_gamma_adjust = -9.9; } else if (imagemagick_gamma_adjust > 9.9) { imagemagick_gamma_adjust = 9.9; } XtFree(temp); xastir_snprintf(temp_string, sizeof(temp_string), "%+.1f", imagemagick_gamma_adjust); XmTextSetString(gamma_adjust_text, temp_string); // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Gamma_adjust(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close; Atom delw; char temp_string[10]; if (!gamma_adjust_dialog) { // Gamma Correction gamma_adjust_dialog = XtVaCreatePopupShell(langcode("GAMMA002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Adjust Gamma pane", xmPanedWindowWidgetClass, gamma_adjust_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Adjust Gamma my_form", xmFormWidgetClass, pane, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gamma_adjust_text = XtVaCreateManagedWidget("Adjust Gamma text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, 4*10, XmNmaxLength, 4, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); xastir_snprintf(temp_string, sizeof(temp_string), "%+.1f", imagemagick_gamma_adjust); XmTextSetString(gamma_adjust_text, temp_string); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gamma_adjust_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gamma_adjust_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Gamma_adjust_change_data, gamma_adjust_dialog); XtAddCallback(button_close, XmNactivateCallback, Gamma_adjust_destroy_shell, gamma_adjust_dialog); pos_dialog(gamma_adjust_dialog); delw = XmInternAtom(XtDisplay(gamma_adjust_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(gamma_adjust_dialog, delw, Gamma_adjust_destroy_shell, (XtPointer)gamma_adjust_dialog); XtManageChild(my_form); XtManageChild(pane); XtPopup(gamma_adjust_dialog, XtGrabNone); fix_dialog_size(gamma_adjust_dialog); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(gamma_adjust_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(gamma_adjust_dialog), XtWindow(gamma_adjust_dialog)); } } #endif // NO_GRAPHICS && HAVE_MAGICK void Load_station_font(void) { // Assign a font (or a different font) to the GC // Free any old font first. If we fail to assign a new font in // the code here, can we get in a situation where we are trying // to draw without a font? if (station_font != NULL) { XFreeFont(XtDisplay(da), station_font); } // Load the new font from the FONT_STATION string station_font = (XFontStruct *)XLoadQueryFont(XtDisplay(da), rotated_label_fontname[FONT_STATION]); if (station_font == NULL) // Couldn't get the font!!! { char tempy[100]; fprintf(stderr,"Map_font_change_data: Couldn't load station font %s. ", rotated_label_fontname[FONT_STATION]); fprintf(stderr,"Loading default station font instead.\n"); strcpy(tempy, "Couldn't get font "); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, rotated_label_fontname[FONT_STATION]); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, ". Loading default font instead."); tempy[sizeof(tempy)-1] = '\0'; // Terminate string popup_message_always(langcode("POPEM00035"), tempy); station_font = (XFontStruct *)XLoadQueryFont(XtDisplay(da), "fixed"); if (station_font == NULL) // Couldn't get the font!!! { fprintf(stderr,"Map_font_change_data: Couldn't load default station font.\n"); popup_message_always(langcode("POPEM00035"), "Couldn't load default station font."); } } // Assign the font to the GC. if (station_font != NULL) { XSetFont(XtDisplay(da), gc, station_font->fid); } } // chose map label font void Map_font_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; xfontsel_query = 0; XtPopdown(shell); XtDestroyWidget(shell); map_font_dialog = (Widget)NULL; } // Function called by UpdateTime when xfontsel_query is non-zero. // Checks the pipe to see if xfontsel has sent anything to us yet. // If we get anything from the read, we should wait a small amount // of time and try another read, to make sure we don't get a partial // read the first time and quit. // void Query_xfontsel_pipe (void) { char xfontsel_font[FONT_MAX][sizeof(rotated_label_fontname[0])]; struct timeval tmv; fd_set rd; int retval; int fd; int i; for (i = 0; i < FONT_MAX; i++) { // if (fgets(xfontsel_font,sizeof(xfontsel_font),f_xfontsel_pipe)) { // Find out the file descriptor associated with our pipe. if (!f_xfontsel_pipe[i]) { continue; } fd = fileno(f_xfontsel_pipe[i]); FD_ZERO(&rd); FD_SET(fd, &rd); tmv.tv_sec = 0; tmv.tv_usec = 1; // 1 usec // Do a non-blocking check of the read end of the pipe. retval = select(fd+1,&rd,NULL,NULL,&tmv); //fprintf(stderr,"1\n"); if (retval) { int l = strlen(xfontsel_font[i]); // We have something to process. Wait a bit, then snag the // data. usleep(250000); // 250ms if (fgets(xfontsel_font[i],sizeof(xfontsel_font[0]),f_xfontsel_pipe[i]) == NULL) { // We hit end-of-file or there's an error reading // Do nothing here, which was the standard operation // prior to adding the check for the return value. } if (xfontsel_font[i][l-1] == '\n') { xfontsel_font[i][l-1] = '\0'; } if (map_font_text[i] != NULL) { XmTextSetString(map_font_text[i], xfontsel_font[i]); } pclose(f_xfontsel_pipe[i]); f_xfontsel_pipe[i] = 0; //fprintf(stderr,"Resetting xfontset_query\n"); xfontsel_query = 0; } else { // Read nothing. Let UpdateTime run this function again // shortly. } } } void Map_font_xfontsel(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { #if defined(HAVE_XFONTSEL) int fontsize = XTPOINTER_TO_INT(clientData); char xfontsel[70]; /* invoke xfontsel -print and stick into map_font_text */ sprintf(xfontsel, "%s -print -title \"xfontsel %d\"", XFONTSEL_PATH, fontsize); if ((f_xfontsel_pipe[fontsize] = popen(xfontsel,"r"))) { // Request UpdateTime to keep checking the pipe periodically // using non-blocking reads. //fprintf(stderr,"Setting xfontsel_query\n"); xfontsel_query++; } else { perror("xfontsel"); } #endif // HAVE_XFONTSEL } void Map_font_change_data(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp; Widget shell = (Widget) clientData; int i; xfontsel_query = 0; for (i = 0; i < FONT_MAX; i++) { temp = XmTextGetString(map_font_text[i]); xastir_snprintf(rotated_label_fontname[i], sizeof(rotated_label_fontname[i]), "%s", temp); XtFree(temp); XmTextSetString(map_font_text[i], rotated_label_fontname[i]); } // Load a new font into the GC for the station font Load_station_font(); // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; XtPopdown(shell); XtDestroyWidget(shell); map_font_dialog = (Widget)NULL; } void Map_font(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, fontname[FONT_MAX], button_ok, button_cancel,button_xfontsel[FONT_MAX]; Atom delw; int i; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if (!map_font_dialog) { map_font_dialog = XtVaCreatePopupShell(langcode("MAPFONT002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Choose map labels font", xmPanedWindowWidgetClass, map_font_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Map font my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // ac=0; // XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; // XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; for (i = 0; i < FONT_MAX; i++) { char *fonttitle[FONT_MAX] = {"MAPFONT009","MAPFONT010","MAPFONT003", "MAPFONT004","MAPFONT005","MAPFONT006", "MAPFONT007","MAPFONT008","MAPFONT011" }; ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, fontname[i-1]); ac++; } XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNwidth, 150); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNforeground,colors[0x08]); ac++; XtSetArg(al[ac], XmNbackground,colors[0xff]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; fontname[i] = XtCreateManagedWidget(langcode(fonttitle[i]), xmLabelWidgetClass, my_form, al, ac); ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, map_font_text[i-1]); ac++; } XtSetArg(al[ac], XmNeditable, TRUE); ac++; XtSetArg(al[ac], XmNcursorPositionVisible, TRUE); ac++; XtSetArg(al[ac], XmNsensitive, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 1); ac++; XtSetArg(al[ac], XmNcolumns, 60); ac++; XtSetArg(al[ac], XmNwidth, (60*7)+2); ac++; XtSetArg(al[ac], XmNmaxLength, 128); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNbottomAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNleftWidget, fontname[i]); ac++; XtSetArg(al[ac], XmNleftOffset, 10); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNrightAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_font_text[i] = XtCreateManagedWidget("Map font text", xmTextFieldWidgetClass, my_form, al, ac); XmTextSetString(map_font_text[i], rotated_label_fontname[i]); // Xfontsel ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, button_xfontsel[i-1]); ac++; } XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNleftWidget, map_font_text[i]); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 10); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNforeground,colors[0x08]); ac++; XtSetArg(al[ac], XmNbackground,colors[0xff]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; button_xfontsel[i] = XtCreateManagedWidget(langcode("PULDNMP015"), xmPushButtonGadgetClass, my_form, al,ac); #if defined(HAVE_XFONTSEL) XtSetSensitive(button_xfontsel[i],TRUE); #else // HAVE_FONTSEL XtSetSensitive(button_xfontsel[i],FALSE); #endif // HAVE_FONTSEL XtAddCallback(button_xfontsel[i], XmNactivateCallback, Map_font_xfontsel, INT_TO_XTPOINTER(i) ); } button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_font_text[FONT_MAX-1], XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_font_text[FONT_MAX-1], XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Map_font_change_data, map_font_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Map_font_destroy_shell, map_font_dialog); pos_dialog(map_font_dialog); delw = XmInternAtom(XtDisplay(map_font_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_font_dialog, delw, Map_font_destroy_shell, (XtPointer)map_font_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, map_font_dialog); XtPopup(map_font_dialog, XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_font_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_font_dialog), XtWindow(map_font_dialog)); } } // Used by view_gps_status() function below. We must either expire // this data or associate a time with it on the display. char gps_status_save[100]; time_t gps_status_save_time = 0; char *report_gps_status(void) { static char gps_temp[100]; char temp2[20]; switch (gps_valid) { case 8: // Simulation Mode xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS008") ); // "Simulation" break; case 7: // Manual Input Mode xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS009") ); // "Manual" break; case 6: // Estimated Fix (dead reckoning) xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS010") ); // "Estimated" break; case 5: // Float RTK xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS011") ); // "Float RTK" break; case 4: // RTK xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS012") ); // "RTK" break; case 3: // WAAS or PPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS001") ); // "WAAS or PPS" break; case 2: // DGPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS002") ); // "DGPS" break; case 1: // Valid SPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS003") ); // "Valid SPS" break; case 0: // Invalid default: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS004") ); // "Invalid" break; } xastir_snprintf(gps_temp, sizeof(gps_temp), "%s:%s %s:%s", langcode("GPSS005"), // "Sats/View" gps_sats, langcode("GPSS006"), // "Fix" temp2); // Save it in global variable in case we request status via the // menus. xastir_snprintf(gps_status_save, sizeof(gps_status_save), "%s", gps_temp); gps_status_save_time = sec_now(); // Reset the variables. xastir_snprintf(gps_sats, sizeof(gps_sats), "00"); gps_valid = 0; return(gps_temp); } void view_gps_status(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // GPS status data too old? if ((gps_status_save_time + 30) >= sec_now()) { // Nope, within 30 seconds popup_message_always(langcode("PULDNVI015"), gps_status_save); } else { // Yes, GPS status data is old popup_message_always(langcode("PULDNVI015"), langcode("GPSS007") ); // "!GPS data is older than 30 seconds!" } } void Compute_Uptime(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp[200]; unsigned long runtime; int days, hours, minutes, seconds; char Days[6]; char Hours[7]; char Minutes[9]; char Seconds[9]; runtime = sec_now() - program_start_time; days = runtime / 86400; runtime = runtime - (days * 86400); hours = runtime / 3600; runtime = runtime - (hours * 3600); minutes = runtime / 60; seconds = runtime - (minutes * 60); if (days == 1) { xastir_snprintf(Days,sizeof(Days),"%s",langcode("TIME001")); // Day } else { xastir_snprintf(Days,sizeof(Days),"%s",langcode("TIME002")); // Days } if (hours == 1) { xastir_snprintf(Hours,sizeof(Hours),"%s",langcode("TIME003")); // Hour } else { xastir_snprintf(Hours,sizeof(Hours),"%s",langcode("TIME004")); // Hours } if (minutes == 1) { xastir_snprintf(Minutes,sizeof(Minutes),"%s",langcode("TIME005")); // Minute } else { xastir_snprintf(Minutes,sizeof(Minutes),"%s",langcode("TIME006")); // Minutes } if (seconds == 1) { xastir_snprintf(Seconds,sizeof(Seconds),"%s",langcode("TIME007")); // Second } else { xastir_snprintf(Seconds,sizeof(Seconds),"%s",langcode("TIME008")); // Seconds } if (days != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s, %d %s, %d %s", days, Days, hours, Hours, minutes, Minutes, seconds, Seconds); } else if (hours != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s, %d %s", hours, Hours, minutes, Minutes, seconds, Seconds); } else if (minutes != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s", minutes, Minutes, seconds, Seconds); } else { xastir_snprintf(temp, sizeof(temp), "%d %s", seconds, Seconds); } popup_message_always(langcode("PULDNVI014"),temp); } void Mouse_button_handler (Widget UNUSED(w), Widget UNUSED(popup), XButtonEvent *event, Boolean * UNUSED(dispatch) ) { // Snag the current pointer position input_x = event->x; input_y = event->y; if (event->type == ButtonPress) { //fprintf(stderr,"Mouse_button_handler, button pressed %d\n", event->button); } if (event->type == ButtonRelease) { //fprintf(stderr,"Mouse_button_handler, button released %d\n", event->button); return; } #ifdef SWAP_MOUSE_BUTTONS if (event->button != Button1) { //fprintf(stderr,"Pressed a mouse button, but not Button1: %x\n",event->button); #else // SWAP_MOUSE_BUTTONS if (event->button != Button3) { //fprintf(stderr,"Pressed a mouse button, but not Button3: %x\n",event->button); #endif // SWAP_MOUSE_BUTTONS return; } // Right mouse button press menu_x=input_x; menu_y=input_y; if (right_menu_popup != NULL) // If popup menu defined { #ifdef SWAP_MOUSE_BUTTONS // This gets the menus out of the way that are on pointer // button1 if SWAP_MOUSE_BUTTONS is enabled. If it's not // enabled, they don't interfere with each other anyway. if (!measuring_distance && !moving_object) { #else // SWAP_MOUSE_BUTTONS if (1) // Always bring up the menu if SWAP is disabled { #endif // SWAP_MOUSE_BUTTONS // Bring up the popup menu XmMenuPosition(right_menu_popup,(XButtonPressedEvent *)event); XtManageChild(right_menu_popup); // Check whether any modifiers are pressed. // If so, pop up a warning message. if ( (event->state != 0) && warn_about_mouse_modifiers) { popup_message_always(langcode("POPUPMA023"),langcode("POPUPMA024")); } } } } void menu_link_for_mouse_menu(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (right_menu_popup!=NULL) { //XmMenuPosition(right_menu_popup,(XButtonPressedEvent *)event); XtManageChild(right_menu_popup); } } void store_all_kml_callback(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { export_trail_as_kml(NULL); last_kmlsnapshot = sec_now(); } void KML_Snapshots_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // Whether we're setting or unsetting it, set the timer such // that a snapshot will occur immediately once the button is set // again. last_kmlsnapshot = 0; if(state->set) { kmlsnapshots_enabled = atoi(which); } else { kmlsnapshots_enabled = 0; } } void Snapshots_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // Whether we're setting or unsetting it, set the timer such // that a snapshot will occur immediately once the button is set // again. last_snapshot = 0; if(state->set) { snapshots_enabled = atoi(which); } else { snapshots_enabled = 0; } } static inline int no_data_selected(void) { return ( Select_.none || ( !Select_.mine && !Select_.net && ( !Select_.tnc || ( !Select_.direct && !Select_.via_digi ) ) ) ); } #ifdef ARROWS Widget pan_up_menu, pan_down_menu, pan_left_menu, pan_right_menu, zoom_in_menu, zoom_out_menu; #endif // ARROWS void create_appshell( Display *display, char * UNUSED(app_name), int UNUSED(app_argc), char ** UNUSED(app_argv) ) { Pixmap icon_pixmap; Atom WM_DELETE_WINDOW; Widget children[9]; /* Children to manage */ Arg al[100]; /* Arg List */ register unsigned int ac; /* Arg Count */ /*popup menu widgets */ Widget zoom_in, zoom_out, zoom_sub, zl1, zl2, zl3, zl4, zl5, zl6, zl7, zl8, zl9, zlC; // Widget zoom_level; // Widget sar_object_menu; Widget CAD_sub, CAD1, CAD3, CAD4; Widget pan_sub; // Widget pan_menu; Widget move_my_sub; // Widget move_my_menu; Widget pan_ctr, last_loc, station_info, send_message_to; Widget set_object, modify_object; Widget setmyposition, pan_up, pan_down, pan_left, pan_right; /*menu widgets */ Widget sep; Widget filepane, configpane, mappane, viewpane, stationspane, messagepane, ifacepane, helppane, filter_data_pane, filter_display_pane, map_config_pane, station_config_pane, help_emergency_pane; // Widget exitpane, // help_emergency_button, // display_button, // file_button, // view_button, // config_button, // map_button, // map_background_button, // map_config_button, // station_config_button, // raster_intensity_button, // map_station_label_button, // map_icon_outline_button, // iface_button, // message_button, // filter_data_button, // filter_display_button, // draw_CAD_objects_menu, // store_data_button; Widget track_button, download_trail_button, station_clear_button, tracks_clear_button, object_history_refresh_button, object_history_clear_button, tactical_clear_button, tactical_history_clear_button, uptime_button, aloha_button, save_button, open_file_button, exit_button, view_messages_button, gps_status_button, bullet_button, packet_data_button, mobile_button, stations_button, localstations_button, laststations_button, objectstations_button, objectmystations_button, weather_button, wx_station_button, locate_button, geocode_place_button, locate_place_button, jump_button, jump_button2, alert_button, defaults_button, timing_button, coordinates_button, station_button, map_lock_pan_zoom_button, map_disable_button, map_auto_button, map_chooser_button, map_grid_button, map_levels_button, map_labels_button, map_fill_button, coordinate_calculator_button, center_zoom_button, Map_background_color_Pane, map_pointer_menu_button, cad_draw_button, cad_show_label_button, cad_show_probability_button, cad_show_area_button, cad_show_comment_button, #if !defined(NO_GRAPHICS) Raster_intensity_Pane, #if defined(HAVE_MAGICK) gamma_adjust_button, #endif // HAVE_MAGICK #ifdef HAVE_LIBGEOTIFF drg_config_button, #endif // HAVE_LIBGEOTIFF #endif // NO_GRAPHICS font_button, Map_station_label_Pane, Map_icon_outline_Pane, map_wx_alerts_button, index_maps_on_startup_button, redownload_maps_button, flush_map_cache_button, units_choice_button, dbstatus_choice_button, iface_connect_button, tnc_logging, transmit_disable_toggle, net_logging, igate_logging, wx_logging, message_logging, wx_alert_logging, enable_snapshots, print_button, test_button, debug_level_button, aa_button, speech_button, smart_beacon_button, map_indexer_button, map_all_indexer_button, auto_msg_set_button, send_message_to_button, show_pending_messages_button, enable_kmlsnapshots, open_messages_group_button, clear_messages_button, General_q_button, IGate_q_button, WX_q_button, store_data_pane, store_all_kml_button, #ifdef HAVE_DB store_all_db_button, #endif // HAVE_DB help_button, help_about, help_help; char *title, *t; int t_size; // XWMHints *wm_hints; // Used for window manager hints Dimension my_appshell_width, my_appshell_height; Dimension da_width, da_height; static XmFontListEntry font_entry; if(debug_level & 8) { fprintf(stderr,"Create appshell start\n"); } /* wm_hints = XAllocWMHints(); if (!wm_hints) { fprintf(stderr,"Failure allocating memory: wm_hints\n"); exit(0); } // Set up the wm_hints struct wm_hints->initial_state = NormalState; wm_hints->input = True; wm_hints->flags = StateHint | InputHint; */ t = "X Amateur Station Tracking and Information Reporting"; title = (char *)malloc(t_size = (strlen(t) + 42 + strlen(xastir_package))); if (!title) { fprintf(stderr,"Couldn't allocate memory for title\n"); } else { xastir_snprintf(title, t_size, "XASTIR"); strncat(title, " - ", t_size - 1 - strlen(title)); strncat(title, t, t_size - 1 - strlen(title)); strncat(title, " @ ", t_size - 1 - strlen(title)); (void)gethostname(&title[strlen(title)], 28); } // Allocate a couple of colors that we'll need before we get // around to calling create_gc(), which creates the rest. // colors[0x08] = GetPixelByName(appshell,"black"); colors[0x0c] = GetPixelByName(appshell,"red"); colors[0xff] = GetPixelByName(appshell,"gray73"); ac = 0; // Snag border widths so that we can use them in the calculations // below. If we fail to do this the size and offsets will be off by // the width of the borders added by the window manager. // // if (XGetGeometry(XtDisplay(da), // XtWindow(appshell), // &root_return, // &x_return, // &y_return, // &width_return, // &height_return, // &border_width_return, // &depth_return) ) == False) { // fprintf(stderr,"Couldn't get window attributes\n"); // } // // Another method: // // XWindowAttributes windowattr; // Defined in Xlib.h // Struct has x/y/width/height/border_width/depth fields. // if (XGetWindowAttributes(display,XtWindow(appshell),&windowattr) == 0) { // fprintf(stderr,"Couldn't get window attributes\n") // } // Set up the main window X/Y sizes and the minimum sizes // allowable. // if ( (WidthValue|HeightValue) & geometry_flags ) { // // Size of Xastir was specified with a -geometry setting. // Set up the window size. // my_appshell_width = (Dimension)geometry_width; // Used in offset equations below my_appshell_height = (Dimension)geometry_height; // Used in offset equations below //fprintf(stderr,"gW:%d gH:%d\n", geometry_width, geometry_height); //fprintf(stderr,"tW:%d tH:%d\n", (int)my_appshell_width, (int)my_appshell_height); if (my_appshell_width < 61) { my_appshell_width = 61; } if (my_appshell_height < 61) { my_appshell_height = 61; } //fprintf(stderr,"tW:%d tH:%d\n", (int)my_appshell_width, (int)my_appshell_height); XtSetArg(al[ac], XmNwidth, my_appshell_width); ac++; XtSetArg(al[ac], XmNheight, my_appshell_height); ac++; // XtSetArg(al[ac], XmNminWidth, 61); ac++; // XtSetArg(al[ac], XmNminHeight, 61); ac++; // Lock the min size to the specified initial size for now, release // later after creating initial window. Snagged this idea from the // Lincity project where they do similar things in "lcx11.c" // XtSetArg(al[ac], XmNminWidth, my_appshell_width); ac++; // XtSetArg(al[ac], XmNminHeight, my_appshell_height); ac++; } else { // Size was NOT specified in a -geometry string. Set to the // size specified in the config file instead. // my_appshell_width = (Dimension)screen_width; my_appshell_height = (Dimension)(screen_height + 60); XtSetArg(al[ac], XmNwidth, my_appshell_width); ac++; XtSetArg(al[ac], XmNheight, my_appshell_height); ac++; // XtSetArg(al[ac], XmNminWidth, 61); ac++; // XtSetArg(al[ac], XmNminHeight, 61); ac++; // Lock the min size to the specified initial size for now, release // later after creating initial window. Got this idea from the // Lincity project where they do the similar things in "lcx11.c" // XtSetArg(al[ac], XmNminWidth, my_appshell_width); ac++; // XtSetArg(al[ac], XmNminHeight, my_appshell_height); ac++; } // Set up default font font1 = XLoadQueryFont(display, rotated_label_fontname[FONT_SYSTEM]); if (font1 == NULL) // Couldn't get the font!!! { fprintf(stderr,"create_appshell: Couldn't load system font %s. ", rotated_label_fontname[FONT_SYSTEM]); fprintf(stderr,"Loading default system font instead.\n"); font1 = XLoadQueryFont(display, "fixed"); if (font1 == NULL) // Couldn't get the font!!! { fprintf(stderr,"create_appshell: Couldn't load default system font, exiting.\n"); exit(1); } else { // _Now_ we can do a popup message about the first error // as we have a font to work with! char tempy[100]; strcpy(tempy, "Couldn't get font "); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, rotated_label_fontname[FONT_SYSTEM]); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, ". Loading default font instead."); tempy[sizeof(tempy)-1] = '\0'; // Terminate string popup_message_always(langcode("POPEM00035"), tempy); } } font_entry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT, font1); fontlist1 = XmFontListAppendEntry(NULL, font_entry); XmFontListEntryFree(&font_entry); XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Set up the X/Y offsets for the main window // if ( (XValue|YValue) & geometry_flags ) { Position my_x, my_y; // // Position of Xastir was specified with a -geometry setting. // if (XNegative & geometry_flags) { geometry_x = DisplayWidth(display, DefaultScreen(display) ) + geometry_x - (int)my_appshell_width; } if (YNegative & geometry_flags) { geometry_y = DisplayHeight(display, DefaultScreen(display) ) + geometry_y - (int)my_appshell_height; } my_x = (Position)geometry_x; my_y = (Position)geometry_y; XtSetArg(al[ac], XmNx, my_x); ac++; XtSetArg(al[ac], XmNy, my_y); ac++; } else { // // Position of Xastir was not specified. Use the values // from the config file // /* // This doesn't position the widget in fvwm2. Would hate to go back // to XSizeHints in order to make this work. fprintf(stderr,"Setting up widget's X/Y position at X:%d Y:%d\n", (int)screen_x_offset, (int)screen_y_offset); XtSetArg(al[ac], XmNx, screen_x_offset); ac++; // Doesn't work here XtSetArg(al[ac], XmNy, screen_y_offset); ac++; // Doesn't work here */ } XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++; if (title) { XtSetArg(al[ac], XmNtitle, title); } ac++; XtSetArg(al[ac], XmNdefaultPosition, FALSE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; // // Set the above values into the appshell widget // XtSetValues(appshell, al, ac); // Make at least one Motif call so that the next function won't // result in this problem: 'Error: atttempt to add non-widget // child "DropSiteManager" to parent "xastir"'. // (void) XmIsMotifWMRunning(appshell); form = XtVaCreateWidget("create_appshell form", xmFormWidgetClass, appshell, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Menu Bar */ ac = 0; XtSetArg(al[ac], XmNshadowThickness, 1); ac++; XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNbottomAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; menubar = XmCreateMenuBar(form, "create_appshell menubar", al, ac); /*set args for color */ ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; /* menu bar */ filepane = XmCreatePulldownMenu(menubar,"filepane", al, ac); viewpane = XmCreatePulldownMenu(menubar,"viewpane", al, ac); mappane = XmCreatePulldownMenu(menubar,"mappane", al, ac); stationspane= XmCreatePulldownMenu(menubar,"stationspane",al, ac); messagepane = XmCreatePulldownMenu(menubar,"messagepane", al, ac); ifacepane = XmCreatePulldownMenu(menubar,"ifacepane", al, ac); helppane = XmCreatePulldownMenu(menubar,"helppane", al, ac); //file_button XtVaCreateManagedWidget(langcode("MENUTB0001"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId, filepane, XmNmnemonic,langcode_hotkey("MENUTB0001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //view_button XtVaCreateManagedWidget(langcode("MENUTB0002"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,viewpane, XmNmnemonic,langcode_hotkey("MENUTB0002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //map_button XtVaCreateManagedWidget(langcode("MENUTB0004"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,mappane, XmNmnemonic,langcode_hotkey("MENUTB0004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //display_button XtVaCreateManagedWidget(langcode("MENUTB0005"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,stationspane, XmNmnemonic,langcode_hotkey("MENUTB0005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //message_button XtVaCreateManagedWidget(langcode("MENUTB0006"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,messagepane, XmNmnemonic,langcode_hotkey("MENUTB0006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //iface_button XtVaCreateManagedWidget(langcode("MENUTB0010"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,ifacepane, XmNmnemonic,langcode_hotkey("MENUTB0010"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); help_button = XtVaCreateManagedWidget(langcode("MENUTB0009"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,helppane, XmNmnemonic,langcode_hotkey("MENUTB0009"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtVaSetValues (menubar,XmNmenuHelpWidget,help_button,NULL); /* end bar */ /* File */ ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; configpane = XmCreatePulldownMenu(filepane, "configpane", al, ac); // Print button print_button = XtVaCreateManagedWidget(langcode("PULDNFI015"), xmPushButtonWidgetClass, filepane, XmNmnemonic, langcode_hotkey("PULDNFI015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback( print_button, XmNactivateCallback, Print_Postscript, NULL ); //config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, filepane, XmNsubMenuId,configpane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); open_file_button = XtVaCreateManagedWidget(langcode("PULDNFI002"), xmPushButtonGadgetClass, filepane, XmNmnemonic,langcode_hotkey("PULDNFI002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); tnc_logging = XtVaCreateManagedWidget(langcode("PULDNFI010"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(tnc_logging,XmNvalueChangedCallback,TNC_Logging_toggle,"1"); if (log_tnc_data) { XmToggleButtonSetState(tnc_logging,TRUE,FALSE); } net_logging = XtVaCreateManagedWidget(langcode("PULDNFI011"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(net_logging,XmNvalueChangedCallback,Net_Logging_toggle,"1"); if (log_net_data) { XmToggleButtonSetState(net_logging,TRUE,FALSE); } igate_logging = XtVaCreateManagedWidget(langcode("PULDNFI012"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(igate_logging,XmNvalueChangedCallback,IGate_Logging_toggle,"1"); if (log_igate) { XmToggleButtonSetState(igate_logging,TRUE,FALSE); } // message_logging = XtVaCreateManagedWidget(langcode("PULDNFI012"), message_logging = XtVaCreateManagedWidget("Message Logging", xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(message_logging,XmNvalueChangedCallback,Message_Logging_toggle,"1"); if (log_message_data) { XmToggleButtonSetState(message_logging,TRUE,FALSE); } wx_logging = XtVaCreateManagedWidget(langcode("PULDNFI013"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(wx_logging,XmNvalueChangedCallback,WX_Logging_toggle,"1"); if (log_wx) { XmToggleButtonSetState(wx_logging,TRUE,FALSE); } // wx_alert_logging = XtVaCreateManagedWidget(langcode("PULDNFI013"), wx_alert_logging = XtVaCreateManagedWidget("WX Alert Logging", xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(wx_alert_logging,XmNvalueChangedCallback,WX_Alert_Logging_toggle,"1"); if (log_wx_alert_data) { XmToggleButtonSetState(wx_alert_logging,TRUE,FALSE); } enable_snapshots = XtVaCreateManagedWidget(langcode("PULDNFI014"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(enable_snapshots,XmNvalueChangedCallback,Snapshots_toggle,"1"); if (snapshots_enabled) { XmToggleButtonSetState(enable_snapshots,TRUE,FALSE); } // enable kml snapshots enable_kmlsnapshots = XtVaCreateManagedWidget(langcode("PULDNFI016"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(enable_kmlsnapshots,XmNvalueChangedCallback,KML_Snapshots_toggle,"1"); if (kmlsnapshots_enabled) { XmToggleButtonSetState(enable_kmlsnapshots,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep1a", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1b", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //exitpane XmCreatePulldownMenu(filepane, "exitpane", al, ac); exit_button = XtVaCreateManagedWidget(langcode("PULDNFI004"), xmPushButtonWidgetClass, filepane, XmNmnemonic,langcode_hotkey("PULDNFI004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* View */ packet_data_button = XtVaCreateManagedWidget(langcode("PULDNVI002"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); view_messages_button = XtVaCreateManagedWidget(langcode("PULDNVI011"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI011"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); bullet_button = XtVaCreateManagedWidget(langcode("PULDNVI001"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); mobile_button = XtVaCreateManagedWidget(langcode("PULDNVI003"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); stations_button = XtVaCreateManagedWidget(langcode("PULDNVI004"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); localstations_button = XtVaCreateManagedWidget(langcode("PULDNVI009"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI009"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); laststations_button = XtVaCreateManagedWidget(langcode("PULDNVI012"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI012"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); objectstations_button = XtVaCreateManagedWidget(langcode("LHPUPNI005"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("LHPUPNI005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); objectmystations_button = XtVaCreateManagedWidget(langcode("LHPUPNI006"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("LHPUPNI006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "List All CAD Polygons" CAD1 = XtVaCreateManagedWidget(langcode("POPUPMA046"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("POPUPMA046"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); weather_button = XtVaCreateManagedWidget(langcode("PULDNVI005"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); wx_station_button = XtVaCreateManagedWidget(langcode("PULDNVI008"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); alert_button = XtVaCreateManagedWidget(langcode("PULDNVI007"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep3?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gps_status_button = XtVaCreateManagedWidget(langcode("PULDNVI015"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); uptime_button = XtVaCreateManagedWidget(langcode("PULDNVI013"), xmPushButtonWidgetClass, viewpane, XmNmnemonic, langcode_hotkey("PULDNVI013"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); aloha_button = XtVaCreateManagedWidget(langcode("PULDNVI016"), xmPushButtonWidgetClass, viewpane, XmNmnemonic, langcode_hotkey("PULDNVI016"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Configure */ station_button = XtVaCreateManagedWidget(langcode("PULDNCF004"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); defaults_button = XtVaCreateManagedWidget(langcode("PULDNCF001"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); timing_button = XtVaCreateManagedWidget(langcode("PULDNCF003"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); coordinates_button = XtVaCreateManagedWidget(langcode("PULDNCF002"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); aa_button = XtVaCreateManagedWidget(langcode("PULDNCF006"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); speech_button = XtVaCreateManagedWidget(langcode("PULDNCF007"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); smart_beacon_button = XtVaCreateManagedWidget(langcode("SMARTB001"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("SMARTB001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // map label font select font_button = XtVaCreateManagedWidget(langcode("PULDNMP025"), xmPushButtonWidgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNMP025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(font_button, XmNactivateCallback, Map_font, NULL); test_button = XtVaCreateManagedWidget(langcode("PULDNFI003"), xmPushButtonWidgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNFI003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); debug_level_button = XtVaCreateManagedWidget(langcode("PULDNFI007"), xmPushButtonWidgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNFI007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); units_choice_button = XtVaCreateManagedWidget(langcode("PULDNUT001"), xmToggleButtonGadgetClass, configpane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(units_choice_button,XmNvalueChangedCallback,Units_choice_toggle,"1"); if (english_units) { XmToggleButtonSetState(units_choice_button,TRUE,FALSE); } dbstatus_choice_button = XtVaCreateManagedWidget(langcode("PULDNDB001"), xmToggleButtonGadgetClass, configpane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(dbstatus_choice_button,XmNvalueChangedCallback,Dbstatus_choice_toggle,"1"); if (do_dbstatus) { XmToggleButtonSetState(dbstatus_choice_button,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep1d", xmSeparatorGadgetClass, configpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); save_button = XtVaCreateManagedWidget(langcode("PULDNCF008"), xmPushButtonGadgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNCF008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //- Maps ------------------------------------------------------------- map_chooser_button = XtVaCreateManagedWidget(langcode("PULDNMP001"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_chooser_button, XmNactivateCallback,Map_chooser,NULL); // Map Display Bookmarks jump_button = XtVaCreateManagedWidget(langcode("PULDNMP012"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP012"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); locate_place_button = XtVaCreateManagedWidget(langcode("PULDNMP014"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP014"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); geocode_place_button = XtVaCreateManagedWidget(langcode("PULDNMP029"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP029"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); coordinate_calculator_button = XtVaCreateManagedWidget(langcode("COORD001"), xmPushButtonGadgetClass,mappane, XmNmnemonic, langcode_hotkey("COORD001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); center_zoom_button=XtVaCreateManagedWidget(langcode("POPUPMA026"), xmPushButtonGadgetClass, mappane, XmNmnemonic, langcode_hotkey("POPUPMA026"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(center_zoom_button,XmNactivateCallback,Center_Zoom,NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; CAD_sub=XmCreatePulldownMenu(mappane, "create_appshell CAD sub", al, ac); // "Draw CAD Objects" //draw_CAD_objects_menu XtVaCreateManagedWidget(langcode("POPUPMA029"), xmCascadeButtonGadgetClass, mappane, XmNsubMenuId,CAD_sub, // XmNmnemonic,langcode_hotkey("POPUPMA029"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Draw Mode" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA031")); ac++; // "Close Polygon" CAD_close_polygon_menu_item=XtCreateManagedWidget(langcode("POPUPMA031"), xmPushButtonGadgetClass, CAD_sub, al, ac); XtAddCallback(CAD_close_polygon_menu_item,XmNactivateCallback,Draw_CAD_Objects_close_polygon,NULL); // disable the close polygon menu item if not in draw mode if (draw_CAD_objects_flag==1) { XtSetSensitive(CAD_close_polygon_menu_item,TRUE); } if (draw_CAD_objects_flag==0) { XtSetSensitive(CAD_close_polygon_menu_item,FALSE); } ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; // XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA032")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "Erase CAD Polygons" CAD3=XtCreateManagedWidget(langcode("POPUPMA032"), xmPushButtonGadgetClass, CAD_sub, al, ac); XtAddCallback(CAD3,XmNactivateCallback,Draw_CAD_Objects_erase_dialog,NULL); // "List All CAD Polygons" CAD4 = XtVaCreateManagedWidget(langcode("POPUPMA046"), xmPushButtonGadgetClass, CAD_sub, XmNmnemonic,langcode_hotkey("POPUPMA046"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(CAD4,XmNactivateCallback,Draw_CAD_Objects_list_dialog,NULL); // Toggles for CAD object information display on map // Draw CAD Objects cad_draw_button = XtVaCreateManagedWidget(langcode("POPUPMA047"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_draw_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_draw_objects"); if (CAD_draw_objects==TRUE) { XmToggleButtonSetState(cad_draw_button,TRUE,FALSE); } // Draw CAD Labels cad_show_label_button = XtVaCreateManagedWidget(langcode("POPUPMA048"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_label_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_label"); if (CAD_show_label==TRUE) { XmToggleButtonSetState(cad_show_label_button,TRUE,FALSE); } // Draw CAD Probability cad_show_probability_button = XtVaCreateManagedWidget(langcode("POPUPMA050"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_probability_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_raw_probability"); if (CAD_show_raw_probability==TRUE) { XmToggleButtonSetState(cad_show_probability_button,TRUE,FALSE); } // Draw CAD Comments cad_show_comment_button = XtVaCreateManagedWidget(langcode("POPUPMA049"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_comment_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_comment"); if (CAD_show_comment==TRUE) { XmToggleButtonSetState(cad_show_comment_button,TRUE,FALSE); } // Draw CAD Size of Area cad_show_area_button = XtVaCreateManagedWidget(langcode("POPUPMA051"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_area_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_area"); if (CAD_show_area==TRUE) { XmToggleButtonSetState(cad_show_area_button,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep2", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_lock_pan_zoom_button = XtVaCreateManagedWidget(langcode("PULDNMP016"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_lock_pan_zoom_button, XmNvalueChangedCallback, Map_lock_pan_zoom_toggle, "1"); if (map_lock_pan_zoom) { XmToggleButtonSetState(map_lock_pan_zoom_button, TRUE, FALSE); } map_disable_button = XtVaCreateManagedWidget(langcode("PULDNMP013"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_disable_button, XmNvalueChangedCallback, Map_disable_toggle, "1"); if (disable_all_maps) { XmToggleButtonSetState(map_disable_button, TRUE, FALSE); } map_auto_button = XtVaCreateManagedWidget(langcode("PULDNMP002"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_auto_button,XmNvalueChangedCallback,Map_auto_toggle,"1"); if (map_auto_maps) { XmToggleButtonSetState(map_auto_button,TRUE,FALSE); } map_auto_skip_raster_button = XtVaCreateManagedWidget(langcode("PULDNMP021"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_auto_skip_raster_button,XmNvalueChangedCallback,Map_auto_skip_raster_toggle,"1"); if (auto_maps_skip_raster) { XmToggleButtonSetState(map_auto_skip_raster_button,TRUE,FALSE); } if (!map_auto_maps) { XtSetSensitive(map_auto_skip_raster_button,FALSE); } map_grid_button = XtVaCreateManagedWidget(langcode("PULDNMP003"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_grid_button,XmNvalueChangedCallback,Grid_toggle,"1"); if (long_lat_grid) { XmToggleButtonSetState(map_grid_button,TRUE,FALSE); } // Enable Map Border map_border_button = XtVaCreateManagedWidget(langcode("PULDNMP031"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_border_button,XmNvalueChangedCallback,Map_border_toggle,"1"); if (draw_labeled_grid_border) { XmToggleButtonSetState(map_border_button,TRUE,FALSE); } if (!long_lat_grid) { XtSetSensitive(map_border_button,FALSE); } else { XtSetSensitive(map_border_button,TRUE); } map_levels_button = XtVaCreateManagedWidget(langcode("PULDNMP004"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_levels_button,XmNvalueChangedCallback,Map_levels_toggle,"1"); if (map_color_levels) { XmToggleButtonSetState(map_levels_button,TRUE,FALSE); } map_labels_button = XtVaCreateManagedWidget(langcode("PULDNMP010"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_labels_button,XmNvalueChangedCallback,Map_labels_toggle,"1"); if (map_labels) { XmToggleButtonSetState(map_labels_button,TRUE,FALSE); } map_fill_button = XtVaCreateManagedWidget(langcode("PULDNMP009"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_fill_button,XmNvalueChangedCallback,Map_fill_toggle,"1"); if (map_color_fill) { XmToggleButtonSetState(map_fill_button,TRUE,FALSE); } map_wx_alerts_button = XtVaCreateManagedWidget(langcode("PULDNMP007"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_wx_alerts_button,XmNvalueChangedCallback,Map_wx_alerts_toggle,"1"); if (!wx_alert_style) { XmToggleButtonSetState(map_wx_alerts_button,TRUE,FALSE); } #ifndef HAVE_LIBSHP // If we don't have Shapelib compiled in, grey-out the weather // alerts button. XtSetSensitive(map_wx_alerts_button, FALSE); #endif // HAVE_LIBSHP (void)XtVaCreateManagedWidget("create_appshell sep2b", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2c", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_config_pane = XmCreatePulldownMenu(mappane, "map_config_pane", al, ac); //map_config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, mappane, XmNsubMenuId,map_config_pane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // These go into the map config submenu Map_background_color_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_background_color", al, ac); //map_background_button XtVaCreateManagedWidget(langcode("PULDNMP005"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_background_color_Pane, XmNmnemonic, langcode_hotkey("PULDNMP005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[10] = XtVaCreateManagedWidget(langcode("PULDNMBC11"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC11"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[11] = XtVaCreateManagedWidget(langcode("PULDNMBC12"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC12"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[0] = XtVaCreateManagedWidget(langcode("PULDNMBC01"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[1] = XtVaCreateManagedWidget(langcode("PULDNMBC02"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[2] = XtVaCreateManagedWidget(langcode("PULDNMBC03"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[3] = XtVaCreateManagedWidget(langcode("PULDNMBC04"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[4] = XtVaCreateManagedWidget(langcode("PULDNMBC05"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC05"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[5] = XtVaCreateManagedWidget(langcode("PULDNMBC06"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC06"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[6] = XtVaCreateManagedWidget(langcode("PULDNMBC07"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC07"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[7] = XtVaCreateManagedWidget(langcode("PULDNMBC08"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC08"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[8] = XtVaCreateManagedWidget(langcode("PULDNMBC09"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC09"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[9] = XtVaCreateManagedWidget(langcode("PULDNMBC10"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC10"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtSetSensitive(map_bgcolor[map_background_color],FALSE); XtAddCallback(map_bgcolor[10], XmNactivateCallback,Map_background,"10"); XtAddCallback(map_bgcolor[11], XmNactivateCallback,Map_background,"11"); XtAddCallback(map_bgcolor[0], XmNactivateCallback,Map_background,"0"); XtAddCallback(map_bgcolor[1], XmNactivateCallback,Map_background,"1"); XtAddCallback(map_bgcolor[2], XmNactivateCallback,Map_background,"2"); XtAddCallback(map_bgcolor[3], XmNactivateCallback,Map_background,"3"); XtAddCallback(map_bgcolor[4], XmNactivateCallback,Map_background,"4"); XtAddCallback(map_bgcolor[5], XmNactivateCallback,Map_background,"5"); XtAddCallback(map_bgcolor[6], XmNactivateCallback,Map_background,"6"); XtAddCallback(map_bgcolor[7], XmNactivateCallback,Map_background,"7"); XtAddCallback(map_bgcolor[8], XmNactivateCallback,Map_background,"8"); XtAddCallback(map_bgcolor[9], XmNactivateCallback,Map_background,"9"); #if !defined(NO_GRAPHICS) ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Raster_intensity_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell raster_intensity", al, ac); //raster_intensity_button XtVaCreateManagedWidget(langcode("PULDNMP008"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Raster_intensity_Pane, XmNmnemonic, langcode_hotkey("PULDNMP008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[0] = XtVaCreateManagedWidget("0%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"0%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[1] = XtVaCreateManagedWidget("10%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"10%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[2] = XtVaCreateManagedWidget("20%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"20%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[3] = XtVaCreateManagedWidget("30%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"30%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[4] = XtVaCreateManagedWidget("40%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"40%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[5] = XtVaCreateManagedWidget("50%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"50%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[6] = XtVaCreateManagedWidget("60%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"60%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[7] = XtVaCreateManagedWidget("70%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"70%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[8] = XtVaCreateManagedWidget("80%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"80%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[9] = XtVaCreateManagedWidget("90%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"90%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[10] = XtVaCreateManagedWidget("100%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"100%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtSetSensitive(raster_intensity[(int)(raster_map_intensity * 10.0)],FALSE); //fprintf(stderr,"raster index = %d\n", // (int)(raster_map_intensity * 10.01) ); XtAddCallback(raster_intensity[0], XmNactivateCallback,Raster_intensity,"0.0"); XtAddCallback(raster_intensity[1], XmNactivateCallback,Raster_intensity,"0.1"); XtAddCallback(raster_intensity[2], XmNactivateCallback,Raster_intensity,"0.2"); XtAddCallback(raster_intensity[3], XmNactivateCallback,Raster_intensity,"0.3"); XtAddCallback(raster_intensity[4], XmNactivateCallback,Raster_intensity,"0.4"); XtAddCallback(raster_intensity[5], XmNactivateCallback,Raster_intensity,"0.5"); XtAddCallback(raster_intensity[6], XmNactivateCallback,Raster_intensity,"0.6"); XtAddCallback(raster_intensity[7], XmNactivateCallback,Raster_intensity,"0.7"); XtAddCallback(raster_intensity[8], XmNactivateCallback,Raster_intensity,"0.8"); XtAddCallback(raster_intensity[9], XmNactivateCallback,Raster_intensity,"0.9"); XtAddCallback(raster_intensity[10], XmNactivateCallback,Raster_intensity,"1.0"); #if defined(HAVE_MAGICK) // Adjust Gamma Correction gamma_adjust_button = XtVaCreateManagedWidget(langcode("GAMMA001"), xmPushButtonWidgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("GAMMA001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(gamma_adjust_button, XmNactivateCallback, Gamma_adjust, NULL); #endif // HAVE_MAGICK #endif // NO_GRAPHICS ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Map_station_label_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_station_label", al, ac); //map_station_label_button XtVaCreateManagedWidget(langcode("PULDNMP006"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMP006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label0 = XtVaCreateManagedWidget(langcode("PULDNMSL01"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label1 = XtVaCreateManagedWidget(langcode("PULDNMSL02"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label2 = XtVaCreateManagedWidget(langcode("PULDNMSL03"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label3 = XtVaCreateManagedWidget(langcode("PULDNMSL04"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); sel4_switch(letter_style,map_station_label3,map_station_label2,map_station_label1,map_station_label0); XtAddCallback(map_station_label0, XmNactivateCallback,Map_station_label,"0"); XtAddCallback(map_station_label1, XmNactivateCallback,Map_station_label,"1"); XtAddCallback(map_station_label2, XmNactivateCallback,Map_station_label,"2"); XtAddCallback(map_station_label3, XmNactivateCallback,Map_station_label,"3"); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Map_icon_outline_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_icon_outline", al, ac); //map_icon_outline_button XtVaCreateManagedWidget(langcode("PULDNMP026"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMP026"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline0 = XtVaCreateManagedWidget(langcode("PULDNMIO01"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline1 = XtVaCreateManagedWidget(langcode("PULDNMIO02"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline2 = XtVaCreateManagedWidget(langcode("PULDNMIO03"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline3 = XtVaCreateManagedWidget(langcode("PULDNMIO04"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); sel4_switch(icon_outline_style,map_icon_outline3,map_icon_outline2,map_icon_outline1,map_icon_outline0); XtAddCallback(map_icon_outline0, XmNactivateCallback,Map_icon_outline,"0"); XtAddCallback(map_icon_outline1, XmNactivateCallback,Map_icon_outline,"1"); XtAddCallback(map_icon_outline2, XmNactivateCallback,Map_icon_outline,"2"); XtAddCallback(map_icon_outline3, XmNactivateCallback,Map_icon_outline,"3"); #ifdef HAVE_LIBGEOTIFF drg_config_button= XtVaCreateManagedWidget(langcode("PULDNMP030"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP030"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(drg_config_button, XmNactivateCallback,Config_DRG,NULL); #endif // HAVE_LIBGEOTIFF (void)XtVaCreateManagedWidget("create_appshell sep2d", xmSeparatorGadgetClass, map_config_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Re-download Maps (Not from cache) redownload_maps_button = XtVaCreateManagedWidget(langcode("PULDNMP027"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP027"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(redownload_maps_button, XmNactivateCallback,Re_Download_Maps_Now,NULL); // Flush Entire Map Cache! flush_map_cache_button = XtVaCreateManagedWidget(langcode("PULDNMP028"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP028"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(flush_map_cache_button, XmNactivateCallback,Flush_Entire_Map_Queue,NULL); //Index Maps on startup index_maps_on_startup_button = XtVaCreateManagedWidget(langcode("PULDNMP022"), xmToggleButtonGadgetClass, map_config_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(index_maps_on_startup_button,XmNvalueChangedCallback,Index_maps_on_startup_toggle,"1"); if (index_maps_on_startup) { XmToggleButtonSetState(index_maps_on_startup_button,TRUE,FALSE); } map_indexer_button = XtVaCreateManagedWidget(langcode("PULDNMP023"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP023"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_all_indexer_button = XtVaCreateManagedWidget(langcode("PULDNMP024"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP024"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2e", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_pointer_menu_button = XtVaCreateManagedWidget(langcode("PULDNMP011"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP011"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //- Stations Menu ----------------------------------------------------- locate_button = XtVaCreateManagedWidget(langcode("PULDNDP014"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP014"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); track_button = XtVaCreateManagedWidget(langcode("PULDNDP001"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(track_button, XmNactivateCallback,Track_station,NULL); download_trail_button = XtVaCreateManagedWidget(langcode("PULDNDP022"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP022"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(download_trail_button, XmNactivateCallback,Download_findu_trail,NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Store Data pulldown/tearoff store_data_pane = XmCreatePulldownMenu(stationspane, "store_data_pane", al, ac); // Export all > //store_data_button XtVaCreateManagedWidget(langcode("PULDNDP055"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, store_data_pane, XmNmnemonic, langcode_hotkey("PULDNDP055"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Export to KML file store_all_kml_button = XtVaCreateManagedWidget(langcode("PULDNDP056"), xmPushButtonGadgetClass, store_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(store_all_kml_button, XmNactivateCallback, store_all_kml_callback, NULL); #ifdef HAVE_DB // store to open databases store_all_db_button = XtVaCreateManagedWidget("Store to open databases", xmPushButtonGadgetClass, store_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //XtAddCallback(store_all_db_button, XmNvalueChangedCallback, store_all_db_button_callback, "1"); XtSetSensitive(store_all_db_button,FALSE); #endif // HAVE_DB (void)XtVaCreateManagedWidget("create_appshell sep3", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Filter Data pulldown/tearoff filter_data_pane = XmCreatePulldownMenu(stationspane, "filter_data_pane", al, ac); //filter_data_button XtVaCreateManagedWidget(langcode("PULDNDP032"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, filter_data_pane, XmNmnemonic, langcode_hotkey("PULDNDP032"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); select_none_button = XtVaCreateManagedWidget(langcode("PULDNDP040"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_none_button, XmNvalueChangedCallback, Select_none_toggle, "1"); if (Select_.none) { XmToggleButtonSetState(select_none_button, TRUE, FALSE); } select_mine_button = XtVaCreateManagedWidget(langcode("PULDNDP041"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_mine_button, XmNvalueChangedCallback, Select_mine_toggle, "1"); if (Select_.mine) { XmToggleButtonSetState(select_mine_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_mine_button, FALSE); } select_tnc_button = XtVaCreateManagedWidget(langcode("PULDNDP042"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_tnc_button, XmNvalueChangedCallback, Select_tnc_toggle, "1"); if (Select_.tnc) { XmToggleButtonSetState(select_tnc_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_tnc_button, FALSE); } select_direct_button = XtVaCreateManagedWidget(langcode("PULDNDP027"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_direct_button, XmNvalueChangedCallback, Select_direct_toggle, "1"); if (Select_.direct) { XmToggleButtonSetState(select_direct_button, TRUE, FALSE); } if (!Select_.tnc || Select_.none) { XtSetSensitive(select_direct_button, FALSE); } select_via_digi_button = XtVaCreateManagedWidget(langcode("PULDNDP043"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_via_digi_button, XmNvalueChangedCallback, Select_via_digi_toggle, "1"); if (Select_.via_digi) { XmToggleButtonSetState(select_via_digi_button, TRUE, FALSE); } if (!Select_.tnc || Select_.none) { XtSetSensitive(select_via_digi_button, FALSE); } select_net_button = XtVaCreateManagedWidget(langcode("PULDNDP034"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_net_button, XmNvalueChangedCallback, Select_net_toggle, "1"); if (Select_.net) { XmToggleButtonSetState(select_net_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_net_button, FALSE); } // "Select Tactical Calls Only" select_tactical_button = XtVaCreateManagedWidget(langcode("PULDNDP051"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_tactical_button, XmNvalueChangedCallback, Select_tactical_toggle, "1"); if (Select_.tactical) { XmToggleButtonSetState(select_tactical_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_tactical_button, FALSE); } select_old_data_button = XtVaCreateManagedWidget(langcode("PULDNDP019"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_old_data_button, XmNvalueChangedCallback, Select_old_data_toggle, "1"); if (Select_.old_data) { XmToggleButtonSetState(select_old_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3a", xmSeparatorGadgetClass, filter_data_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); select_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP044"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_stations_button, XmNvalueChangedCallback, Select_stations_toggle, "1"); if (Select_.stations) { XmToggleButtonSetState(select_stations_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_stations_button, FALSE); } select_fixed_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP028"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_fixed_stations_button, XmNvalueChangedCallback, Select_fixed_stations_toggle, "1"); if (Select_.fixed_stations) { XmToggleButtonSetState(select_fixed_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_fixed_stations_button, FALSE); } select_moving_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP029"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_moving_stations_button, XmNvalueChangedCallback, Select_moving_stations_toggle, "1"); if (Select_.moving_stations) { XmToggleButtonSetState(select_moving_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_moving_stations_button, FALSE); } select_weather_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP030"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_weather_stations_button, XmNvalueChangedCallback, Select_weather_stations_toggle, "1"); if (Select_.weather_stations) { XmToggleButtonSetState(select_weather_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_weather_stations_button, FALSE); } select_CWOP_wx_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP053"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_CWOP_wx_stations_button, XmNvalueChangedCallback, Select_CWOP_wx_stations_toggle, "1"); if (Select_.CWOP_wx_stations) { XmToggleButtonSetState(select_CWOP_wx_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected() || !Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } else { XtSetSensitive(select_CWOP_wx_stations_button, TRUE); } select_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP045"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_objects_button, XmNvalueChangedCallback, Select_objects_toggle, "1"); if (Select_.objects) { XmToggleButtonSetState(select_objects_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_objects_button, FALSE); } select_weather_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP026"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_weather_objects_button, XmNvalueChangedCallback, Select_weather_objects_toggle, "1"); if (Select_.weather_objects) { XmToggleButtonSetState(select_weather_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_weather_objects_button, FALSE); } select_gauge_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP039"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_gauge_objects_button, XmNvalueChangedCallback, Select_gauge_objects_toggle, "1"); if (Select_.gauge_objects) { XmToggleButtonSetState(select_gauge_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_gauge_objects_button, FALSE); } select_aircraft_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP057"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_aircraft_objects_button, XmNvalueChangedCallback, Select_aircraft_objects_toggle, "1"); if (Select_.aircraft_objects) { XmToggleButtonSetState(select_aircraft_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_aircraft_objects_button, FALSE); } select_vessel_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP058"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_vessel_objects_button, XmNvalueChangedCallback, Select_vessel_objects_toggle, "1"); if (Select_.vessel_objects) { XmToggleButtonSetState(select_vessel_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_vessel_objects_button, FALSE); } select_other_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP031"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_other_objects_button, XmNvalueChangedCallback, Select_other_objects_toggle, "1"); if (Select_.other_objects) { XmToggleButtonSetState(select_other_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_other_objects_button, FALSE); } // End of Data Filtering ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Displayed Info Filtering filter_display_pane = XmCreatePulldownMenu(stationspane, "filter_display_pane", al, ac); //filter_display_button XtVaCreateManagedWidget(langcode("PULDNDP033"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, filter_display_pane, XmNmnemonic, langcode_hotkey("PULDNDP033"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_callsign_button = XtVaCreateManagedWidget(langcode("PULDNDP010"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_callsign_button, XmNvalueChangedCallback, Display_callsign_toggle, "1"); if (Display_.callsign) { XmToggleButtonSetState(display_callsign_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_callsign_button, FALSE); } display_label_all_trackpoints_button = XtVaCreateManagedWidget(langcode("PULDNDP052"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_label_all_trackpoints_button, XmNvalueChangedCallback, Display_label_all_trackpoints_toggle, "1"); if (Display_.label_all_trackpoints) { XmToggleButtonSetState(display_label_all_trackpoints_button, TRUE, FALSE); } if (!Display_.callsign || no_data_selected()) { XtSetSensitive(display_label_all_trackpoints_button, FALSE); } display_symbol_button = XtVaCreateManagedWidget(langcode("PULDNDP012"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_symbol_button, XmNvalueChangedCallback, Display_symbol_toggle, "1"); if (Display_.symbol) { XmToggleButtonSetState(display_symbol_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_symbol_button, FALSE); } display_symbol_rotate_button = XtVaCreateManagedWidget(langcode("PULDNDP011"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_symbol_rotate_button, XmNvalueChangedCallback, Display_symbol_rotate_toggle, "1"); if (Display_.symbol_rotate) { XmToggleButtonSetState(display_symbol_rotate_button, TRUE, FALSE); } if (!Display_.symbol || no_data_selected()) { XtSetSensitive(display_symbol_rotate_button, FALSE); } display_trail_button = XtVaCreateManagedWidget(langcode("PULDNDP007"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_trail_button, XmNvalueChangedCallback, Display_trail_toggle, "1"); if (Display_.trail) { XmToggleButtonSetState(display_trail_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_trail_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3b", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_course_button = XtVaCreateManagedWidget(langcode("PULDNDP003"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_course_button, XmNvalueChangedCallback, Display_course_toggle, "1"); if (Display_.course) { XmToggleButtonSetState(display_course_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_course_button, FALSE); } display_speed_button = XtVaCreateManagedWidget(langcode("PULDNDP004"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_speed_button, XmNvalueChangedCallback, Display_speed_toggle, "1"); if (Display_.speed) { XmToggleButtonSetState(display_speed_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_speed_button, FALSE); } display_speed_short_button = XtVaCreateManagedWidget(langcode("PULDNDP017"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_speed_short_button, XmNvalueChangedCallback, Display_speed_short_toggle, "1"); if (Display_.speed_short) { XmToggleButtonSetState(display_speed_short_button, TRUE, FALSE); } if (!Display_.speed || no_data_selected()) { XtSetSensitive(display_speed_short_button, FALSE); } display_altitude_button = XtVaCreateManagedWidget(langcode("PULDNDP002"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_altitude_button, XmNvalueChangedCallback, Display_altitude_toggle, "1"); if (Display_.altitude) { XmToggleButtonSetState(display_altitude_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_altitude_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3c", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_weather_button = XtVaCreateManagedWidget(langcode("PULDNDP009"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_weather_button, XmNvalueChangedCallback, Display_weather_toggle, "1"); if (Display_.weather) { XmToggleButtonSetState(display_weather_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_weather_button, FALSE); } display_weather_text_button = XtVaCreateManagedWidget(langcode("PULDNDP046"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_weather_text_button, XmNvalueChangedCallback, Display_weather_text_toggle, "1"); if (Display_.weather_text) { XmToggleButtonSetState(display_weather_text_button, TRUE, FALSE); } if (!Display_.weather || no_data_selected()) { XtSetSensitive(display_weather_text_button, FALSE); } display_temperature_only_button = XtVaCreateManagedWidget(langcode("PULDNDP018"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_temperature_only_button, XmNvalueChangedCallback, Display_temperature_only_toggle, "1"); if (Display_.temperature_only) { XmToggleButtonSetState(display_temperature_only_button, TRUE, FALSE); } if (!Display_.weather || !Display_.weather_text || no_data_selected()) { XtSetSensitive(display_temperature_only_button, FALSE); } display_wind_barb_button = XtVaCreateManagedWidget(langcode("PULDNDP047"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_wind_barb_button, XmNvalueChangedCallback, Display_wind_barb_toggle, "1"); if (Display_.wind_barb) { XmToggleButtonSetState(display_wind_barb_button, TRUE, FALSE); } if (!Display_.weather || no_data_selected()) { XtSetSensitive(display_wind_barb_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3d", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_aloha_circle_button = XtVaCreateManagedWidget(langcode("PULDNDP054"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_aloha_circle_button, XmNvalueChangedCallback, Display_aloha_circle_toggle, "1"); if (Display_.aloha_circle) { XmToggleButtonSetState(display_aloha_circle_button, TRUE, FALSE); } display_ambiguity_button = XtVaCreateManagedWidget(langcode("PULDNDP013"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_ambiguity_button, XmNvalueChangedCallback, Display_ambiguity_toggle, "1"); if (Display_.ambiguity) { XmToggleButtonSetState(display_ambiguity_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_ambiguity_button, FALSE); } display_phg_button = XtVaCreateManagedWidget(langcode("PULDNDP008"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_phg_button, XmNvalueChangedCallback, Display_phg_toggle, "1"); if (Display_.phg) { XmToggleButtonSetState(display_phg_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_phg_button, FALSE); } display_default_phg_button = XtVaCreateManagedWidget(langcode("PULDNDP021"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_default_phg_button, XmNvalueChangedCallback, Display_default_phg_toggle, "1"); if (Display_.default_phg) { XmToggleButtonSetState(display_default_phg_button, TRUE, FALSE); } if (!Display_.phg || no_data_selected()) { XtSetSensitive(display_default_phg_button, FALSE); } display_phg_of_moving_button = XtVaCreateManagedWidget(langcode("PULDNDP020"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_phg_of_moving_button, XmNvalueChangedCallback, Display_phg_of_moving_toggle, "1"); if (Display_.phg_of_moving) { XmToggleButtonSetState(display_phg_of_moving_button, TRUE, FALSE); } if (!Display_.phg || no_data_selected()) { XtSetSensitive(display_phg_of_moving_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3e", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_df_data_button = XtVaCreateManagedWidget(langcode("PULDNDP023"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_data_button, XmNvalueChangedCallback, Display_df_data_toggle, "1"); if (Display_.df_data) { XmToggleButtonSetState(display_df_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_df_data_button, FALSE); } display_df_beamwidth_data_button = XtVaCreateManagedWidget(langcode("PULDNDP123"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_beamwidth_data_button, XmNvalueChangedCallback, Display_df_beamwidth_data_toggle, "1"); if (Display_.df_beamwidth_data) { XmToggleButtonSetState(display_df_beamwidth_data_button, TRUE, FALSE); } if (!Display_.df_data || no_data_selected()) { XtSetSensitive(display_df_beamwidth_data_button, FALSE); } display_df_bearing_data_button = XtVaCreateManagedWidget(langcode("PULDNDP223"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_bearing_data_button, XmNvalueChangedCallback, Display_df_bearing_data_toggle, "1"); if (Display_.df_bearing_data) { XmToggleButtonSetState(display_df_bearing_data_button, TRUE, FALSE); } if (!Display_.df_data || no_data_selected()) { XtSetSensitive(display_df_bearing_data_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3e", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_dr_data_button = XtVaCreateManagedWidget(langcode("PULDNDP035"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_data_button, XmNvalueChangedCallback, Display_dr_data_toggle, "1"); if (Display_.dr_data) { XmToggleButtonSetState(display_dr_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_dr_data_button, FALSE); } display_dr_arc_button = XtVaCreateManagedWidget(langcode("PULDNDP036"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_arc_button, XmNvalueChangedCallback, Display_dr_arc_toggle, "1"); if (Display_.dr_arc) { XmToggleButtonSetState(display_dr_arc_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_arc_button, FALSE); } display_dr_course_button = XtVaCreateManagedWidget(langcode("PULDNDP037"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_course_button, XmNvalueChangedCallback, Display_dr_course_toggle, "1"); if (Display_.dr_course) { XmToggleButtonSetState(display_dr_course_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_course_button, FALSE); } display_dr_symbol_button = XtVaCreateManagedWidget(langcode("PULDNDP038"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_symbol_button, XmNvalueChangedCallback, Display_dr_symbol_toggle, "1"); if (Display_.dr_symbol) { XmToggleButtonSetState(display_dr_symbol_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_symbol_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3f", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_dist_bearing_button = XtVaCreateManagedWidget(langcode("PULDNDP005"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dist_bearing_button, XmNvalueChangedCallback, Display_dist_bearing_toggle, "1"); if (Display_.dist_bearing) { XmToggleButtonSetState(display_dist_bearing_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_dist_bearing_button, FALSE); } display_last_heard_button = XtVaCreateManagedWidget(langcode("PULDNDP024"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_last_heard_button, XmNvalueChangedCallback, Display_last_heard_toggle, "1"); if (Display_.last_heard) { XmToggleButtonSetState(display_last_heard_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_last_heard_button, FALSE); } // End of Displayed Info Filtering (void)XtVaCreateManagedWidget("create_appshell sep3g", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep3h", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_config_pane = XmCreatePulldownMenu(stationspane, "stations_config_pane", al, ac); //station_config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId,station_config_pane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); object_history_refresh_button = XtVaCreateManagedWidget(langcode("PULDNDP048"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP048"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); object_history_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP025"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Clear All Tactical Calls" tactical_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP049"), xmPushButtonGadgetClass, station_config_pane, // XmNmnemonic,langcode_hotkey("PULDNDP049"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Clear Tactical Call History" tactical_history_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP050"), xmPushButtonGadgetClass, station_config_pane, // XmNmnemonic,langcode_hotkey("PULDNDP050"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); tracks_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP016"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP016"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); station_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP015"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //-------------------------------------------------------------------- /* Messages */ send_message_to_button = XtVaCreateManagedWidget(langcode("PULDNMG001"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); show_pending_messages_button = XtVaCreateManagedWidget(langcode("PULDNMG007"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); open_messages_group_button = XtVaCreateManagedWidget(langcode("PULDNMG002"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); clear_messages_button= XtVaCreateManagedWidget(langcode("PULDNMG003"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep4", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); General_q_button = XtVaCreateManagedWidget(langcode("PULDQUS001"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); IGate_q_button = XtVaCreateManagedWidget(langcode("PULDQUS002"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); WX_q_button = XtVaCreateManagedWidget(langcode("PULDQUS003"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep4a", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); auto_msg_set_button = XtVaCreateManagedWidget(langcode("PULDNMG004"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); auto_msg_toggle = XtVaCreateManagedWidget(langcode("PULDNMG005"), xmToggleButtonGadgetClass, messagepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(auto_msg_toggle,XmNvalueChangedCallback,Auto_msg_toggle,"1"); (void)XtVaCreateManagedWidget("create_appshell sep5", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); satellite_msg_ack_toggle = XtVaCreateManagedWidget(langcode("PULDNMG006"), xmToggleButtonGadgetClass, messagepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(satellite_msg_ack_toggle,XmNvalueChangedCallback,Satellite_msg_ack_toggle,"1"); /* Interface */ iface_connect_button = XtVaCreateManagedWidget(langcode("PULDNTNT04"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep5a", xmSeparatorGadgetClass, ifacepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); transmit_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT03"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(transmit_disable_toggle,XmNvalueChangedCallback,Transmit_disable_toggle,"1"); if (transmit_disable) { XmToggleButtonSetState(transmit_disable_toggle,TRUE,FALSE); } posit_tx_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT05"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(posit_tx_disable_toggle,XmNvalueChangedCallback,Posit_tx_disable_toggle,"1"); if (posit_tx_disable) { XmToggleButtonSetState(posit_tx_disable_toggle,TRUE,FALSE); } if (transmit_disable) { XtSetSensitive(posit_tx_disable_toggle,FALSE); } object_tx_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT06"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(object_tx_disable_toggle,XmNvalueChangedCallback,Object_tx_disable_toggle,"1"); if (object_tx_disable) { XmToggleButtonSetState(object_tx_disable_toggle,TRUE,FALSE); } if (transmit_disable) { XtSetSensitive(object_tx_disable_toggle,FALSE); } server_port_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT11"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(server_port_toggle,XmNvalueChangedCallback,Server_port_toggle,"1"); if (enable_server_port) { XmToggleButtonSetState(server_port_toggle,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep5b", xmSeparatorGadgetClass, ifacepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); iface_transmit_now = XtVaCreateManagedWidget(langcode("PULDNTNT01"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); if (transmit_disable) { XtSetSensitive(iface_transmit_now,FALSE); } #ifdef HAVE_GPSMAN Fetch_gps_track = XtVaCreateManagedWidget(langcode("PULDNTNT07"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT07"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Fetch_gps_route = XtVaCreateManagedWidget(langcode("PULDNTNT08"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT08"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Fetch_gps_waypoints = XtVaCreateManagedWidget(langcode("PULDNTNT09"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT09"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Send_gps_track = XtVaCreateManagedWidget(langcode("Send_Tr"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Tr"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Send_gps_route = XtVaCreateManagedWidget(langcode("Send_Rt"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Rt"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Send_gps_waypoints = XtVaCreateManagedWidget(langcode("Send_Wp"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Wp"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); */ Fetch_RINO_waypoints = XtVaCreateManagedWidget(langcode("PULDNTNT10"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT10"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #endif // HAVE_GPSMAN /* Help*/ help_about = XtVaCreateManagedWidget(langcode("PULDNHEL01"), xmPushButtonGadgetClass, helppane, XmNmnemonic,langcode_hotkey("PULDNHEL01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); help_help = XtVaCreateManagedWidget(langcode("PULDNHEL02"), xmPushButtonGadgetClass, helppane, XmNmnemonic,langcode_hotkey("PULDNHEL02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sephelp", xmSeparatorGadgetClass, helppane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; help_emergency_pane = XmCreatePulldownMenu(helppane, "help_emergency_pane", al, ac); //help_emergency_button XtVaCreateManagedWidget(langcode("PULDNHEL03"), xmCascadeButtonGadgetClass, helppane, XmNsubMenuId,help_emergency_pane, XmNmnemonic,langcode_hotkey("PULDNHEL03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); emergency_beacon_toggle = XtVaCreateManagedWidget(langcode("PULDNHEL04"), xmToggleButtonGadgetClass, help_emergency_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(emergency_beacon_toggle,XmNvalueChangedCallback,Emergency_beacon_toggle,"1"); if (emergency_beacon) { XmToggleButtonSetState(emergency_beacon_toggle,TRUE,FALSE); } /* view */ XtAddCallback(stations_button, XmNactivateCallback,Station_List,"0"); XtAddCallback(mobile_button, XmNactivateCallback,Station_List,"1"); XtAddCallback(weather_button, XmNactivateCallback,Station_List,"2"); XtAddCallback(localstations_button, XmNactivateCallback,Station_List,"3"); XtAddCallback(laststations_button, XmNactivateCallback,Station_List,"4"); XtAddCallback(objectstations_button,XmNactivateCallback,Station_List,"5"); XtAddCallback(objectmystations_button,XmNactivateCallback,Station_List,"6"); XtAddCallback(CAD1,XmNactivateCallback,Draw_CAD_Objects_list_dialog,NULL); /* button callbacks */ XtAddCallback(General_q_button, XmNactivateCallback,General_query,""); XtAddCallback(IGate_q_button, XmNactivateCallback,IGate_query,NULL); XtAddCallback(WX_q_button, XmNactivateCallback,WX_query,NULL); XtAddCallback(station_clear_button, XmNactivateCallback,Stations_Clear,NULL); XtAddCallback(tracks_clear_button, XmNactivateCallback,Tracks_All_Clear,NULL); XtAddCallback(object_history_refresh_button, XmNactivateCallback,Object_History_Refresh,NULL); XtAddCallback(object_history_clear_button, XmNactivateCallback,Object_History_Clear,NULL); XtAddCallback(tactical_clear_button, XmNactivateCallback,Tactical_Callsign_Clear,NULL); XtAddCallback(tactical_history_clear_button, XmNactivateCallback,Tactical_Callsign_History_Clear,NULL); XtAddCallback(exit_button, XmNactivateCallback,Menu_Quit,NULL); XtAddCallback(defaults_button, XmNactivateCallback,Configure_defaults,NULL); XtAddCallback(timing_button, XmNactivateCallback,Configure_timing,NULL); XtAddCallback(coordinates_button, XmNactivateCallback,Configure_coordinates,NULL); XtAddCallback(aa_button, XmNactivateCallback,Configure_audio_alarms,NULL); XtAddCallback(speech_button, XmNactivateCallback,Configure_speech,NULL); XtAddCallback(smart_beacon_button, XmNactivateCallback,Smart_Beacon,NULL); XtAddCallback(map_indexer_button, XmNactivateCallback,Index_Maps_Now,NULL); XtAddCallback(map_all_indexer_button,XmNactivateCallback,Index_Maps_Now,"1"); XtAddCallback(station_button, XmNactivateCallback,Configure_station,NULL); XtAddCallback(help_about, XmNactivateCallback,Help_About,NULL); XtAddCallback(help_help, XmNactivateCallback,Help_Index,NULL); /* TNC */ XtAddCallback(iface_transmit_now, XmNactivateCallback,TNC_Transmit_now,NULL); #ifdef HAVE_GPSMAN XtAddCallback(Fetch_gps_track, XmNactivateCallback,GPS_operations,"1"); XtAddCallback(Fetch_gps_route, XmNactivateCallback,GPS_operations,"2"); XtAddCallback(Fetch_gps_waypoints, XmNactivateCallback,GPS_operations,"3"); // XtAddCallback(Send_gps_track, XmNactivateCallback,GPS_operations,"4"); // XtAddCallback(Send_gps_route, XmNactivateCallback,GPS_operations,"5"); // XtAddCallback(Send_gps_waypoints, XmNactivateCallback,GPS_operations,"6"); XtAddCallback(Fetch_RINO_waypoints, XmNactivateCallback,GPS_operations,"7"); #endif // HAVE_GPSMAN XtAddCallback(auto_msg_set_button,XmNactivateCallback,Auto_msg_set,NULL); XtAddCallback(iface_connect_button, XmNactivateCallback,control_interface,NULL); XtAddCallback(open_file_button, XmNactivateCallback,Read_File_Selection,NULL); XtAddCallback(bullet_button, XmNactivateCallback,Bulletins,NULL); XtAddCallback(packet_data_button, XmNactivateCallback,Display_data,NULL); XtAddCallback(locate_button, XmNactivateCallback,Locate_station,NULL); XtAddCallback(alert_button, XmNactivateCallback,Display_Wx_Alert,NULL); XtAddCallback(view_messages_button, XmNactivateCallback,view_all_messages,NULL); XtAddCallback(gps_status_button,XmNactivateCallback,view_gps_status,NULL); XtAddCallback(map_pointer_menu_button, XmNactivateCallback,menu_link_for_mouse_menu,NULL); XtAddCallback(wx_station_button, XmNactivateCallback,WX_station,NULL); XtAddCallback(jump_button, XmNactivateCallback, Jump_location, NULL); XtAddCallback(locate_place_button, XmNactivateCallback,Locate_place,NULL); XtAddCallback(geocode_place_button, XmNactivateCallback,Geocoder_place,NULL); XtAddCallback(coordinate_calculator_button, XmNactivateCallback,Coordinate_calc,""); XtAddCallback(send_message_to_button, XmNactivateCallback,Send_message,NULL); XtAddCallback(show_pending_messages_button, XmNactivateCallback,Show_pending_messages,NULL); XtAddCallback(open_messages_group_button, XmNactivateCallback,Send_message,"*"); XtAddCallback(clear_messages_button,XmNactivateCallback,Clear_messages,NULL); XtAddCallback(save_button, XmNactivateCallback,Save_Config,NULL); XtAddCallback(test_button, XmNactivateCallback,Test,NULL); if (!debug_level) { XtSetSensitive(test_button, False); } XtAddCallback(debug_level_button, XmNactivateCallback, Change_Debug_Level,NULL); // XtSetSensitive(debug_level_button, False); XtAddCallback(uptime_button, XmNactivateCallback, Compute_Uptime,NULL); XtAddCallback(aloha_button, XmNactivateCallback, Show_Aloha_Stats,NULL); //XtSetSensitive(uptime_button, False); // Toolbar toolbar = XtVaCreateWidget("Toolbar form", xmFormWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, menubar, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); trackme_button=XtVaCreateManagedWidget(langcode("POPUPMA022"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, -5, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(trackme_button,XmNvalueChangedCallback,Track_Me,"1"); measure_button=XtVaCreateManagedWidget(langcode("POPUPMA020"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trackme_button, XmNtopOffset, -7, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, -5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(measure_button,XmNvalueChangedCallback,Measure_Distance,"1"); cad_draw_button=XtVaCreateManagedWidget(langcode("POPUPMA030"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, -5, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, trackme_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_draw_button,XmNvalueChangedCallback,Draw_CAD_Objects_mode,NULL); move_button=XtVaCreateManagedWidget(langcode("POPUPMA021"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_draw_button, XmNtopOffset, -7, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, -5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, trackme_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(move_button,XmNvalueChangedCallback,Move_Object,"1"); #ifdef ARROWS zoom_in_menu=XtVaCreateManagedWidget(langcode("POPUPMA002"), xmPushButtonWidgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_draw_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(zoom_in_menu,XmNactivateCallback,Zoom_in_no_pan,NULL); if (map_lock_pan_zoom) { XtSetSensitive(zoom_in_menu, FALSE); } zoom_out_menu=XtVaCreateManagedWidget(langcode("POPUPMA003"), xmPushButtonWidgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_in_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(zoom_out_menu,XmNactivateCallback,Zoom_out_no_pan,NULL); if (map_lock_pan_zoom) { XtSetSensitive(zoom_out_menu, FALSE); } pan_left_menu=XtVaCreateManagedWidget("create_appshell arrow1_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_out_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_LEFT, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_left_menu,XmNactivateCallback,Pan_left,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_left_menu, FALSE); } pan_up_menu=XtVaCreateManagedWidget("create_appshell arrow2_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_left_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_UP, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_up_menu,XmNactivateCallback,Pan_up,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_up_menu, FALSE); } pan_down_menu=XtVaCreateManagedWidget("create_appshell arrow3_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_up_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_DOWN, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_down_menu,XmNactivateCallback,Pan_down,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_down_menu, FALSE); } pan_right_menu=XtVaCreateManagedWidget("create_appshell arrow4_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_down_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_RIGHT, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_right_menu,XmNactivateCallback,Pan_right,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_right_menu, FALSE); } #endif // ARROWS #define FONT_WIDTH 9 // Create bottom text area // #ifdef USE_TWO_STATUS_LINES // Quantity of stations box, Bottom left corner text3 = XtVaCreateWidget("create_appshell text_output3", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 14, XmNwidth, ((22*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom level box, Bottom second from left text4 = XtVaCreateWidget("create_appshell text_output4", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((15*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Log indicator box, Bottom second from right log_indicator = XtVaCreateWidget(langcode("BBARSTA043"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*FONT_WIDTH)), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text4, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interface status indicators, Bottom right corner iface_da = XtVaCreateWidget("create_appshell iface", xmDrawingAreaWidgetClass, form, XmNwidth, 22*(MAX_IFACE_DEVICES/2), XmNheight, 20, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, log_indicator, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Message box, on Top left text = XtVaCreateWidget("create_appshell text_output", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 30, XmNwidth, ((29*FONT_WIDTH)+2), XmNtopOffset, 4, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text3, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Coordinate display box, Top right text2 = XtVaCreateWidget("create_appshell text_output2", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 35, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text3, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #else // Message box, on left text = XtVaCreateWidget("create_appshell text_output", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 30, XmNwidth, ((29*FONT_WIDTH)+2), XmNtopOffset, 4, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Coordinate display box, 2nd from left text2 = XtVaCreateWidget("create_appshell text_output2", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 35, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Quantity of stations box, 3rd from left text3 = XtVaCreateWidget("create_appshell text_output3", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 14, XmNwidth, ((10*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text2, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom level box, 3rd from right text4 = XtVaCreateWidget("create_appshell text_output4", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((8*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Log indicator box, 2nd from right log_indicator = XtVaCreateWidget(langcode("BBARSTA043"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*FONT_WIDTH)), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text4, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interface status indicators, on right iface_da = XtVaCreateWidget("create_appshell iface", xmDrawingAreaWidgetClass, form, XmNwidth, 22*(MAX_IFACE_DEVICES/2), XmNheight, 20, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, log_indicator, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #endif // USE_TWO_STATUS_LINES // The separator goes on top of the text box no matter how // many lines the status bar is, so I'm putting if after the // endif statement - DCR sep = XtVaCreateManagedWidget("create_appshell sep6", xmSeparatorGadgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Map drawing area da_width = (Dimension)screen_width; da_height = (Dimension)screen_height; da = XtVaCreateWidget("create_appshell da", xmDrawingAreaWidgetClass, form, XmNwidth, da_width, XmNheight, da_height, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menubar, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, sep, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //------------------------------------------------------------------------- // Create the mouse menus here ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; #ifdef SWAP_MOUSE_BUTTONS // // Motif 2.2.2 (and perhaps earlier, back to version 2.0) has a // problem where the XmNmenuPost doesn't work properly for // modifiers (CapsLock/ScrollLock/NumLock/etc). We're reverting // back to the Motif 1.x method of doing things. It works! // //XtSetArg(al[ac], XmNmenuPost, ""); ac++; // Set for popup menu on button 1 XtSetArg(al[ac], XmNwhichButton, 1); ac++; // Enable popup menu on button 1 #else // SWAP_MOUSE_BUTTONS // // Motif 2.2.2 (and perhaps earlier, back to version 2.0) has a // problem where the XmNmenuPost doesn't work properly for // modifiers (CapsLock/ScrollLock/NumLock/etc). We're reverting // back to the Motif 1.x method of doing things. It works! // //XtSetArg(al[ac], XmNmenuPost, ""); ac++; // Set for popup menu on button 3 XtSetArg(al[ac], XmNwhichButton, 3); ac++; // Enable popup menu on button 3 #endif // SWAP_MOUSE_BUTTONS XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; // Right menu popup (right mouse button or button 3) right_menu_popup = XmCreatePopupMenu(da, "create_appshell Menu Popup", al, ac); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "Options" (void)XtCreateManagedWidget(langcode("POPUPMA001"), xmLabelWidgetClass, right_menu_popup, al, ac); (void)XtCreateManagedWidget("create_appshell sep7", xmSeparatorWidgetClass, right_menu_popup, al, ac); // "Center" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA00c")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_ctr=XtCreateManagedWidget(langcode("POPUPMA00c"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(pan_ctr,XmNactivateCallback,Pan_ctr,NULL); // "Station info" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA015")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_info=XtCreateManagedWidget(langcode("POPUPMA015"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(station_info,XmNactivateCallback,Station_info,NULL); // Send Message To ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("PULDNMG001")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; send_message_to=XtCreateManagedWidget(langcode("PULDNMG001"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(send_message_to,XmNactivateCallback,Station_info,"4"); // Map Bookmarks ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("PULDNMP012")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; jump_button2=XtCreateManagedWidget(langcode("PULDNMP012"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(jump_button2,XmNactivateCallback,Jump_location, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell zoom sub", al, ac); // "Zoom level" //zoom_level XtVaCreateManagedWidget(langcode("POPUPMA004"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,zoom_sub, XmNmnemonic,langcode_hotkey("POPUPMA004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom in" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA002")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_in=XtCreateManagedWidget(langcode("POPUPMA002"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zoom_in,XmNactivateCallback,Zoom_in,NULL); // Zoom out" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA003")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_out=XtCreateManagedWidget(langcode("POPUPMA003"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zoom_out,XmNactivateCallback,Zoom_out,NULL); // "1" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA005")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl1=XtCreateManagedWidget(langcode("POPUPMA005"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl1,XmNactivateCallback,Zoom_level,"1"); // "16" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA006")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl2=XtCreateManagedWidget(langcode("POPUPMA006"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl2,XmNactivateCallback,Zoom_level,"2"); // "64" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA007")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl3=XtCreateManagedWidget(langcode("POPUPMA007"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl3,XmNactivateCallback,Zoom_level,"3"); // "256" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA008")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl4=XtCreateManagedWidget(langcode("POPUPMA008"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl4,XmNactivateCallback,Zoom_level,"4"); // "1024" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA009")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl5=XtCreateManagedWidget(langcode("POPUPMA009"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl5,XmNactivateCallback,Zoom_level,"5"); // "8192" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA010")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl6=XtCreateManagedWidget(langcode("POPUPMA010"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl6,XmNactivateCallback,Zoom_level,"6"); // "Entire World" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA017")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl7=XtCreateManagedWidget(langcode("POPUPMA017"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl7,XmNactivateCallback,Zoom_level,"7"); // "10% out" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'o'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl8=XtCreateManagedWidget(langcode("POPUPMA035"), // 10% out xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl8,XmNactivateCallback,Zoom_level,"8"); // "10% in" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'i'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl9=XtCreateManagedWidget(langcode("POPUPMA036"), // 10% in xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl9,XmNactivateCallback,Zoom_level,"9"); // "Custom Zoom Level" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'i'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zlC=XtCreateManagedWidget(langcode("POPUPMA034"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zlC,XmNactivateCallback,Zoom_level,"10"); // "Last map pos/zoom" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA016")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; last_loc=XtCreateManagedWidget(langcode("POPUPMA016"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(last_loc,XmNactivateCallback,Last_location,NULL); (void)XtCreateManagedWidget("create_appshell sep7a", xmSeparatorWidgetClass, right_menu_popup, al, ac); // "Object -> Create" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA018")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; set_object=XtCreateManagedWidget(langcode("POPUPMA018"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(set_object,XmNactivateCallback,Set_Del_Object,NULL); // "Object -> Modify" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA019")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; modify_object=XtCreateManagedWidget(langcode("POPUPMA019"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(modify_object,XmNactivateCallback,Station_info,"1"); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Display a list of predefined SAR or Public service event objects. sar_object_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell sar_object_sub", al, ac); // "Predefined Objects" //sar_object_menu XtVaCreateManagedWidget(langcode("POPUPMA045"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,sar_object_sub, // XmNmnemonic,langcode_hotkey("POPUPMA045"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); BuildPredefinedSARMenu_UI(&sar_object_sub); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; XtCreateManagedWidget("create_appshell sep7b", xmSeparatorWidgetClass, right_menu_popup, al, ac); XtCreateManagedWidget("create_appshell sep7c", xmSeparatorWidgetClass, right_menu_popup, al, ac); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell pan sub", al, ac); // "Pan" // pan_menu=XtVaCreateManagedWidget(langcode(""), //pan_menu XtVaCreateManagedWidget("Pan", xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,pan_sub, // XmNmnemonic,langcode_hotkey("POPUPMA004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Pan Up" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA011")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_up=XtCreateManagedWidget(langcode("POPUPMA011"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_up=XtVaCreateManagedWidget("create_appshell arrow1", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_UP, // NULL); XtAddCallback(pan_up,XmNactivateCallback,Pan_up,NULL); // "Pan Left" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA013")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_left=XtCreateManagedWidget(langcode("POPUPMA013"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_left=XtVaCreateManagedWidget("create_appshell arrow3", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_LEFT, // NULL); XtAddCallback(pan_left,XmNactivateCallback,Pan_left,NULL); // "Pan Right" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA014")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_right=XtCreateManagedWidget(langcode("POPUPMA014"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_right=XtVaCreateManagedWidget("create_appshell arrow4", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_RIGHT, // NULL); XtAddCallback(pan_right,XmNactivateCallback,Pan_right,NULL); // "Pan Down" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA012")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_down=XtCreateManagedWidget(langcode("POPUPMA012"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_down=XtVaCreateManagedWidget("create_appshell arrow2", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_DOWN, // NULL); XtAddCallback(pan_down,XmNactivateCallback,Pan_down,NULL); XtCreateManagedWidget("create_appshell sep7d", xmSeparatorWidgetClass, right_menu_popup, al, ac); move_my_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell move_my sub", al, ac); //move_my_menu XtVaCreateManagedWidget(langcode("POPUPMA025"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,move_my_sub, XmNmnemonic,langcode_hotkey("POPUPMA025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Move my station here" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA025")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; setmyposition=XtCreateManagedWidget(langcode("POPUPMA025"), xmPushButtonGadgetClass, move_my_sub, al, ac); XtAddCallback(setmyposition,XmNactivateCallback,SetMyPosition,"1"); //------------------------------------------------------------------------- /* mouse tracking */ XtAddEventHandler(da,LeaveWindowMask,FALSE,ClearTrackMouse,(XtPointer)text2); XtAddEventHandler(da,PointerMotionMask,FALSE,TrackMouse,(XtPointer)text2); // Popup menus XtAddEventHandler(da, ButtonPressMask, FALSE, (XtEventHandler)Mouse_button_handler, NULL); //XtAddEventHandler(da,ButtonReleaseMask,FALSE,(XtEventHandler)Mouse_button_handler,NULL); // If adding any more widgets here, increase the size of the // children[] array above. ac = 0; children[ac++] = text; children[ac++] = text2; children[ac++] = text3; children[ac++] = text4; children[ac++] = log_indicator; children[ac++] = iface_da; children[ac++] = menubar; children[ac++] = toolbar; children[ac++] = da; XtManageChildren(children, ac); ac = 0; // This one needs to be done after all of // the above 'cuz it contains all of them. XtManageChild(form); WM_DELETE_WINDOW = XmInternAtom(XtDisplay(appshell),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(appshell, WM_DELETE_WINDOW, Window_Quit, (XtPointer) NULL); XtAddCallback(appshell,XtNsaveCallback, save_state, (XtPointer) NULL); XtAddCallback(appshell,XtNdieCallback, Window_Quit, (XtPointer) NULL); XmTextFieldSetString(text,""); XtManageChild(text); display_zoom_status(); XtManageChild(text); // We get this error on some systems if XtRealizeWidget() is called // without setting width/height values first: // "Error: Shell widget xastir has zero width and/or height" XtRealizeWidget (appshell); // Flush all pending requests to the X server. XFlush(display); create_gc(da); // Fill the drawing area with the background color. (void)XSetForeground(XtDisplay(da),gc,MY_BG_COLOR); // Not a mistake! (void)XSetBackground(XtDisplay(da),gc,MY_BG_COLOR); (void)XFillRectangle(XtDisplay(appshell), XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height); XtAddCallback (da, XmNinputCallback, da_input,NULL); XtAddCallback (da, XmNresizeCallback, da_resize,NULL); XtAddCallback (da, XmNexposeCallback, da_expose,(XtPointer)text); // Don't discard events in X11 queue, but wait for the X11 // server to catch up. (void)XSync(XtDisplay(appshell), False); // Send the window manager hints // XSetWMHints(display, XtWindow(appshell), wm_hints); // Set up the icon icon_pixmap = XCreateBitmapFromData(display, XtWindow(appshell), (char *)icon_bits, icon_width, // icon_bitmap_width, icon_height); // icon_bitmap_height XSetStandardProperties(display, XtWindow(appshell), title ? title: "Xastir", // window name "Xastir", // icon name icon_pixmap, // pixmap for icon 0, 0, // argv and argc for restarting NULL); // size hints if (title) { free(title); title = NULL; } if (track_me) { XmToggleButtonSetState(trackme_button,TRUE,TRUE); } else { XmToggleButtonSetState(trackme_button,FALSE,TRUE); } // Flush all pending requests to the X server. XFlush(display); // Don't discard events in X11 queue, but wait for the X11 // server to catch up. (void)XSync(XtDisplay(appshell), False); // Reset the minimum window size so that we can adjust the // window downwards again, but only down to size 61. If we go // any smaller height-wise then we end up getting segfaults, // probably because we're trying to update some widgets that // aren't visible at that point. // XtVaSetValues(appshell, XmNminWidth, 61, XmNminHeight, 61, XmNwidth, my_appshell_width, XmNheight, my_appshell_height, // XmNx, screen_x_offset, // Doesn't work here // XmNy, screen_y_offset, // Doesn't work here NULL); // Lincity method of locking down the min_width/height when // instantiating the window, then releasing it later: // http://pingus.seul.org/~grumbel/tmp/lincity-source/lcx11_8c-source.html // Actually show the draw and show the window on the display XMapRaised(XtDisplay(appshell), XtWindow(appshell)); // Free the allocated struct. We won't need it again. // XFree(wm_hints); // We're not currently using this struct if(debug_level & 8) { fprintf(stderr,"Create appshell stop\n"); } } // end of create_appshell() void BuildPredefinedSARMenu_UI(Widget *parent_menu) { int i; // number of items in menu int ac; // number of arguments Arg al[100]; // arguments // Set standard menu item arguments to use with each widget. ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Before building menu, make sure that any existing menu items are removed // this allows the menu to be changed on the fly while the program is running. // for (i = 0; i < MAX_NUMBER_OF_PREDEFINED_OBJECTS; i++) { if (predefined_object_menu_items[i] != NULL) { XtDestroyWidget(predefined_object_menu_items[i]); predefined_object_menu_items[i] = NULL; } } // Now build a menu item for each entry in the predefinedObjects array. for (i = 0; i < number_of_predefined_objects; i++) { // Walk through array of predefined objects and // build a menu item for each predefined object. // if (predefinedObjects[i].show_on_menu == 1) { // Some predefined objects are hidden to allow construction // of two predefined objects in the same place at the same // time with one menu item. if(debug_level & 1) fprintf(stderr, "Menu item with name: %s and index_of_child=%d\n", predefinedObjects[i].menu_call, predefinedObjects[i].index_of_child); predefined_object_menu_items[i]=XtCreateManagedWidget(predefinedObjects[i].menu_call, xmPushButtonGadgetClass, *parent_menu, al, ac); XtAddCallback(predefined_object_menu_items[i], XmNactivateCallback, Create_SAR_Object, (intptr_t *)predefinedObjects[i].index); if (predefinedObjects[i].index_of_child > -1) { // This second callback allows stacking of two // objects such as a PLS with 0.25 and 0.5 and a // PLS_ with 0.75 and 1.0 mile probability circles. // if (predefinedObjects[i].index_of_child < number_of_predefined_objects) { XtAddCallback(predefined_object_menu_items[i], XmNactivateCallback, Create_SAR_Object, (intptr_t *)predefinedObjects[predefinedObjects[i].index_of_child].index); } } } } } void create_gc(Widget w) { XGCValues values; Display *my_display = XtDisplay(w); int mask = 0; Pixmap pix; unsigned int _w, _h; int _xh, _yh; char xbm_path[500]; int ret_val; if (debug_level & 8) { fprintf(stderr,"Create gc start\n"); } if (gc != 0) { return; } memset(&values, 0, sizeof(values)); // Allocate colors // Note that the names here are the ones given in xastir.rgb colors[0x00] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) colors[0x01] = GetPixelByName(w,"purple"); colors[0x02] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) colors[0x03] = GetPixelByName(w,"cyan"); colors[0x04] = GetPixelByName(w,"brown"); colors[0x05] = GetPixelByName(w,"plum"); // light magenta colors[0x06] = GetPixelByName(w,"orange"); colors[0x07] = GetPixelByName(w,"darkgray"); colors[0x08] = GetPixelByName(w,"black"); // Foreground font color colors[0x09] = GetPixelByName(w,"blue"); colors[0x0a] = GetPixelByName(w,"green"); // PHG (old) colors[0x0b] = GetPixelByName(w,"mediumorchid"); // light purple colors[0x0c] = GetPixelByName(w,"red"); colors[0x0d] = GetPixelByName(w,"magenta"); colors[0x0e] = GetPixelByName(w,"yellow"); colors[0x0f] = GetPixelByName(w,"white"); // colors[0x10] = GetPixelByName(w,"black"); colors[0x11] = GetPixelByName(w,"black"); colors[0x12] = GetPixelByName(w,"black"); colors[0x13] = GetPixelByName(w,"black"); colors[0x14] = GetPixelByName(w,"lightgray"); colors[0x15] = GetPixelByName(w,"magenta"); colors[0x16] = GetPixelByName(w,"mediumorchid"); // light purple colors[0x17] = GetPixelByName(w,"lightblue"); colors[0x18] = GetPixelByName(w,"purple"); colors[0x19] = GetPixelByName(w,"orange2"); // light orange colors[0x1a] = GetPixelByName(w,"SteelBlue"); colors[0x20] = GetPixelByName(w,"white"); // Area object colors. Order must not be changed. If beginning moves, // update draw_area and draw_map. // High colors[0x21] = GetPixelByName(w,"black"); // AREA_BLACK_HI colors[0x22] = GetPixelByName(w,"blue"); // AREA_BLUE_HI colors[0x23] = GetPixelByName(w,"green"); // AREA_GREEN_HI colors[0x24] = GetPixelByName(w,"cyan3"); // AREA_CYAN_HI colors[0x25] = GetPixelByName(w,"red"); // AREA_RED_HI colors[0x26] = GetPixelByName(w,"magenta"); // AREA_VIOLET_HI colors[0x27] = GetPixelByName(w,"yellow"); // AREA_YELLOW_HI colors[0x28] = GetPixelByName(w,"gray35"); // AREA_GRAY_HI // Low colors[0x29] = GetPixelByName(w,"gray27"); // AREA_BLACK_LO colors[0x2a] = GetPixelByName(w,"blue4"); // AREA_BLUE_LO colors[0x2b] = GetPixelByName(w,"green4"); // AREA_GREEN_LO colors[0x2c] = GetPixelByName(w,"cyan4"); // AREA_CYAN_LO colors[0x2d] = GetPixelByName(w,"red4"); // AREA_RED_LO colors[0x2e] = GetPixelByName(w,"magenta4"); // AREA_VIOLET_LO colors[0x2f] = GetPixelByName(w,"yellow4"); // AREA_YELLOW_LO colors[0x30] = GetPixelByName(w,"gray53"); // AREA_GRAY_LO colors[0x40] = GetPixelByName(w,"yellow"); // symbols ... colors[0x41] = GetPixelByName(w,"DarkOrange3"); colors[0x42] = GetPixelByName(w,"purple"); colors[0x43] = GetPixelByName(w,"gray80"); colors[0x44] = GetPixelByName(w,"red3"); colors[0x45] = GetPixelByName(w,"brown1"); colors[0x46] = GetPixelByName(w,"brown3"); colors[0x47] = GetPixelByName(w,"blue4"); colors[0x48] = GetPixelByName(w,"DeepSkyBlue"); colors[0x49] = GetPixelByName(w,"DarkGreen"); colors[0x4a] = GetPixelByName(w,"red2"); colors[0x4b] = GetPixelByName(w,"green3"); colors[0x4c] = GetPixelByName(w,"MediumBlue"); colors[0x4d] = GetPixelByName(w,"white"); colors[0x4e] = GetPixelByName(w,"gray53"); colors[0x4f] = GetPixelByName(w,"gray35"); colors[0x50] = GetPixelByName(w,"gray27"); colors[0x51] = GetPixelByName(w,"black"); // ... symbols colors[0x52] = GetPixelByName(w,"LimeGreen"); // PHG, symbols colors[0xfe] = GetPixelByName(w,"pink"); // map solid colors colors[0x60] = GetPixelByName(w,"HotPink"); colors[0x61] = GetPixelByName(w,"RoyalBlue"); colors[0x62] = GetPixelByName(w,"orange3"); colors[0x63] = GetPixelByName(w,"yellow3"); colors[0x64] = GetPixelByName(w,"ForestGreen"); colors[0x65] = GetPixelByName(w,"DodgerBlue"); colors[0x66] = GetPixelByName(w,"cyan2"); colors[0x67] = GetPixelByName(w,"plum2"); colors[0x68] = GetPixelByName(w,"MediumBlue"); // was blue3 (the same!) colors[0x69] = GetPixelByName(w,"gray86"); // These colors added to make it possible to color local shapefile tiger // maps similar to on-line ones. colors[0x70] = GetPixelByName(w,"RosyBrown2"); colors[0x71] = GetPixelByName(w,"gray81"); colors[0x72] = GetPixelByName(w,"tgr_park_1"); colors[0x73] = GetPixelByName(w,"tgr_city_1"); colors[0x74] = GetPixelByName(w,"tgr_forest_1"); colors[0x75] = GetPixelByName(w,"tgr_water_1"); // tracking trail colors // set color for your own station with #define MY_TRAIL_COLOR in db.c trail_colors[0x00] = GetPixelByName(w,"yellow"); trail_colors[0x01] = GetPixelByName(w,"blue"); trail_colors[0x02] = GetPixelByName(w,"green"); trail_colors[0x03] = GetPixelByName(w,"red"); trail_colors[0x04] = GetPixelByName(w,"magenta"); trail_colors[0x05] = GetPixelByName(w,"black"); trail_colors[0x06] = GetPixelByName(w,"white"); trail_colors[0x07] = GetPixelByName(w,"DarkOrchid"); trail_colors[0x08] = GetPixelByName(w,"purple"); // very similar to DarkOrchid... trail_colors[0x09] = GetPixelByName(w,"OrangeRed"); trail_colors[0x0a] = GetPixelByName(w,"brown"); trail_colors[0x0b] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) trail_colors[0x0c] = GetPixelByName(w,"MediumBlue"); trail_colors[0x0d] = GetPixelByName(w,"ForestGreen"); trail_colors[0x0e] = GetPixelByName(w,"chartreuse"); trail_colors[0x0f] = GetPixelByName(w,"cornsilk"); trail_colors[0x10] = GetPixelByName(w,"LightCyan"); trail_colors[0x11] = GetPixelByName(w,"cyan"); trail_colors[0x12] = GetPixelByName(w,"DarkSlateGray"); trail_colors[0x13] = GetPixelByName(w,"NavyBlue"); trail_colors[0x14] = GetPixelByName(w,"DarkOrange3"); trail_colors[0x15] = GetPixelByName(w,"gray27"); trail_colors[0x16] = GetPixelByName(w,"RoyalBlue"); trail_colors[0x17] = GetPixelByName(w,"yellow2"); trail_colors[0x18] = GetPixelByName(w,"DodgerBlue"); trail_colors[0x19] = GetPixelByName(w,"cyan2"); trail_colors[0x1a] = GetPixelByName(w,"MediumBlue"); // was blue3 (the same!) trail_colors[0x1b] = GetPixelByName(w,"gray86"); trail_colors[0x1c] = GetPixelByName(w,"SteelBlue"); trail_colors[0x1d] = GetPixelByName(w,"PaleGreen"); trail_colors[0x1e] = GetPixelByName(w,"RosyBrown"); trail_colors[0x1f] = GetPixelByName(w,"DeepSkyBlue"); values.background=GetPixelByName(w,"darkgray"); gc = XCreateGC(my_display, XtWindow(w), mask, &values); // Load a new font into the GC for the station font Load_station_font(); gc_tint = XCreateGC(my_display, XtWindow(w), mask, &values); gc_stipple = XCreateGC(my_display, XtWindow(w), mask, &values); gc_bigfont = XCreateGC(my_display, XtWindow(w), mask, &values); pix = XCreatePixmap(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), 20, 20, 1); values.function = GXcopy; gc2 = XCreateGC(XtDisplay(w), pix,GCForeground|GCBackground|GCFunction, &values); pixmap=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); pixmap_final=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); pixmap_alerts=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "2x2.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_50pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 2x2.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "25pct.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_25pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 25pct.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "13pct.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_13pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 13pct.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "alert.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_wx_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // alert.xbm couldn't be loaded } display_up=1; wait_to_redraw=0; if (debug_level & 8) { fprintf(stderr,"Create gc stop\n"); } } // create_gc() // This routine just copies an area from pixmap_final to the // display, so we won't go through all the trouble of making this // interruptible. Just get on with it, perform the operation, and // return to X. If it did any map drawing, we'd make it // interruptible. // void da_expose(Widget w, XtPointer UNUSED(client_data), XtPointer call_data) { Dimension width, height, margin_width, margin_height; XmDrawingAreaCallbackStruct *db = (XmDrawingAreaCallbackStruct *)call_data; XExposeEvent *event = (XExposeEvent *) db->event; unsigned char unit_type; //fprintf(stderr,"Expose event\n");*/ /* Call a routine to create a Graphics Context */ create_gc(w); /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XCopyArea(XtDisplay(w), pixmap_final, XtWindow(w), gc, event->x, event->y, event->width, event->height, event->x, event->y); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; } // The work function for resizing. This one will be called by // UpdateTime if certain flags have been set my da_resize. This // function and the functions it calls that are CPU intensive should // be made interruptible: They should check interrupt_drawing_now // flag periodically and exit nicely if it is set. // void da_resize_execute(Widget w) { Dimension width, height; busy_cursor(appshell); // Reset the flags that may have brought us here. interrupt_drawing_now = 0; request_resize = 0; if (XtIsRealized(w)) { /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); screen_width = (long)width; screen_height = (long)height; XtVaSetValues(w, XmNwidth, width, XmNheight, height, NULL); /* fprintf(stderr,"Size x:%ld, y:%ld\n",screen_width,screen_height);*/ if (pixmap) { (void)XFreePixmap(XtDisplay(w),pixmap); } if(pixmap_final) { (void)XFreePixmap(XtDisplay(w),pixmap_final); } if(pixmap_alerts) { (void)XFreePixmap(XtDisplay(w),pixmap_alerts); } pixmap=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); pixmap_final=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); pixmap_alerts=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } setup_in_view(); // flag stations that are in screen view HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(w)) { // (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } // We got a resize callback. Set flags. UpdateTime will come // along in a bit and perform the resize. With this method, the // resize can be made interruptible. We merely need to check for // the interrupt_drawing_now flag periodically while doing the // resize drawing. // void da_resize(Widget UNUSED(w), XtPointer UNUSED(client_data), XtPointer UNUSED(call_data) ) { // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Set the request_resize flag request_resize++; // last_input_event = sec_now() + 2; } // We got a mouse or keyboard callback. Set flags. UpdateTime // will come along in a bit and perform the screen redraw. With // this method, the redraw can be made interruptible. We merely // need to check for the interrupt_drawing_now flag periodically // while doing the redraw. // void da_input(Widget w, XtPointer client_data, XtPointer call_data) { XEvent *event = ((XmDrawingAreaCallbackStruct *) call_data)->event; Dimension width, height; int redraw; char buffer[20]; int bufsize = 20; char temp[200]; char temp_course[20]; KeySym key; XComposeStatus compose; int x_center; int y_center; // int x_distance; // int y_distance; float x_distance_real; float y_distance_real; float full_distance; double area; float area_acres; // area in acres long a_x, a_y, b_x, b_y; char str_lat[20]; char str_long[20]; long x,y; int done = 0; long lat, lon; XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); /*fprintf(stderr,"input event %d %d\n",event->type,ButtonPress);*/ redraw=0; // Snag the current pointer position input_x = event->xbutton.x; input_y = event->xbutton.y; ///////////////// // CAD OBJECTS // ///////////////// // Start of CAD Objects code. We have both ButtonPress and // ButtonRelease code handlers here, for this mode only. // Check whether we're in CAD Object draw mode first if (draw_CAD_objects_flag && event->xbutton.button == Button2) { if (event->type == ButtonRelease) { // We don't want to do anything for ButtonRelease. Most // of all, we don't want another point drawn for both // press and release, and we don't want other GUI // actions performed on release when in CAD Draw mode. done++; } else // ButtonPress for Button2 { // We need to check to see whether we're dragging the // pointer, and then need to save the points away (in // Xastir lat/long format), drawing lines between the // points whenever we do a pixmap_final refresh to the // screen. // Check whether we just did the first mouse button down // while in CAD draw mode. If so, save away the mouse // pointer and get out. We'll use that mouse pointer // the next time a mouse button gets pressed in order to // draw a line. // We're going to use gc_tint with an XOR bitblit here // to make sure that any lines we draw will be easily // seen, no matter what colors we're drawing on top of. // // If we have a valid saved position already from our // first click, then we must be on the 2nd or later // click. Draw a line. if (polygon_last_x != -1 && polygon_last_y != -1) { // Convert from screen coordinates to Xastir // coordinate system and save in the object->vertice // list. convert_screen_to_xastir_coordinates(input_x, input_y, &lat, &lon); CAD_vertice_allocate(lat, lon); // Reload symbols/tracks/CAD objects redraw_symbols(da); } else // First point of a polygon. Save it. { // Figure out the real lat/long from the screen // coordinates. Create a new object to hold the // point. convert_screen_to_xastir_coordinates(input_x, input_y, &lat, &lon); CAD_object_allocate(lat, lon); } // Save current point away for the next draw. polygon_last_x = input_x; polygon_last_y = input_y; done++; } } // End of CAD Objects code. ///////////////////////////////// // Start of ButtonRelease code // ///////////////////////////////// if (!done && event->type == ButtonRelease) { //fprintf(stderr,"ButtonRelease %d %d\n",event->xbutton.button,Button3); #ifdef SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button3) { // Right mouse button release #else // SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button1) { // Left mouse button release #endif // SWAP_MOUSE_BUTTONS // If no drag, Center the map on the mouse pointer // If drag, compute new zoom factor/center and redraw // -OR- measure distances. ///////////////////////// // CENTER MAP FUNCTION // ///////////////////////// // Check for "Center Map" function. Must be within 15 // pixels of where the button press occurred to qualify. if ( mouse_zoom && !measuring_distance && !moving_object && (abs(menu_x - input_x) < 15) && (abs(menu_y - input_y) < 15) ) { /* if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } */ // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; } // It's not the center function because the mouse moved more than 15 pixels. // It must be either the "Compute new zoom/center" -OR- the "Measure distance" // -OR- "Move distance" functions.. The "measuring_distance" or "moving_object" // variables will tell us. else { // At this stage we have menu_x/menu_y where the button press occurred, // and input_x/input_y where the button release occurred. ////////////////////// // MEASURE DISTANCE // ////////////////////// if (measuring_distance) // Measure distance function { double R = EARTH_RADIUS_METERS; // Check whether we already have a box on screen // that we need to erase. if (zoom_box_x1 != -1) { //fprintf(stderr,"erasing\n"); // Remove the last box drawn via the XOR // function. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x1), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y1), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y1)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x2), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x2), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y2), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y2)); } // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; // x_distance = abs(menu_x - input_x); // y_distance = abs(menu_y - input_y); // Here we need to convert to either English or Metric units of distance. //(temp,"Distance x:%d pixels, y:%d pixels\n",x_distance,y_distance); //popup_message_always(langcode("POPUPMA020"),temp); XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); a_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); a_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); b_x = center_longitude - ((width *scale_x)/2) + (input_x*scale_x); b_y = center_latitude - ((height*scale_y)/2) + (input_y*scale_y); // Keep y constant to get x distance. Convert // to the current measurement units for display. x_distance_real = cvt_kn2len * calc_distance_course(a_y,a_x,a_y,b_x,temp_course,sizeof(temp_course)); // Keep x constant to get y distance. Convert // to the current measurement units for display. y_distance_real = cvt_kn2len * calc_distance_course(a_y,a_x,b_y,a_x,temp_course,sizeof(temp_course)); // Compute the total distance and course. // Convert to the current measurement units for // display. full_distance = cvt_kn2len * calc_distance_course(a_y,a_x,b_y,b_x,temp_course,sizeof(temp_course)); if (full_distance < 1.0) { switch (english_units) { case 1: // English full_distance = full_distance * 5280; // convert from miles to feet x_distance_real = x_distance_real * 5280; // convert from miles to feet y_distance_real = y_distance_real * 5280; // convert from miles to feet break; case 2: // Nautical miles and knots full_distance = full_distance * 6076; // convert from miles to feet x_distance_real = x_distance_real * 6076; // convert from miles to feet y_distance_real = y_distance_real * 6076; // convert from miles to feet break; default: // Metric full_distance = full_distance * 1000; // convert from kilometers to meters x_distance_real = x_distance_real * 1000; // convert from kilometers to meters y_distance_real = y_distance_real * 1000; // convert from kilometers to meters break; } // See this URL for a method of calculating the area of a lat/long // rectangle on a sphere: // http://mathforum.org/library/drmath/view/63767.html // area = (pi/180)*R^2 * abs(sin(lat1)-sin(lat2)) * abs(lon1-lon2) // // Their formula is incorrect due to the mistake of mixing radians // and degrees. The correct formula is (WE7U): // area = R^2 * abs(sin(lat1)-sin(lat2)) * abs(lon1-lon2) // Compute correct units switch (english_units) { case 1: // English R = EARTH_RADIUS_MILES * 5280.0; // feet break; case 2: // Nautical miles and knots R = EARTH_RADIUS_MILES * 5280.0; // feet break; default: // Metric R = EARTH_RADIUS_METERS; // Meters break; } // Compute the total area in feet or meters // New method using area on a sphere: area = R*R * fabs( sin(convert_lat_l2r(a_y)) - sin(convert_lat_l2r(b_y)) ) * fabs( convert_lon_l2r(a_x) - convert_lon_l2r(b_x) ); // Old method using planar geometry: //area = x_distance_real * y_distance_real; // calculate area in acres switch (english_units) { case 1: case 2: area_acres = area * 2.2956749e-05; break; default: // Metric area_acres = area * 2.4710439e-04; break; } //if (area_acres<0.1) // area_acres = 0; //fprintf(stderr,"Old method: %f\nNew method: %f\n\n", // x_distance_real * y_distance_real, // area); // NOTE: Angles currently change at zoom==1, so we purposely don't // give an angle in that measurement instance below. // xastir_snprintf(temp, sizeof(temp), "%0.2f %s, x=%0.2f %s, y=%0.2f %s, %0.2f %s %s (%0.2f %s), %s: %s %s", full_distance, un_alt, // feet/meters x_distance_real, un_alt, // feet/meters y_distance_real, un_alt, // feet/meters area, langcode("POPUPMA038"), // square un_alt, area_acres, "acres", langcode("POPUPMA041"), // Bearing (scale_y == 1) ? "??" : temp_course, // Fix for zoom==1 langcode("POPUPMA042") ); // degrees } else { // Compute the total area in miles or // kilometers // Compute correct units switch (english_units) { case 1: // English R = EARTH_RADIUS_MILES; // Statute miles break; case 2: // Nautical miles and knots R = EARTH_RADIUS_KILOMETERS/1.852; // Nautical miles break; default: // Metric R = EARTH_RADIUS_KILOMETERS; // kilometers break; } // New method, area on a sphere: area = R*R * fabs(sin(convert_lat_l2r(a_y))-sin(convert_lat_l2r(b_y))) * fabs(convert_lon_l2r(a_x)-convert_lon_l2r(b_x)); // Old method using planar geometry: //area = x_distance_real * y_distance_real; //fprintf(stderr,"Old method: %f\nNew method: %f\n\n", // x_distance_real * y_distance_real, // area); xastir_snprintf(temp, sizeof(temp), "%0.2f %s, x=%0.2f %s, y=%0.2f %s, %0.2f %s %s, %s: %s %s", full_distance, un_dst, // miles/kilometers x_distance_real, un_dst, // miles/kilometers y_distance_real, un_dst, // miles/kilometers area, langcode("POPUPMA038"), // square un_dst, langcode("POPUPMA041"), // Bearing temp_course, langcode("POPUPMA042") ); // degrees } popup_message_always(langcode("POPUPMA020"),temp); } /////////////////// // MOVING OBJECT // /////////////////// else if (moving_object) // Move function { // For this function we need to: // Determine which icon is closest to the mouse pointer press position. // We'll use Station_info to select the icon for us. // Determine whether it is our object. If not, force // the user to "adopt" the object before moving it. // Compute the lat/lon of the mouse pointer release position. // Put the new value of lat/lon into the object data. // Cause symbols to get redrawn. // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; x = (center_longitude - ((screen_width * scale_x)/2) + (event->xmotion.x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (event->xmotion.y * scale_y)); if (x < 0) { x = 0l; // 180°W } if (x > 129600000l) { x = 129600000l; // 180°E } if (y < 0) { y = 0l; // 90°N } if (y > 64800000l) { y = 64800000l; // 90°S } if (debug_level & 1) { // This math is only used for the debug mode printf below. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DEC_DEG); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DMS_NORMAL); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_HP_NORMAL); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_HP_NORMAL); } //fprintf(stderr,"%s %s\n", str_lat, str_long); } // Effect the change in the object/item's // position. // doing_move_operation++; Station_info(w, "2", NULL); doing_move_operation = 0; } ///////////////////////////// // COMPUTE NEW CENTER/ZOOM // ///////////////////////////// else // Must be "Compute new center/zoom" function { float ratio; if (!map_lock_pan_zoom) { // We need to compute a new center and a new scale, then // cause the new image to be created. // Compute new center. It'll be the average of the two points x_center = (menu_x + input_x) /2; y_center = (menu_y + input_y) /2; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (x_center*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (y_center*scale_y); // // What Rolf had to say: // // Calculate center of mouse-marked area and get the scaling relation // between x and y for that position. This position will be the new // center, so that lattitude-dependent relation does not change with // a zoom-in. For both x and y calculate a new zoom factor necessary // to fit that screen direction. Select the one that allows both x // and y part to fall into the screen area. Draw the new screen with // new center and new zoom factor. // // Compute the new scale, or as close to it as we can get //new_scale_y = scale_y / 2; // Zoom in by a factor of 2 new_scale_y = (long)( (((1.0 * abs(menu_y - input_y)) / (float)height ) * (float)scale_y ) + 0.5); new_scale_x = (long)( (((1.0 * abs(menu_x - input_x)) / (float)width ) * (float)scale_x ) + 0.5); if (new_scale_y < 1) { new_scale_y = 1; // Don't go further in than zoom 1 } if (new_scale_x < 1) { new_scale_x = 1; // Don't go further in than zoom 1 } // We now know approximately the scales we need // in order to view all of the pixels just // selected in the drag operation. Now set // new_scale_y to the highest number of the two, // which will make sure the entire drag // selection will be seen at the new zoom level. // Use the new ratio between scales to compute // this, computed from the new midpoint. // //fprintf(stderr,"scale_x:%ld\tscale_y:%ld\n", get_x_scale(new_mid_x, new_mid_y, scale_y), scale_y ); ratio = ( (1.0 * get_x_scale(new_mid_x,new_mid_y,scale_y)) / (float)scale_y); //fprintf(stderr,"Ratio: %f\n", ratio); //fprintf(stderr,"x:%ld\ty:%ld\n", new_scale_x, new_scale_y); if ( new_scale_y < (long)((new_scale_x / ratio) + 0.5) ) { new_scale_y = (long)((new_scale_x / ratio) + 0.5); //fprintf(stderr,"Changed y\n"); } //fprintf(stderr,"x:%ld\ty:%ld\n", new_scale_x, new_scale_y); display_zoom_image(1); // Check range and do display, recenter menu_x = input_x; menu_y = input_y; //fprintf(stderr,"Drag/zoom/center happened\n"); // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; } } } mouse_zoom = 0; } // End of Button1 release code ////////////// // ZOOM OUT // ////////////// else if (event->xbutton.button == Button2 && !map_lock_pan_zoom) { // Middle mouse button release // Zoom out 2x with panning menu_x=input_x; menu_y=input_y; Zoom_out( w, client_data, call_data ); // Simple zoom out, keeping map center at current position //Zoom_out_no_pan( w, client_data, call_data ); mouse_zoom = 0; } // End of Button2 release code //////////////////////////////// // THIRD MOUSE BUTTON RELEASE // //////////////////////////////// #ifdef SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button1) { // Left mouse button release #else // SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button3) { // Right mouse button release #endif // SWAP_MOUSE_BUTTONS // Do nothing. We have a popup tied into the button press anyway. // (Mouse_button_handler & right_menu_popup). // Leave the button release alone in this case. mouse_zoom = 0; } // End of Button3 release code /////////////// // SCROLL UP // /////////////// else if (event->xbutton.button == Button4 && !map_lock_pan_zoom) { // Scroll up menu_x=input_x; menu_y=input_y; Pan_up(w, client_data, call_data); } // End of Button4 release code ///////////////// // SCROLL DOWN // ///////////////// else if (event->xbutton.button == Button5 && !map_lock_pan_zoom) { // Scroll down menu_x=input_x; menu_y=input_y; Pan_down(w, client_data, call_data); } // End of Button5 release code //////////////////////////////////// // YET MORE MOUSE BUTTON RELEASES // //////////////////////////////////// else if (event->xbutton.button == 6 && !map_lock_pan_zoom) { // Mouse button 6 release menu_x=input_x; menu_y=input_y; Zoom_out_no_pan(w, client_data, call_data); mouse_zoom = 0; } // End of Button6 code else if (event->xbutton.button == 7 && !map_lock_pan_zoom) { // Mouse button 7 release menu_x=input_x; menu_y=input_y; Zoom_in_no_pan(w, client_data, call_data); mouse_zoom = 0; } // End of Button7 release code } // End of ButtonRelease code /////////////////////////////// // Start of ButtonPress code // /////////////////////////////// else if (!done && event->type == ButtonPress) { //fprintf(stderr,"ButtonPress %d %d\n",event->xbutton.button,Button3); #ifdef SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button3) { // Right mouse button press #else // SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button1) { // Left mouse button press #endif // SWAP_MOUSE_BUTTONS // Mark the position for possible drag function menu_x=input_x; menu_y=input_y; mouse_zoom = 1; if (!moving_object) // Can be "Measure" or "Zoom-in" { if (!map_lock_pan_zoom || (map_lock_pan_zoom && measuring_distance)) { // Not moving an object/item, so allow the // zoom-in box to display. possible_zoom_function++; } } } // End of Button1 Press code else if (event->xbutton.button == Button2) { // Middle mouse button or both right/left mouse buttons press // Nothing attached here. mouse_zoom = 0; } // End of Button2 Press code #ifdef SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button1) { // Left mouse button press #else // SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button3) { // Right mouse button press #endif // SWAP_MOUSE_BUTTONS // Nothing attached here. mouse_zoom = 0; } // End of Button3 Press code } // End of ButtonPress code //////////////////////////// // Start of KeyPress code // //////////////////////////// else if (!done && event->type == KeyPress) { // We want to branch from the keysym instead of the keycode (void)XLookupString( (XKeyEvent *)event, buffer, bufsize, &key, &compose ); //fprintf(stderr,"main.c:da_input():keycode %d\tkeysym %ld\t%s\n", event->xkey.keycode, key, buffer); // keycode ??, keysym 65360 is Home (0x???? on sun kbd) // if ((key == 65360) || (key == 0x????)) { if (key == 65360) { if (!map_lock_pan_zoom) { Go_Home(w, NULL, NULL); } } // keycode 99, keysym 65365 is PageUp (0xffda on sun kbd) if ((key == 65365) || (key == 0xffda)) { menu_x=input_x; menu_y=input_y; Zoom_out_no_pan( w, client_data, call_data ); TrackMouse(w, (XtPointer)text2, event, NULL); } // keycode 105, keysym 65366 is PageDown (0xffe0 on sun kbd) if ((key == 65366) || (key == 0xffe0)) { menu_x=input_x; menu_y=input_y; Zoom_in_no_pan( w, client_data, call_data ); TrackMouse(w, (XtPointer)text2, event, NULL); } // keycode 100, keysym 65361 is left-arrow if ( (key == 65361) || ( (key == 65361) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_left_less( w, client_data, call_data); } else { Pan_left( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 102, keysym 65363 is right-arrow if ( (key == 65363) || ( (key == 65363) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_right_less( w, client_data, call_data); } else { Pan_right( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 98, keysym 65362 is up-arrow if ( (key == 65362) || ( (key == 65362) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_up_less( w, client_data, call_data); } else { Pan_up( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 105, keysym 65364 is down-arrow if ( (key == 65364) || ( (key == 65364) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_down_less( w, client_data, call_data); } else { Pan_down( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 35, keysym 61 is Equals // keycode 35, keysim 43 is Plus // keycode 86, keysim 65451 is KP_Add if (key == 61 || key == 43 || key == 65451) { grid_size++; redraw = 1; } // keycode 48, keysym 45 is Minus // keycode 82, keysym 65453 is KP_Subtract if (key == 45 || key == 65453) { grid_size--; redraw = 1; } // Adjust map scale, execpt when pan/zoom locked if (!map_lock_pan_zoom && OSM_optimize_key(key)) { if (debug_level & 512) { fprintf(stderr, "Initial scale, before adjustment sx/sy = %li/%li\n", scale_x, scale_y); } adj_to_OSM_level(&scale_x, &scale_y); if (debug_level & 512) { fprintf(stderr, "Scale adjusted for OSM, sx/sy = %li/%li\n", scale_x, scale_y); } redraw = 1; } if ((debug_level & 512) && OSM_report_scale_key(key)) { fprintf(stderr, "scale_x = %li, scale_y = %li, OSM zoom = %i\n", scale_x, scale_y, osm_zoom_level(scale_x)); } } // End of KeyPress code ////////////////////////////////// // START OF SOMETHING ELSE CODE // ////////////////////////////////// else if (!done) // Something else { if (event->type == MotionNotify) { input_x = event->xmotion.x; input_y = event->xmotion.y; //fprintf(stderr,"da_input2 x %d y %d\n",input_x,input_y); } } // End of SomethingElse code if (redraw) { /*fprintf(stderr,"Current x %ld y * %ld\n",center_longitude,center_latitude);*/ // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // last_input_event = sec_now() + 2; } } // DK7IN: this function is unused... //void wait_sec(int dt) { // time_t ct; // // ct = sec_now() + dt; // while (ct < sec_now()) { // } //} // This function snags the current pointer information and tries to // determine whether we're doing some sort of draw or zoom function. // If so, draws the appropriate temporary squares or lines that the // operator expects. // void check_pointer_position(void) { Window root_return, child_return; int rootx_return, rooty_return; int win_x_return, win_y_return; unsigned int mask_return; Bool ret; int x_return; int y_return; unsigned int width_return; unsigned int height_return; unsigned int border_width_return; unsigned int depth_return; // If this variable has not been set, we should not display the // box. if (!possible_zoom_function) { return; } // Snag the current pointer info ret = XQueryPointer(XtDisplay(da), XtWindow(da), // Window we are interested in &root_return, // Root window that pointer is in &child_return, // Child windows that pointer is in, if any &rootx_return, // Pointer coord. relative to root window &rooty_return, // Pointer coord. relative to root window &win_x_return, // Pointer coord. relative to specified window &win_y_return, // Pointer coord. relative to specified window &mask_return); // State of modifier keys and pointer buttons switch (ret) { case True: // If we made it here, we're on the same screen as the // specified window. It's a good start anyway. //fprintf(stderr, "x:%d y:%d ", win_x_return, win_y_return); //fprintf(stderr, "root:%lx child:%lx ", root_return, child_return); //fprintf(stderr, "mask:%03x ret:%02x\n", mask_return, ret); // Check mask_return to see if button one is being // pressed down (a drag operation). If so, we're doing // a zoom-in operation and need to draw a box. 0x100 // Check if button two (middle button) is being pressed // down (a drag operation). If so, we're doing a CAD // Object draw and need to draw a line. 0x200 // Figure out how to erase previous lines/boxes so that // only the current object is shown. We might need to // keep track of earlier vectors and then redraw them // with an XOR function to erase. // Get the dimensions for the drawing area // XGetGeometry(Display *display, // Drawable d, // Window *root_return, // int *x_return, // int *y_return, // unsigned int *width_return, // unsigned int *height_return, // unsigned int *border_width_return, // unsigned int *depth_return); XGetGeometry(XtDisplay(da), XtWindow(da), &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); // Check that X/Y are positive and below the max size of // the child window. if ( win_x_return >= (int)width_return || win_y_return >= (int)height_return) { /* fprintf(stderr, "Out of bounds: %d:%d %d:%d\n", win_x_return, width_return, win_y_return, height_return); */ return; } else { // Draw what we need to. // For CAD objects, polygon_last_x and // polygon_last_y contain the last position. // For the zoom-in function, menu_x and menu_y // contain the last position. if (draw_CAD_objects_flag) { // Check if button two (middle button) is being // pressed down (a drag operation). If so, // we're doing a CAD Object draw and need to // draw a line. 0x200 if ( (mask_return & 0x200) == 0) { return; } // Remove the last line drawn (if any). Draw a // line from polygon_last_x and polygon_last_y // to the current pointer position. /* (void)XSetLineAttributes(XtDisplay(da), gc_tint, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da), gc_tint, colors[(int)0x0e]); // yellow XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(polygon_last_x), l16(polygon_last_y), l16(win_x_return), l16(win_y_return)); */ return; } else // Zoom-in function? { // Check mask_return to see if button one is // being pressed down (a drag operation). If // so, we're doing a zoom-in operation and need // to draw a box. 0x100 #ifdef SWAP_MOUSE_BUTTONS if ( (mask_return & 0x400) == 0) // Button3 { #else // SWAP_MOUSE_BUTTONS if ( (mask_return & 0x100) == 0) // Button1 { #endif // SWAP_MOUSE_BUTTONS return; } (void)XSetLineAttributes(XtDisplay(da), gc_tint, 1, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da), gc_tint, colors[(int)0x0e]); // yellow (void)XSetFunction(XtDisplay(da), gc_tint, GXxor); // Check whether we already have a box on screen // that we need to erase. if (zoom_box_x1 != -1) { //fprintf(stderr,"erasing\n"); // Remove the last box drawn via the XOR // function. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x1), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y1), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y1)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x2), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x2), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y2), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y2)); } // Draw a box around the current zoom area. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), // Keep x constant l16(menu_y), l16(menu_x), l16(win_y_return)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), l16(menu_y), // Keep y constant l16(win_x_return), l16(menu_y)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(win_x_return), // Keep x constant l16(menu_y), l16(win_x_return), l16(win_y_return)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), l16(win_y_return), // Keep y constant l16(win_x_return), l16(win_y_return)); // Save the values away so that we can erase the // box later. zoom_box_x1 = menu_x; zoom_box_y1 = menu_y; zoom_box_x2 = win_x_return; zoom_box_y2 = win_y_return; return; } } break; case BadWindow: // A window passed to the function was no // good. fprintf(stderr, "check_pointer_position: BadWindow\n"); return; break; case False: // Pointer is not on the same screen as the // specified window. default: return; break; } } // End of check_pointer_position() // Release ApplicationContext when we are asked to leave // void clear_application_context(void) { if (app_context) { XtDestroyApplicationContext(app_context); } app_context = NULL; } time_t stations_status_time = 0; static int last_alert_on_screen = -1; // This is the periodic process that updates the maps/symbols/tracks. // At the end of the function it schedules itself to be run again. void UpdateTime( XtPointer clientData, XtIntervalId UNUSED(id) ) { Widget w = (Widget) clientData; time_t nexttime; // int do_time; int max; int i; char station_num[30]; char line[MAX_LINE_SIZE+1]; int line_offset = 0; int n; time_t current_time; int data_length; int data_port; unsigned char data_string[MAX_LINE_SIZE]; #ifdef HAVE_DB int got_conn; // holds result from openConnection() #endif // HAVE_DB char temp_file_name[MAX_VALUE]; // do_time = 0; // Start UpdateTime again 10 milliseconds after we've completed. // Note: Setting this too low can cause // some systems // (RedHat/FreeBSD) to spin their wheels a lot, using up great // amounts of CPU time. This is heavily dependent on the true // value of the "HZ" value, which is reported as "100" on some // systems even if the kernel is using another value. #ifdef __CYGWIN__ // Cygwin performance is abysmal if nexttime is lower than 50, almost // acceptable at 200. nexttime = 200; #else // Changed from 2 to 10 to fix high CPU usage problems on // FreeBSD. nexttime = 10; #endif // __CYGWIN__ if (restart_xastir_now) { char bin_path[250]; clear_application_context(); // Restart Xastir in this process space. This is triggered // by receiving a SIGHUP signal to the main process, which // causes the signal handler restart() to run. restart() // shuts down most things nicely and then sets the // restart_xastir_now global variable. // // We need to snag the path to the executable from somewhere // so that we can start up again on a variety of systems. // Trying to get it from argv[0] doesn't work as that ends // up as "xastir" with no path. We therefore get it from // XASTIR_BIN_PATH which we define in configure.ac // // execve("/usr/local/bin/xastir", my_argv, my_envp); xastir_snprintf(bin_path, sizeof(bin_path), "%s/bin/xastir", XASTIR_BIN_PATH); // Restart this Xastir instance execve(bin_path, my_argv, my_envp); } current_time = sec_now(); if (last_updatetime > current_time) { // Time just went in the wrong direction. Sleep for a bit // so that we don't use massive CPU until the time catches // up again. // if (time_went_backwards == 0) { char temp[110]; // This is our first time through UpdateTime() since the // time went in the wrong direction. Dump out a // message to the user. time_went_backwards++; get_timestamp(temp); fprintf(stderr,"\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); fprintf(stderr, "!! System time jumped backwards %d seconds!\n", (int)(last_updatetime - current_time) ); fprintf(stderr, "!! Xastir sleeping, else will use excessive CPU\n"); fprintf(stderr, "!! %s\n", temp); fprintf(stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"); time_went_backwards++; } usleep(1); // Sleep for 1uS. } else { // Time is behaving normally. last_updatetime = current_time; if (time_went_backwards) { fprintf(stderr, "Xastir is done sleeping due to time reversal.\n\n"); } time_went_backwards = 0; } (void)sound_done(); if(display_up) { if(display_up_first == 0) // very first call, do initialization { display_up_first = 1; statusline(langcode("BBARSTA045"), 1); // Loading symbols... load_pixmap_symbol_file("symbols.dat", 0); statusline(langcode("BBARSTA047"), 1); // Initialize my station... my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); da_resize(w, NULL,NULL); // make sure the size is right after startup & create image set_last_position(); // init last map position #ifdef HAVE_DB //uncomment to enable hardcoded test of writing station to db //simpleDbTest(); #endif /* HAVE_DB */ // Restore weather alerts so that we have a clear // picture of the current state. Do this before we // start the interfaces. load_wx_alerts_from_log(); statusline(langcode("BBARSTA048"), 1); // Start interfaces... startup_all_or_defined_port(-1); // start interfaces } else // Not the first time UpdateTime was called. { // Perform the regular updates. if (first_time_run) { first_time_run = 0; Configure_station(NULL, NULL, NULL); } popup_time_out_check(current_time); // clear popup windows after timeout check_statusline_timeout(current_time); // clear statusline after timeout check_station_remove(current_time); // remove old stations check_message_remove(current_time); // remove old messages #ifdef HAVE_LIBSHP purge_shp_hash(current_time); // purge stale rtrees #endif // HAVE_LIBSHP // We need to always calculate the Aloha circle so that // if it is turned on by the user it will be accurate. calc_aloha(current_time); //if ( (new_message_data > 0) && ( (delay_time % 2) == 0) ) //update_messages(0); // Check Messages, no forced update // Check whether it's time to expire some weather // alerts. This function will set redraw_on_new_data // and alert_redraw_on_update if any alerts are expired // from the list. (void)alert_expire(current_time); #ifdef HAVE_GPSMAN // Check whether we've just completed a GPS transfer and // have new maps to draw because of it. This function // can cause a complete redraw of the maps. check_for_new_gps_map(current_time); // Check whether it is time to snag RINO waypoints // again, creating APRS Objects out of them. "0" for // the download interval disables this function. if (RINO_download_interval > 0) { int rino_time = RINO_download_interval * 60; if (last_RINO_download + rino_time < current_time) { last_RINO_download = current_time; GPS_operations(NULL, "7", NULL); } } #endif // HAVE_GPSMAN if (xfontsel_query) { Query_xfontsel_pipe(); } // Check on resize requests if (request_resize) { // if (last_input_event < current_time) { da_resize_execute(w); // } } if (request_new_image) { // if (last_input_event < current_time) { new_image(w); // } } // check on Redraw requests if ( ( (redraw_on_new_data > 1) || (redraw_on_new_data && (current_time > last_redraw + REDRAW_WAIT)) || (current_time > next_redraw) || (pending_ID_message && (current_time > remove_ID_message_time)) ) && !wait_to_redraw) { int temp_alert_count; //fprintf(stderr,"Redraw on new data\n"); // Cause refresh_image() to happen if no other // triggers occurred, but enough time has passed. if (current_time > next_redraw) { alert_redraw_on_update++; } // check if alert_redraw_on_update is set and it has been at least xx seconds since // last weather alert redraw. if ( (alert_redraw_on_update && !pending_ID_message && ( current_time > ( last_alert_redraw + WX_ALERTS_REFRESH_TIME ) )) || (pending_ID_message && (current_time > remove_ID_message_time)) ) { // If we got here because of the ID_message // stuff, clear the variable. if (pending_ID_message && (current_time > remove_ID_message_time)) { pending_ID_message = 0; } //if (alert_redraw_on_update) { //fprintf(stderr,"Alert redraw on update: %ld\t%ld\t%ld\n", // current_time, last_alert_redraw, WX_ALERTS_REFRESH_TIME); if (!pending_ID_message) { refresh_image(da); // Much faster than create_image. (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); // We just refreshed the screen, so don't // try to erase any zoom-in boxes via XOR. zoom_box_x1 = -1; } // Here we use temp_alert_count as a temp holding place for the // count of active alerts. Sound alarm if new alerts are displayed. if ((temp_alert_count = alert_on_screen()) > last_alert_on_screen) { if (sound_play_wx_alert_message) { play_sound(sound_command, sound_wx_alert_message); } #ifdef HAVE_FESTIVAL if (festival_speak_new_weather_alert) { char station_id[50]; xastir_snprintf(station_id, sizeof(station_id), "%s, %d", langcode("SPCHSTR009"), temp_alert_count); SayText(station_id); } #endif // HAVE_FESTIVAL } last_alert_on_screen = temp_alert_count; alert_redraw_on_update = 0; } else { if (!pending_ID_message) { redraw_symbols(w); } } redraw_on_new_data = 0; //next_redraw = current_time+60; // redraw every minute next_redraw = current_time+1; // redraw every 1 second last_redraw = current_time; // This assures that we periodically check for expired alerts // and schedule a screen update if we find any. if (alert_display_request()) // should nor be placed in redraw loop !!??? { alert_redraw_on_update = redraw_on_new_data = 1; // ???? } } if (initial_load) { // Reload saved objects and items from previous runs. // This implements persistent objects. reload_object_item(); #ifdef HAVE_DB // load data from SQL database connections // step through interface list for (i = 0; i < MAX_IFACE_DEVICES; i++) { // if interface is a database and is set to load on start then load if (connections_initialized==0) { fprintf(stderr,"main, initializing connections"); connections_initialized = initConnections(); } if (devices[i].device_type == DEVICE_SQL_DATABASE && devices[i].query_on_startup && port_data[i].status==DEVICE_UP) { // load data if (devices[i].connect_on_startup == 1) { // there should be an open connection already if (debug_level & 4096) { fprintf(stderr,"Opening (in main) connection [%d] with existing connection [%p]",i,&connections[i]); } if (pingConnection(&connections[i])==True) { got_conn = 1; } else { // if (debug_level & 4096) fprintf(stderr,"Ping failed opening new connection [%p]",&connections[i]); got_conn = openConnection(&devices[i],&connections[i]); } } else { if (debug_level & 4096) { fprintf(stderr,"Opening (in main) connection [%d] with new connection [%p]",i,&connections[i]); } got_conn = openConnection(&devices[i],&connections[i]); } if ((got_conn == 1) && (!(connections[i].type==0))) { getAllSimplePositions(&connections[i]); // if connection worked, it is a oneshot upload of data, so we don't // need to set port_data[].active and .status values here. } else { // report error on this port port_data[i].active = DEVICE_IN_USE; port_data[i].status = DEVICE_ERROR; update_interface_list(); } } } #endif /* HAVE_DB */ // Reload any CAD objects from file. This implements // persistent objects. Restore_CAD_Objects_from_file(); initial_load = 0; // All done! } if (Display_.dr_data && ((current_time - sec_last_dr_update) > update_DR_rate) ) { //WE7U: Possible slow-down here w.r.t. dead-reckoning? If //update_DR_rate is too quick, we end up looking through all of the //stations in station list much too often and using a lot of CPU. redraw_on_new_data = 1; sec_last_dr_update = current_time; } // Look for packet data and check port status display_packet_data(); if (delay_time > 15) { interface_status(w); delay_time = 0; // check station lists update_station_scroll_list(); // maybe update lists } delay_time++; // If active HSP ports, check whether we've been sitting // for longer than XX seconds waiting for GPS data. If // so, the GPS is powered-down, lost lock, or become // disconnected. Go back to listening on the TNC port. // if (current_time > (sec_last_dtr + 2)) // 2-3 secs { if (!gps_stop_now) // No GPS strings parsed { // GPS listen timeout! Pop us out of GPS listen // mode on all HSP ports. Listen to the TNC for // a while. //fprintf(stderr,"1:calling dtr_all_set(0)\n"); dtr_all_set(0); sec_last_dtr = current_time; } } // If we parsed valid GPS data, bring all DTR lines back // to normal for all HSP interfaces (set to receive from // TNC now). if (gps_stop_now) { //fprintf(stderr,"2:calling dtr_all_set(0)\n"); dtr_all_set(0); // Go back to TNC listen mode sec_last_dtr = current_time; } // Start the GPS listening process again // check gps start up, GPS on GPSPORT if(current_time > sec_next_gps) { // Reset the gps good-data flag if (gps_stop_now) { gps_stop_now = 0; } //fprintf(stderr,"Check GPS\n"); // Set dtr lines down // works for SERIAL_GPS and SERIAL_TNC_HSP_GPS? // HSP interfaces: Set DTR line for all. DTR will // get reset for each line as valid GPS data gets // parsed on that interface. //fprintf(stderr,"3:calling dtr_all_set(1)\n"); dtr_all_set(1); sec_last_dtr = current_time; // GPS listen timeout for(i=0; i net_next_time) { net_last_time = current_time; net_next_time = net_last_time + 300; // Check every five minutes //net_next_time = net_last_time + 30; // This statement is for debug //fprintf(stderr,"Checking for reconnects\n"); check_ports(); } #ifdef USING_LIBGC // Check for leaks? if(current_time > gc_next_time) { gc_next_time = current_time + 60; // Check every minute //fprintf(stderr,"Checking for leaks\n"); CHECK_LEAKS(); } #endif // USING_LIBGC // Check to see if it is time to spit out data if(!wait_to_redraw) { if (last_time == 0) { // first update next_time = 120; last_time = current_time; // do_time = 1; } else { // check for update //fprintf(stderr,"Checking --- time %ld time to update %ld\n",current_time,last_time+next_time); if(current_time >= (last_time + next_time)) { next_time += next_time; if (next_time > max_transmit_time) { next_time = max_transmit_time; } last_time = current_time; // do_time = 1; } } } // Time to spit out a posit? If emergency_beacon is enabled // change to a relatively fast fixed beacon rate. Should be // more than a 30-second interval though to avoid digipeater // dupe intervals of 30 seconds. // if ( my_position_valid && ( transmit_now || (emergency_beacon && (current_time > (posit_last_time + 60) ) ) || (current_time > posit_next_time && POSIT_rate) ) ) { //fprintf(stderr,"Transmitting posit\n"); // Check for proper symbol in case we're a weather station (void)check_weather_symbol(); posit_last_time = current_time; if (smart_beaconing) { // Schedule next computed posit time based on // speed/turns, etc. posit_next_time = posit_last_time + sb_POSIT_rate; sb_last_heading = sb_current_heading; //fprintf(stderr,"Sending Posit\n"); } else { // Schedule next fixed posit time, set in // Configure->Defaults dialog posit_next_time = posit_last_time + POSIT_rate; } transmit_now = 0; // Output to ALL net/tnc ports that are enabled & have tx enabled //fprintf(stderr,"Sending posit\n"); output_my_aprs_data(); // Decrement the my_position_valid variable if we're // using GPS. This will make sure that positions // are valid, as we'll only get four positions out // maximum per valid GPS position. If the GPS // position goes stale, we'll stop sending posits. // We initialize it to one if we turn on a GPS // interface, so we'll get at the very most one // posit sent out with a stale position, each time // we open a GPS interface. if (using_gps_position && my_position_valid) { my_position_valid--; //fprintf(stderr,"my_position_valid:%d\n",my_position_valid); if (!my_position_valid) // We just went to zero! { // Waiting for GPS data.. statusline(langcode("BBARSTA041"),1); // If the user intends to send posits, GPS // interface is enabled, and we're not // getting GPS data, warn the user that // posits are disabled. if (!transmit_disable && !posit_tx_disable) { popup_message_always(langcode("POPEM00033"), langcode("POPEM00034")); } //fprintf(stderr,"my_position_valid just went to zero!\n"); } } } // if (do_time || transmit_now) { // transmit_now = 0; // // output to ALL net/tnc ports // //fprintf(stderr,"Output data\n"); // output_my_aprs_data(); // } // Must compute rain on a periodic basis, as some // weather daemons don't put out data often enough // to rotate through our queues. // We also refresh the Station_info dialog here if // it is currently drawn. if (current_time >= (last_weather_cycle + 30)) // Every 30 seconds { // Note that we also write timestamps out to all of the log files // from this routine. It works out well with the 30 second update // rate of cycle_weather(). (void)cycle_weather(); last_weather_cycle = current_time; if (station_data_auto_update) { update_station_info(w); // Go refresh the Station Info display } // Time to put out raw WX data ? if (current_time > sec_next_raw_wx) { sec_next_raw_wx = current_time+600; #ifdef TRANSMIT_RAW_WX if (transmit_raw_wx) { tx_raw_wx_data(); } #endif // TRANSMIT_RAW_WX // check wx data last received wx_last_data_check(); } } // is it time to spit out messages? check_and_transmit_messages(current_time); // Is it time to spit out any delayed ack's? check_delayed_transmit_queue(current_time); // Is it time to spit out objects/items? check_and_transmit_objects_items(current_time); // Do we have any new bulletins to display? check_for_new_bulletins(current_time); // Is it time to create a JPG snapshot? if (snapshots_enabled) { (void)Snapshot(); } // Is it time to create a kml dump of all current stations if (kmlsnapshots_enabled) { if (sec_now() > (last_kmlsnapshot + (snapshot_interval * 60)) ) { last_kmlsnapshot = sec_now(); // Set up timer for next time export_trail_as_kml(NULL); } } // Is it time to refresh maps? if ( map_refresh_interval && (current_time > map_refresh_time) ) { // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls // create_image, XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } map_refresh_time = current_time + map_refresh_interval; } // get data from interfaces max=0; // Allow multiple packets to be processed inside this // loop. Well, it was a nice idea anyway. See the // below note. // CAREFUL HERE: If we try to send to the Spider pipes faster than // it's reading from the pipes we corrupt the data out our server // ports. Having too high of a number here or putting too small of // a delay down lower causes our server port to server up junk! while (max < 1 && !XtAppPending(app_context)) { struct timeval tmv; // Check the x_spider server for incoming data if (enable_server_port) { // Check whether the x_spider server pipes have // any data for us. Process if found. // Check the TCP pipe line[0] = '\0'; // Start with line empty n = readline(pipe_tcp_server_to_xastir, line, MAX_LINE_SIZE); if (n == 0) { // Do nothing, empty packet } else if (n < 0) { //fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); } } else // We have a good packet { // Knock off the linefeed at the end line[n-1] = '\0'; if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)line); //fprintf(stderr,"TCP server data:%d: %s\n", n, line); packet_data_add(langcode("WPUPDPD006"), (char *)line, -1); // data_port -1 signifies x_spider // Set port to -2 here to designate that it // came from x_spider. -1 = from a log // file, 0 - 14 = from normal interfaces. decode_ax25_line((char *)line, 'I', -2, // Port -2 signifies x_spider data 1); max++; // Count the number of packets processed } // Check the UDP pipe line[0] = '\0'; // Start with line empty n = readline(pipe_udp_server_to_xastir, line, MAX_LINE_SIZE); if (n == 0) { // Do nothing, empty packet } else if (n < 0) { //fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); } } else // We have a good packet { char temp_call[10]; int skip_decode = 0; // Knock off the linefeed at the end line[n-1] = '\0'; // Check for "TO_INET," prefix, then check // for "TO_RF," prefix. Set appropriate // flags and remove the prefixes if found. // x_spider.c will always put them in that // order if both flags are present, so we // don't need to check for the reverse // order. // Note that this is NOT the "-to_inet" that xastir_udp_client // uses!!! See xspider.c for how that gets parsed/changed. // Set appropriate flags and remove the prefixes if found. if (strncmp(line, "TO_INET,", 8) == 0) { line_offset += 8; // // "TO_INET," found. // This packet should be gated to the internet if and only if // igating is enabled. This may happen automatically as-is, due to // the decode_ax25_line() call below. Check whether that's true. // // We can always add "NOGATE" or "RFONLY" to the path before we dump // it to decode_ax25_line() in order to stop this igating... // } else { // The packet did NOT have "TO_INET," in the string. // Change the packet to add "NOGATE", to the path to // assure it doesn't get igated. // Find the first ':' in the string. Copy the // first part of the string to a new string, add ",NOGATE" // to the path, copy the 2nd part of the string after it. char path[100+1]; char info[100+1]; char *path0 = NULL; char *info0 = NULL; path0 = strtok(line,":"); // Pointer to start of path info0 = strtok(NULL,""); // Pointer to information field xastir_snprintf(path, sizeof(path), "%s", path0); xastir_snprintf(info, sizeof(info), "%s", info0); //fprintf(stderr, "path: %s\n", path); //fprintf(stderr, "info: %s\n", info); //fprintf(stderr, "line: %s\n", line); xastir_snprintf(line, sizeof(line), "%s%s%s", path, ",NOGATE:", info); //fprintf(stderr, "line: %s\n", line); } // Check for "TO_RF," string // Note that this is NOT the "-to_rf" that xastir_udp_client // uses!!! See xspider.c for how that gets parsed/changed. if (strncmp((char *)(line+line_offset), "TO_RF,", 6) == 0) { fprintf(stderr,"Xastir received UDP packet with \"TO_RF,\" prefix\n"); line_offset += 6; // // "TO_RF," found. // This packet should be sent out the local RF ports. If the // callsign matches Xastir's (without the SSID), then send it out // first-person format. If it doesn't, send it out third-party // format? // // Snag FROM callsign and do a non-exact // match on it against "my_callsign" xastir_snprintf(temp_call, sizeof(temp_call), "%s", (char *)(line+line_offset)); if (strchr(temp_call,'>')) { *strchr(temp_call,'>') = '\0'; } // if (is_my_call(temp_call, 0)) { // Match ignoring SSID // exact match // Send to RF as direct packet //fprintf(stderr,"\tBase callsigns Match! Send to RF as direct packet\n"); //fprintf(stderr,"\t%s\n", line); // Change this to go out only RF interfaces so we don't double-up on // the INET interfaces? This would require looping on the // interfaces and checking type and transmit_enable for each, as is // done in output_igate_rf(). If we change to that method, // re-enable the decode_ax25_line() call below. // // Change to a third-party packet. In this case we know we have a // line_offset, so backing up one to insert a char is ok. *(line + line_offset - 1) = '}'; output_my_data( (char *)(line + line_offset - 1), // Raw data line -1, // ports, -1=send out all interfaces 0, // type: 0=cooked, 1=raw 0, // loopback_only 0, // use_igate_path NULL); // path //skip_decode++; igate_msgs_tx++; // } // else { // Send to RF as 3rd party packet //fprintf(stderr, // "\tBase callsigns don't match. Could send to RF as 3rd party packet, but dropping packet for now...\n"); //fprintf(stderr,"\t%s\n", line); // Drop the packet for now, until we get more code added to turn it // into a 3rd party packet /* output_igate_rf(temp_call, addr, path, (char *)(line + line_offset), port, 1, NULL); igate_msgs_tx++; */ //continue; // } } if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)(line + line_offset)); //fprintf(stderr,"UDP server data: %s\n", line); //fprintf(stderr,"\tUDP server data2: %s\n\n", (char *)(line + line_offset)); packet_data_add(langcode("WPUPDPD006"), (char *)(line + line_offset), -1); // data_port -1 signifies x_spider // We don't need the below if we call output_my_data with -1 for the // port, as in that case it calls decode_ax25_line directly. if (!skip_decode) { // Set port to -2 here to designate that it // came from x_spider. -1 = from a log // file, 0 - 14 = from normal interfaces. decode_ax25_line((char *)(line + line_offset), 'I', -2, // Port -2 signifies x_spider data 1); max++; // Count the number of packets processed } } } // End of x_spider server check code //if (begin_critical_section(&data_lock, "main.c:UpdateTime(1)" ) > 0) // fprintf(stderr,"data_lock\n"); // Check the rest of the ports for incoming data. Process up to // 1000 packets here in a loop. data_length = pop_incoming_data(data_string, &data_port); if (data_length != 0) { int data_type; // 0=AX25, 1=GPS // Terminate the string data_string[data_length] = '\0'; //fprintf(stderr,"device_type: %d\n",port_data[data_port].device_type); switch (port_data[data_port].device_type) { // NET Data stream case DEVICE_NET_STREAM: if (log_net_data) log_data(get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD006"), (char *)data_string, data_port); //fprintf(stderr,"\n-1 %s", data_string); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, data_length+1, "%s\n", data_string); //fprintf(stderr,"\n-2 %s", new_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { if (errno != EPIPE) { fprintf(stderr, "UpdateTime: Writen error (Net send x_spider): %d\n", errno); } } //fprintf(stderr,"\n-3 %s", new_string); } // End of x_spider server send code decode_ax25_line((char *)data_string, 'I', data_port, 1); break; // TNC Devices case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: // Try to decode header and checksum. If // bad, break, else continue through to // ASCII logging & decode routines. // Note that the length of data_string // can increase within decode_ax25_header(). if ( !decode_ax25_header( (unsigned char *)data_string, &data_length ) ) { // Had a problem decoding it. Drop // it on the floor. break; } else { // Good decode. Drop through to the // next block to log and decode the // packet. } /* Falls through. */ case DEVICE_SERIAL_TNC: tnc_data_clean((char *)data_string); /* Falls through. */ case DEVICE_AX25_TNC: case DEVICE_NET_AGWPE: if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error (TNC Send x_spider): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); break; case DEVICE_SERIAL_TNC_HSP_GPS: if (port_data[data_port].dtr==1) // get GPS data { char temp[200]; (void)gps_data_find((char *)data_string, data_port); xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } else { // get TNC data if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error(HSP data): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); } break; case DEVICE_SERIAL_TNC_AUX_GPS: tnc_data_clean((char *)data_string); data_type=tnc_get_data_type((char *)data_string, data_port); if (data_type) // GPS Data { char temp[200]; (void)gps_data_find((char *)data_string, data_port); xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } else // APRS Data { if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error(TNC/GPS data): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); } break; // GPS Devices case DEVICE_SERIAL_GPS: case DEVICE_NET_GPSD: //fprintf(stderr,"GPS Data <%s>\n",data_string); (void)gps_data_find((char *)data_string, data_port); { char temp[200]; xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } break; // WX Devices case DEVICE_SERIAL_WX: case DEVICE_NET_WX: if (log_wx) // TODO: Probably only logs to the first 0x00 byte... Need another // logging function that accepts a size, perhaps converting it to // 0x00 or similar as it writes to file. log_data( get_user_base_dir(LOGFILE_WX, temp_file_name, sizeof(temp_file_name)), (char *)data_string); wx_decode(data_string, data_length, data_port); break; default: fprintf(stderr,"Data from unknown source\n"); break; } max++; // Count the number of packets processed } else { max=1000; // Go straight to "max": Exit loop } //if (end_critical_section(&data_lock, "main.c:UpdateTime(2)" ) > 0) // fprintf(stderr,"data_lock\n"); // Do a usleep() here to give the interface threads // time to put something in the queue if they still // have data to process. We also need a delay here // to allow the x_spider code to process packets // we've sent to it. // NOTE: There's a very delicate balance here between x_spider // server, sched_yield(), the delay below, and nexttime. If we feed // packets to the x_spider server faster than it gets to process // them, we end up with blank lines and corrupted lines going to the // connected clients. sched_yield(); // Yield to the other threads if (enable_server_port) { tmv.tv_sec = 0; tmv.tv_usec = 2000; // Delay 2ms (void)select(0,NULL,NULL,NULL,&tmv); } } // End of packet processing loop // END- get data from interface // READ FILE IF OPENED if (read_file) { if (current_time >= next_file_read) { read_file_line(read_file_ptr); next_file_read = current_time + REPLAY_DELAY; } } // END- READ FILE IF OPENED } // If number of stations has changed, update the status // line, but only once per second max. if (station_count != station_count_save && stations_status_time != current_time) { // show number of stations in status line xastir_snprintf(station_num, sizeof(station_num), langcode("BBARSTH001"), currently_selected_stations, station_count); XmTextFieldSetString(text3, station_num); // Set up for next time station_count_save = station_count; stations_status_time = current_time; } check_pointer_position(); } sched_yield(); // Yield the processor to another thread (void)XtAppAddTimeOut(XtWidgetToApplicationContext(w), nexttime, (XtPointer)UpdateTime, (XtPointer)w); } void shut_down_server(void) { // Shut down the server if it was enabled if (tcp_server_pid || udp_server_pid) { // Send a kill to the main server process if (tcp_server_pid) { kill(tcp_server_pid, SIGHUP); } if (udp_server_pid) { kill(udp_server_pid, SIGHUP); } wait(NULL); // Reap the status of the process // Send to all processes in our process group. This will // cause the server and all of its children to die. Also // causes Xastir to die! Don't do it! //kill(0, 1); sleep(1); // Send a more forceful kill signal in case the "nice" kill // signal didn't work. if (tcp_server_pid) { kill(tcp_server_pid, SIGKILL); } if (udp_server_pid) { kill(udp_server_pid, SIGKILL); } } } // This is the SIGHUP handler. We restart Xastir if we receive a // SIGHUP, hopefully with the same environment that the original // Xastir had. We set a global variable, then UpdateTime() is the // process that actually calls execve() in order to replace our // current process with the new one. This assures that the signal // handler gets reset. We can't call execve() from inside the // signal handler and have the restart work more than once. // // This function should be nearly identical to the quit() function // below. // // One strangeness is that this routine gets called when any of the // spawned processes get a SIGHUP also, which means when we shut // down the TCP/UDP servers or similar. For some reason it still // appears to work, even though restart() gets called multiple // times when we shut down Xastir or the servers. We probably need // to call signal() from outside any signal handlers to tell it to // ignore further SIGHUP's. // static void restart(int UNUSED(sig) ) { char temp_file_name[MAX_VALUE]; // if (debug_level & 1) fprintf(stderr,"Shutting down Xastir...\n"); save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); #ifdef USE_PID_FILE_CHECK // remove the PID file unlink(get_user_base_dir("xastir.pid", temp_file_name, sizeof(temp_file_name))); #endif #ifdef HAVE_LIBCURL curl_global_cleanup(); #endif #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC // if (debug_level & 1) fprintf(stderr,"Attempting to restart Xastir...\n"); // Set the global variable which tells UpdateTime() to do a // restart. // restart_xastir_now++; } static void quit(int sig) { char temp_file_name[MAX_VALUE]; if(debug_level & 15) { fprintf(stderr,"Caught %d\n",sig); } save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); #ifdef USE_PID_FILE_CHECK // remove the PID file unlink(get_user_base_dir("xastir.pid",temp_file_name, sizeof(temp_file_name))); #endif if (debug_level & 1) { fprintf(stderr,"Exiting Xastir...\n"); } #ifdef HAVE_LIBCURL curl_global_cleanup(); #endif clear_application_context(); #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC exit(sig); // Main exit from the program } #ifdef USE_PID_FILE_CHECK static int pid_file_check(int hold) { int killret=0; int other_pid=0; char temp[32] ; FILE * PIDFILE ; char temp_file_name[MAX_VALUE]; /* Save our PID */ char pidfile_name[MAX_FILENAME]; xastir_snprintf(pidfile_name, sizeof(pidfile_name), "%s", get_user_base_dir("xastir.pid", temp_file_name, sizeof(temp_file_name))); if (filethere(pidfile_name)) { fprintf(stderr,"Found pid file: %s\n",pidfile_name); PIDFILE=fopen(pidfile_name,"r"); if (PIDFILE!=NULL) { if(!feof(PIDFILE)) { (void)get_line(PIDFILE,temp,32); } (void)fclose(PIDFILE); other_pid=atoi(temp); } else { fprintf(stderr,"Couldn't open file: %s\n", pidfile_name); } // send a ping killret = kill(other_pid,0); #ifdef N8YSZ fprintf(stderr, "other_pid = <%d> killret == <%d> errno == <%d>\n", other_pid,killret,errno); #endif if ((killret == -1) && (errno == ESRCH ) && !hold) { fprintf(stderr, "Other Xastir process, pid: %d does not appear be running. \n", other_pid); // nuke from orbit if (unlink(pidfile_name)) { fprintf(stderr,"Error unlinking pid file: %s, %d\n", pidfile_name,errno); } } else { fprintf(stderr, "Other Xastir process, pid: %d may be running. Exiting..\n", other_pid); #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC exit(-1); // Quick exit from the program } } else { // if we're here - ok to truncate & open pidfile. #ifdef N8YSZ fprintf(stderr, "other_pid = <%d> killret == <%d> errno == <%d>\n", other_pid,killret,errno); #endif PIDFILE = fopen(pidfile_name,"w"); if(PIDFILE != NULL) { fprintf(PIDFILE, "%d",getpid()); (void) fclose (PIDFILE); return(0); } else { fprintf(stderr, "Error opening pidfile: %s\n", strerror(errno) ); return(errno); } return(0); } return(0); } // end pid_file_check #endif /* handle segfault signal */ void segfault(int UNUSED(sig) ) { fprintf(stderr, "Caught Segfault! Xastir will terminate\n"); fprintf(stderr, "Previous incoming line was: %s\n", incoming_data_copy_previous); fprintf(stderr, " Last incoming line was: %s\n", incoming_data_copy); if (dangerous_operation[0] != '\0') { fprintf(stderr, "Possibly died at: %s\n", dangerous_operation); } fprintf(stderr, "%02d:%02d:%02d\n", get_hours(), get_minutes(), get_seconds() ); shut_down_server(); quit(-1); } /* Added by KB4AMA Handle USR1 signal. This will cause a snapshot to be generated. */ #ifndef OLD_PTHREADS void usr1sig(int sig) { if (debug_level & 512) { fprintf(stderr, "Caught Signal USR1, Doing a snapshot! Signal No %d\n", sig); } last_snapshot = 0; (void)Snapshot(); } void usr2sig(int sig) { if (debug_level & 512) { fprintf(stderr, "Caught Signal USR2, Transmitting now! Signal No %d\n", sig); } transmit_now = 1; } #endif // OLD_PTHREADS /********************* dialog position *************************/ void pos_dialog(Widget w) { static Position x,y; Dimension wd, ht; int max_x, max_y; XtVaGetValues(appshell, XmNx, &x, XmNy, &y, NULL); XtVaGetValues(appshell, XmNwidth, &wd, XmNheight, &ht, NULL); if (x > 1280) // We sometimes get strange values for X/Y { x = 300; } if (y > 1024) // We sometimes get strange values for X/Y { y = 200; } if (wd > 1280) // And for width and height { wd = 640; } if (ht > 1024) // And for width and height { ht = 480; } max_x = x + wd - (wd / 5); // max_y = y + ht - (ht / 5); max_y = y + ht/3; // Check for proper values for last stored position if ( (last_popup_x < x) || (last_popup_y < y) || (last_popup_x > max_x) || (last_popup_y > max_y) ) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } else { last_popup_x += 10; // Increment slightly for next dialog last_popup_y += 20; // Increment slightly for next dialog } if ((last_popup_y+50) > max_y) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } if ((last_popup_x+50) > max_x) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } #ifdef FIXED_DIALOG_STARTUP XtVaSetValues(w,XmNx,x,XmNy,y,NULL); #else XtVaSetValues(w,XmNx,last_popup_x,XmNy,last_popup_y,NULL); #endif // FIXED_DIALOG_STARTUP //fprintf(stderr,"max_x:%d max_y:%d x:%d y:%d wd:%d ht:%d last_x:%d last_y:%d\n", //max_x,max_y,x,y,wd,ht,last_popup_x,last_popup_y); } /********************* resize_dialog *************************/ // // Resize dialog to fit screen size or form, whichever is smaller. // If screen size is smaller, also position dialog at 0,0. // // Don't forget window decorations! Setting a dialog to 320x240 ends // up with a total dialog of 326x267 on one Linux w/xfwm4 window // manager and certain selected fonts. This is 6 more in the X and 27 // more in the Y direction. We need to either add in the size of the // window decorations or activate the full-screen button on the // dialog. // // Found this which talks about getting sizes from parent and // grandparent of window to compute decoration sizes: // https://ubuntuforums.org/showthread.php?t=2048596 // Tried the above, plus several other methods: Couldn't come up with // a general method for calculating the size of the title bar portion // of the decorations. In particular the parent numbers return full // screen size and can't get the grandparent window. // // NOTE: 6, 27, and 10 numbers below were determined experimentally // on one system. Your mileage may vary based on window manager and // fonts selected. // void resize_dialog( Widget form, Widget dialog) { Dimension form_width, form_height; Dimension final_width, final_height; Dimension screen_width, screen_height; int set_to_origin = 0; // Fetch form size. Note that this will NOT include // the sizes of window decorations and title bar. XtVaGetValues(form, XmNwidth, &form_width, XmNheight, &form_height, NULL); // Fetch screen size screen_height = DisplayHeight(XtDisplay(appshell), DefaultScreen(display)); screen_width = DisplayWidth(XtDisplay(appshell), DefaultScreen(display)); // Simulate a small screen for testing: //screen_width = 320; //screen_height = 240; // NOTE: 27 and 6 numbers below were discovered by capturing a // known window size with XV, then examining the image with (any // of) "xv" / "gimp" / "identify" to determine final size with // decorations. On one system it was 3 pixels each side plus 21 // more for the titlebar, adding up to +6 left/right and +27 // top/bottom. This will vary per window manager, WM settings, // and fonts selected. // Find smaller of the two heights: // If dialog height is larger than screen, make smaller which // also activates the scrollbars. if ( (form_height+27) > screen_height) { // Set form height to screen height minus decorations and move // to origin final_height = screen_height-27; set_to_origin++; } else { // Dialog fits within the screen. final_height = form_height+10; } // Find smaller of the two widths: // If dialog width is larger than screen, make smaller which // also activates the scrollbars. if ( (form_width+6) > screen_width) { // Set form width to screen width minus decorations // and move to origin final_width = screen_width-6; set_to_origin++; } else { // Dialog fits within the screen. final_width = form_width+10; } if (set_to_origin) { // Set dialog's origin to 0,0. // Set width/height to the smaller of the two sizes. // Set max width/height to size of original form. // 10 was determined experimentally. XtVaSetValues(dialog, XmNx, 0, XmNy, 0, XmNwidth, final_width, XmNheight, final_height, XmNmaxWidth,form_width+10, XmNmaxHeight,form_height+10, NULL); } else { // Set width/height to the smaller of the two sizes. // Set max width/height to size of original form. // 10 was determined experimentally. XtVaSetValues(dialog, XmNwidth, final_width, XmNheight, final_height, XmNmaxWidth,form_width+10, XmNmaxHeight,form_height+10, NULL); } if (debug_level & 1) { fprintf(stderr,"Form size: X:%d\tY:%d\n", form_width, form_height); fprintf(stderr,"Screen size: X:%i, Y:%i\n", screen_width, screen_height); fprintf(stderr,"Setting dialog to width:%i, height:%i\n", final_width, final_height); if (set_to_origin) { fprintf(stderr,"Setting dialog to position 0,0\n"); } } } /********************* fix dialog size *************************/ void fix_dialog_size(Widget w) { Dimension wd, ht; if (XtIsRealized(w)) { XtVaGetValues(w, XmNwidth, &wd, XmNheight, &ht, NULL); XtVaSetValues(w, XmNminWidth,wd, XmNminHeight,ht, XmNmaxWidth,wd, XmNmaxHeight,ht, NULL); } } /**************************************** Button CallBacks *************************************/ /***********************************************************************************************/ /* * Button callback for 1 out of 2 selection */ void on_off_switch(int switchpos, Widget first, Widget second) { if(switchpos) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); } } /* * Button callback for 1 out of 3 selection */ void sel3_switch(int switchpos, Widget first, Widget second, Widget third) { if(switchpos == 2) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); } else if(switchpos == 1) { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); XtSetSensitive(third, TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, FALSE); } } /* * Button callback for 1 out of 4 selection */ void sel4_switch(int switchpos, Widget first, Widget second, Widget third, Widget fourth) { if(switchpos == 3) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, TRUE); } else if(switchpos == 2) { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, TRUE); } else if(switchpos == 1) { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, FALSE); XtSetSensitive(fourth, TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, FALSE); } } // Called by UpdateTime when request_new_image flag is set. void new_image(Widget da) { busy_cursor(appshell); // Reset flags interrupt_drawing_now = 0; request_new_image = 0; // Set up floating point lat/long values to match Xastir // coordinates (speeds things up when dealing with lat/long // values later). convert_from_xastir_coordinates(&f_center_longitude, &f_center_latitude, center_longitude, center_latitude); if (create_image(da)) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } display_zoom_status(); } } /* * Keep map in real world space, readjust center and scaling if necessary */ void check_range(void) { Dimension width, height; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); // Check the window itself to see if our new y-scale fits it // if ((height*new_scale_y) > 64800000l) { // Center between 90°N and 90°S new_mid_y = 64800000l/2; // Adjust y-scaling so that we fit perfectly in the window new_scale_y = 64800000l / height; } if ((new_mid_y < (height*new_scale_y)/2)) { new_mid_y = (height*new_scale_y)/2; // upper border max 90°N } if ((new_mid_y + (height*new_scale_y)/2) > 64800000l) { new_mid_y = 64800000l-((height*new_scale_y)/2); // lower border max 90°S } // Adjust scaling based on latitude of new center new_scale_x = get_x_scale(new_mid_x,new_mid_y,new_scale_y); // recalc x scaling depending on position if (debug_level & 512) { fprintf(stderr,"checkrange- x:%ld\ty:%ld\n\n",new_scale_x,new_scale_y); } // // scale_x will always be bigger than scale_y, so no problem here... // if ((width*new_scale_x) > 129600000l) { // // Center between 180°W and 180°E // new_mid_x = 129600000l/2; // } // The below code causes the map image to snap to the left or right // of the display. I'd rather see the scale factor changed so that // the map fits perfectly left/right in the display, so that we // cannot go past the edges of the earth. Change the code to work // this way later. We'll have to compute new_y_scale from the // new_x_scale once we scale X appropriately, then will probably // have to test the y scaling again? /* // Check against left border if ((new_mid_x < (width*new_scale_x)/2)) { // This will cause the map image to snap to the left of the // display. new_mid_x = (width*new_scale_x)/2; // left border max 180°W } else { // Check against right border if ((new_mid_x + (width*new_scale_x)/2) > 129600000l) // This will cause the map image to snap to the right of // the display. new_mid_x = 129600000l-((width*new_scale_x)/2); // right border max 180°E } */ // long NW_corner_longitude; // Longitude at top NW corner of map screen // long NW_corner_latitude; // Latitude at top NW corner of map screen /* if (NW_corner_longitude < 0l) { // fprintf(stderr,"left\n"); NW_corner_longitude = 0l; // New left viewpoint edge new_mid_x = 0l + ((width*new_scale_x) / 2); // New midpoint } if ( (NW_corner_longitude + (width*new_scale_x) ) > 129600000l) { // fprintf(stderr,"right\n"); NW_corner_longitude = 129600000l - (width*new_scale_x); // New left viewpoint edge new_mid_x = 129600000l - ((width*new_scale_x) / 2); // New midpoint } */ // Find the four corners of the map in the new scale system. Make // sure they are on the display, but not well inside the borders of // the display. // We keep getting center_longitude out of range when zooming out // and having the edge of the world map to the right of the middle // of the window. This shows up in new_image() above during the // convert_from_xastir_coordinates() call. new_mid_x is the data of // interest in this routine. } /* * Display a new map view after checking the view and scaling */ void display_zoom_image(int recenter) { Dimension width, height; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); //fprintf(stderr,"Before, x: %lu, y: %lu\n",new_scale_x,new_scale_y); check_range(); // keep map inside world and calc x scaling //fprintf(stderr,"After, x: %lu, y: %lu\n\n",new_scale_x,new_scale_y); if (new_mid_x != center_longitude || new_mid_y != center_latitude || new_scale_x != scale_x || new_scale_y != scale_y) // If there's been a change in zoom or center { set_last_position(); if (recenter) { center_longitude = new_mid_x; // new map center center_latitude = new_mid_y; } scale_x = new_scale_x; scale_y = new_scale_y; setup_in_view(); // update "in view" flag for all stations // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // last_input_event = sec_now() + 2; } else // No change in zoom or center. Don't update ANYTHING. { } } void Zoom_in( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y / 2; if (new_scale_y < 1) { new_scale_y = 1; // don't go further in } display_zoom_image(1); // check range and do display, recenter } } void Zoom_in_no_pan( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude; new_scale_y = scale_y / 2; if (new_scale_y < 1) { new_scale_y = 1; // don't go further in, scale_x always bigger than scale_y } display_zoom_image(0); // check range and do display, keep center } } void Zoom_out( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); if (width*scale_x < 129600000l || height*scale_y < 64800000l) { new_scale_y = scale_y * 2; } else { new_scale_y = scale_y; // don't zoom out if whole world could be shown } display_zoom_image(1); // check range and do display, recenter } } void Zoom_out_no_pan( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude; if (width*scale_x < 129600000l || height*scale_y < 64800000l) { new_scale_y = scale_y * 2; } else { new_scale_y = scale_y; // don't zoom out if whole world could be shown } display_zoom_image(0); // check range and do display, keep center } } void Custom_Zoom_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); custom_zoom_dialog = (Widget)NULL; } static Widget custom_zoom_zoom_level; void Custom_Zoom_do_it( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp_ptr; temp_ptr = XmTextFieldGetString(custom_zoom_zoom_level); scale_y = atoi(temp_ptr); XtFree(temp_ptr); new_scale_y = scale_y; display_zoom_image(1); } // Function to bring up a dialog. User can then select zoom for the // display directly. // void Custom_Zoom( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { static Widget pane, form, button_ok, button_cancel, zoom_label; // Arg al[50]; /* Arg List */ // unsigned int ac = 0; /* Arg Count */ Atom delw; char temp[50]; if(!custom_zoom_dialog) { // "Custom Zoom" custom_zoom_dialog = XtVaCreatePopupShell(langcode("POPUPMA034"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, custom_zoom_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Zoom Level" zoom_label = XtVaCreateManagedWidget(langcode("POPUPMA004"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); custom_zoom_zoom_level = XtVaCreateManagedWidget("Custom_Zoom zoom_level", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,6, XmNwidth,((6*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Custom_Zoom_destroy_shell, custom_zoom_dialog); XtAddCallback(button_ok, XmNactivateCallback, Custom_Zoom_do_it, NULL); pos_dialog(custom_zoom_dialog); delw = XmInternAtom(XtDisplay(custom_zoom_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(custom_zoom_dialog, delw, Custom_Zoom_destroy_shell, (XtPointer)custom_zoom_dialog); // Snag the current zoom value, convert them to // displayable values, and fill in the fields. xastir_snprintf(temp, sizeof(temp), "%ld", scale_y); XmTextFieldSetString(custom_zoom_zoom_level, temp); XtManageChild(form); XtManageChild(pane); XtPopup(custom_zoom_dialog,XtGrabNone); fix_dialog_size(custom_zoom_dialog); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(custom_zoom_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(custom_zoom_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(custom_zoom_dialog), XtWindow(custom_zoom_dialog)); } } void Zoom_level( Widget w, XtPointer clientData, XtPointer calldata) { Dimension width, height; int level; level=atoi((char *)clientData); if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); switch(level) { case(1): new_scale_y = 1; break; case(2): new_scale_y = 16; break; case(3): new_scale_y = 64; break; case(4): new_scale_y = 256; break; case(5): new_scale_y = 1024; break; case(6): new_scale_y = 8192; break; case(7): //WE7U // Here it'd be good to calculate what zoom level the entire world // would best fit in, instead of fixing the scale to a particular // amount. Figure out which zoom level would fit in the X and the Y // direction, and then pick the higher zoom level of the two (to // make sure the world fits in both). We should probably center at // 0.0N/0.0W as well. new_scale_y = 500000; // Center on Earth (0/0) // new_mid_x = 12900000l / 2; // new_mid_y = 6480000l / 2; break; case(8): // 10% out new_scale_y = (int)(scale_y * 1.1); if (new_scale_y == scale_y) { new_scale_y++; } break; case(9): // 10% in new_scale_y = (int)(scale_y * 0.9); // Don't allow the user to go in further than zoom 1 if (new_scale_y < 1) { new_scale_y = 1; } break; // Pop up a new dialog that allows the user to select // the zoom level, then causes that zoom level and the // right-click mouse location to take effect on the map // window. Similar to the Center_Zoom function but with // the mouse coordinates instead of the center of the // screen. case(10): // Custom Zoom Level // Pop up a new dialog that allows the user to // select the zoom level, then causes that zoom // level and the right-click mouse location to take // effect on the map window. Similar to the // Center_Zoom function but with the mouse // coordinates instead of the center of the screen. // Set up new_scale_y for whatever custom zoom level // the user has chosen, then call // display_zoom_image() from the callback there. // Custom_Zoom( w, clientData, calldata); return; break; default: break; } display_zoom_image(1); // check range and do display, recenter } } void Pan_ctr( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_up( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude - (height*scale_y/4); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_up_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude - (height*scale_y/10); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_down( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude + (height*scale_y/4); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_down_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude + (height*scale_y/10); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_left( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - (width*scale_x/4); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_left_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - (width*scale_x/10); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_right( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude + (width*scale_x/4); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_right_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude + (width*scale_x/10); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Center_Zoom_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData)) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); center_zoom_dialog = (Widget)NULL; } static Widget center_zoom_latitude, center_zoom_longitude, center_zoom_zoom_level; void Center_Zoom_do_it( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { unsigned long x, y; char *temp_ptr; temp_ptr = XmTextFieldGetString(center_zoom_latitude); f_center_latitude = atof(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(center_zoom_longitude); f_center_longitude = atof(temp_ptr); XtFree(temp_ptr); //Convert to Xastir coordinate system for lat/long convert_to_xastir_coordinates(&x, &y, f_center_longitude, f_center_latitude); temp_ptr = XmTextFieldGetString(center_zoom_zoom_level); scale_y = atoi(temp_ptr); XtFree(temp_ptr); new_mid_x = x; new_mid_y = y; new_scale_y = scale_y; display_zoom_image(1); } void Go_Home( Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { DataRow *p_station; if (!map_lock_pan_zoom) { if (search_station_name(&p_station,my_callsign,1)) { set_map_position(w, p_station->coord_lat, p_station->coord_lon); } } } // Function to bring up a dialog. User can then select the center // and zoom for the display directly. // // Later it would be nice to have a "Calc" button so that the user // could input lat/long in any of the supported formats. Right now // it is DD.DDDD format only. // void Center_Zoom( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer calldata) { static Widget pane,form, button_ok, button_cancel, lat_label, lon_label, zoom_label; // Arg al[50]; /* Arg List */ // unsigned int ac = 0; /* Arg Count */ Atom delw; char temp[50]; if(!center_zoom_dialog) { // "Center & Zoom" center_zoom_dialog = XtVaCreatePopupShell(langcode("POPUPMA026"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, center_zoom_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Latitude" lat_label = XtVaCreateManagedWidget(langcode("POPUPMA027"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_latitude = XtVaCreateManagedWidget("Center_Zoom latitude", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, lat_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); // "Longitude" lon_label = XtVaCreateManagedWidget(langcode("POPUPMA028"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lat_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_longitude = XtVaCreateManagedWidget("Center_Zoom longitude", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, lat_label, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, lon_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); // "Zoom Level" zoom_label = XtVaCreateManagedWidget(langcode("POPUPMA004"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lon_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_zoom_level = XtVaCreateManagedWidget("Center_Zoom zoom_level", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, lon_label, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Center_Zoom_destroy_shell, center_zoom_dialog); XtAddCallback(button_ok, XmNactivateCallback, Center_Zoom_do_it, NULL); pos_dialog(center_zoom_dialog); delw = XmInternAtom(XtDisplay(center_zoom_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(center_zoom_dialog, delw, Center_Zoom_destroy_shell, (XtPointer)center_zoom_dialog); if (center_zoom_override) // We've found a Map View { // "eyeball" object and are // doing a center/zoom based on // that object's info. Grab the // pointer to the object which // is in calldata. DataRow *p_station = (DataRow *)calldata; float f_latitude, f_longitude; int range; Dimension width, height; long x, x0, y, y0; double x_miles, y_miles, distance; char temp_course[10]; double scale_factor; long my_scale_y; int fell_off = 0; //fprintf(stderr,"Map View Object: %s\n",p_station->call_sign); center_zoom_override = 0; // Snag the objects values, convert them to displayable // values, and fill in the fields. convert_from_xastir_coordinates(&f_longitude, &f_latitude, p_station->coord_lon, p_station->coord_lat); xastir_snprintf(temp, sizeof(temp), "%f", f_latitude); XmTextFieldSetString(center_zoom_latitude, temp); xastir_snprintf(temp, sizeof(temp), "%f", f_longitude); XmTextFieldSetString(center_zoom_longitude, temp); // Compute the approximate zoom level we need from the // range value in the object. Range is in miles. range = atoi(&p_station->power_gain[3]); // We should be able to compute the distance across the // screen that we currently have, then compute an // accurate zoom level that will give us the range we // want. // Find out the screen values XtVaGetValues(da,XmNwidth, &width, XmNheight, &height, NULL); // Convert points to Xastir coordinate system // X x = center_longitude - ((width *scale_x)/2); // Check for the edge of the earth if (x < 0) { x = 0; fell_off++; // Fell off the edge of the earth } x0 = center_longitude; // Center of screen // Y y = center_latitude - ((height*scale_y)/2); // Check for the edge of the earth if (y < 0) { y = 0; fell_off++; // Fell off the edge of the earth } y0 = center_latitude; // Center of screen // Compute distance from center to each edge // X distance. Keep Y constant. x_miles = cvt_kn2len * calc_distance_course(y0, x0, y0, x, temp_course, sizeof(temp_course)); // Y distance. Keep X constant. y_miles = cvt_kn2len * calc_distance_course(y0, x0, y, x0, temp_course, sizeof(temp_course)); // Choose the smaller distance if (x_miles < y_miles) { distance = x_miles; } else { distance = y_miles; } //fprintf(stderr,"Current screen range: %f\n", distance); //fprintf(stderr,"Desired screen range: %d\n", range); // Note that these numbers will be off if we're zoomed out way too // far (edges of the earth are inside the screen view). // Now we know the range of the current screen // (distance) in miles. Compute what we need from // "distance" (screen) and "range" (object) in order to // get a scale factor we can apply to our zoom numbers. if (distance < range) { //fprintf(stderr,"Zooming out\n"); scale_factor = (range * 1.0)/distance; // fprintf(stderr,"Scale Factor: %f\n", scale_factor); my_scale_y = (long)(scale_y * scale_factor); } else // distance > range { //fprintf(stderr,"Zooming in\n"); scale_factor = distance/(range * 1.0); //fprintf(stderr,"Scale Factor: %f\n", scale_factor); my_scale_y = (long)(scale_y / scale_factor); } if (my_scale_y < 1) { my_scale_y = 1; } //fprintf(stderr,"my_scale_y: %ld\n", my_scale_y); xastir_snprintf(temp, sizeof(temp), "%ld", my_scale_y); XmTextFieldSetString(center_zoom_zoom_level, temp); } else { // Normal user-initiated center/zoom function // Snag the current lat/long/center values, convert them to // displayable values, and fill in the fields. xastir_snprintf(temp, sizeof(temp), "%f", f_center_latitude); XmTextFieldSetString(center_zoom_latitude, temp); xastir_snprintf(temp, sizeof(temp), "%f", f_center_longitude); XmTextFieldSetString(center_zoom_longitude, temp); xastir_snprintf(temp, sizeof(temp), "%ld", scale_y); XmTextFieldSetString(center_zoom_zoom_level, temp); } XtManageChild(form); XtManageChild(pane); XtPopup(center_zoom_dialog,XtGrabNone); fix_dialog_size(center_zoom_dialog); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(center_zoom_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(center_zoom_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(center_zoom_dialog), XtWindow(center_zoom_dialog)); } } void SetMyPosition( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; long my_new_latl, my_new_lonl; // check for fixed station //if ( (output_station_type == 0) || (output_station_type > 3)) { // popup_message( "Modify fixed position", "Are you sure you want to modify your position?"); //} // check for position ambiguity if ( position_amb_chars > 0 ) // popup warning that ambiguity is on { popup_message_always(langcode("POPUPMA043"), // "Modify ambiguous position" langcode("POPUPMA044") ); // "Position ambiguity is on, your new position may appear to jump." } if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); my_new_lonl = (center_longitude - ((width *scale_x)/2) + (menu_x*scale_x)); my_new_latl = (center_latitude - ((height*scale_y)/2) + (menu_y*scale_y)); // Check if we are still on the planet... if ( my_new_latl > 64800000l ) { my_new_latl = 64800000l; } if ( my_new_latl < 0 ) { my_new_latl = 0; } if ( my_new_lonl > 129600000l ) { my_new_lonl = 129600000l; } if ( my_new_lonl < 0 ) { my_new_lonl = 0; } convert_lon_l2s( my_new_lonl, my_long, sizeof(my_long), CONVERT_HP_NOSP); convert_lat_l2s( my_new_latl, my_lat, sizeof(my_lat), CONVERT_HP_NOSP); // Update my station data with the new lat/lon my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; } } void Window_Quit( Widget UNUSED(w), XtPointer UNUSED(client), XtPointer UNUSED(calldata) ) { quit(0); } void Menu_Quit( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { quit(0); } void save_state( Widget UNUSED(w), XtPointer UNUSED(client), XtPointer calldata) { if (((XtCheckpointToken)calldata)->shutdown) { save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); } } // Turn on or off map border, callback from map_border_button. void Map_border_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { draw_labeled_grid_border = TRUE; } else { draw_labeled_grid_border = FALSE; } redraw_symbols(da); } void Grid_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { long_lat_grid = atoi(which); } else { long_lat_grid = 0; } if (long_lat_grid) { statusline(langcode("BBARSTA005"),1); // Map Lat/Long Grid On XtSetSensitive(map_border_button,TRUE); } else { statusline(langcode("BBARSTA006"),2); // Map Lat/Long Grid Off XtSetSensitive(map_border_button,FALSE); } redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } // Callback from menu buttons that allow user to turn on or off the // global display of CAD objects and their metadata on the map. void CAD_draw_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // turn on or off display of cad objects if (strcmp(which,"CAD_draw_objects")==0) { CAD_draw_objects = state->set; } // turn on or off display of standard metadata if (strcmp(which,"CAD_show_label")==0) { CAD_show_label = state->set; } if (strcmp(which,"CAD_show_raw_probability")==0) { CAD_show_raw_probability = state->set; } if (strcmp(which,"CAD_show_comment")==0) { CAD_show_comment = state->set; } if (strcmp(which,"CAD_show_area")==0) { CAD_show_area = state->set; } // redraw objects on the current base maps redraw_symbols(da); } void Map_lock_pan_zoom_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_lock_pan_zoom = atoi(which); XtSetSensitive(zoom_in_menu, FALSE); XtSetSensitive(zoom_out_menu, FALSE); XtSetSensitive(pan_left_menu, FALSE); XtSetSensitive(pan_up_menu, FALSE); XtSetSensitive(pan_down_menu, FALSE); XtSetSensitive(pan_right_menu, FALSE); } else { map_lock_pan_zoom = 0; XtSetSensitive(zoom_in_menu, TRUE); XtSetSensitive(zoom_out_menu, TRUE); XtSetSensitive(pan_left_menu, TRUE); XtSetSensitive(pan_up_menu, TRUE); XtSetSensitive(pan_down_menu, TRUE); XtSetSensitive(pan_right_menu, TRUE); } } void Map_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { disable_all_maps = atoi(which); } else { disable_all_maps = 0; } request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_auto_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_auto_maps = atoi(which); XtSetSensitive(map_auto_skip_raster_button,TRUE); } else { map_auto_maps = 0; XtSetSensitive(map_auto_skip_raster_button,FALSE); } re_sort_maps = 1; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } if (map_auto_maps) { statusline(langcode("BBARSTA007"),1); // The use of Auto Maps is now on } else { statusline(langcode("BBARSTA008"),2); // The use of Auto Maps is now off } } void Map_auto_skip_raster_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { auto_maps_skip_raster = atoi(which); } else { auto_maps_skip_raster = 0; } re_sort_maps = 1; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_levels_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_color_levels = atoi(which); } else { map_color_levels = 0; } if (map_color_levels) { statusline(langcode("BBARSTA009"),1); // The use of Auto Maps is now on } else { statusline(langcode("BBARSTA010"),2); // The use of Auto Maps is now off } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_labels_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_labels = atoi(which); } else { map_labels = 0; } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_fill_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_color_fill = atoi(which); } else { map_color_fill = 0; } if (map_color_fill) { statusline(langcode("BBARSTA009"),1); // The use of Map Color Fill is now On } else { statusline(langcode("BBARSTA010"),1); // The use of Map Color Fill is now Off } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_background( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int bgcolor; int i; bgcolor=atoi((char *)clientData); if(display_up) { for (i=0; i<12; i++) { if (i == bgcolor) { XtSetSensitive(map_bgcolor[i],FALSE); } else { XtSetSensitive(map_bgcolor[i],TRUE); } } map_background_color=bgcolor; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } #if !defined(NO_GRAPHICS) void Raster_intensity(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { float my_intensity; int i; my_intensity=atof((char *)clientData); if(display_up) { for (i=0; i<11; i++) { if (i == (int)((float)(my_intensity * 10.01)) ) { XtSetSensitive(raster_intensity[i],FALSE); } else { XtSetSensitive(raster_intensity[i],TRUE); } //fprintf(stderr,"Change to index: %d\n", (int)((float)(my_intensity * 10.01))); } raster_map_intensity=my_intensity; //fprintf(stderr,"raster_map_intensity = %f\n", raster_map_intensity); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } #endif // NO_GRAPHICS void Map_station_label( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int style; style=atoi((char *)clientData); if(display_up) { letter_style = style; sel4_switch(letter_style,map_station_label3,map_station_label2,map_station_label1,map_station_label0); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } } void Map_icon_outline( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int style; style=atoi((char *)clientData); if(display_up) { icon_outline_style = style; sel4_switch(icon_outline_style,map_icon_outline3,map_icon_outline2,map_icon_outline1,map_icon_outline0); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } statusline( langcode("BBARSTA046"), 1); // Reloading symbols... load_pixmap_symbol_file("symbols.dat", 1); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } void Map_wx_alerts_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { wx_alert_style = !(atoi(which)); } else { wx_alert_style = 1; } if (display_up) { refresh_image(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } } void Index_maps_on_startup_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { index_maps_on_startup = 1; } else { index_maps_on_startup = 0; } } void TNC_Transmit_now( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { transmit_now = 1; /* toggle transmission of station now*/ } ///////////////////////////////////////////////////////////////////// // GPS operations ///////////////////////////////////////////////////////////////////// #ifdef HAVE_GPSMAN // Function to process the RINO.gpstrans file. We'll create APRS // objects out of them as if our own callsign created them. Lines // in the file look like this (spaces removed): // // W N3EG3 20-JUN-02 17:55 07/08/2004 13:03:29 46.1141682 -122.9384817 // W N3JGI 20-JUN-02 18:29 07/08/2004 13:03:29 48.0021644 -116.0118324 // // Fields are: // W name Comment Date/Time Latitude Longitude // void process_RINO_waypoints(void) { FILE *f; char temp[MAX_FILENAME * 2]; char line[301]; // float UTC_Offset; char temp_file_name[MAX_VALUE]; // char datum[50]; // Just to be safe line[300] = '\0'; // Create the full path/filename xastir_snprintf(temp, sizeof(temp), "%s/RINO.gpstrans", get_user_base_dir("gps", temp_file_name, sizeof(temp_file_name))); f=fopen(temp,"r"); // Open for reading if (f == NULL) { fprintf(stderr, "Couldn't open %s file for reading\n", temp); return; } // Process the file line-by-line here. The format for gpstrans // files as written by GPSMan appears to be: // // "W" // Waypoint name // Comment field (Date/Time is default on Garmins) // Date/Time // Decimal latitude // Decimal longitude // while (fgets(line, 300, f) != NULL) { // Snag the "Format:" line at the top of the file: // Format: DDD UTC Offset: -8.00 hrs Datum[100]: WGS 84 // if (strncmp(line,"Format:",7) == 0) { int i = 7; char temp2[50]; // Find the ':' after "UTC Offset" while (line[i] != ':' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Skip white space while (line[i] == ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy UTC offset chars into temp2 temp2[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(temp2,&line[i],1); i++; } // UTC_Offset = atof(temp2); //fprintf(stderr,"UTC Offset: %f\n", UTC_Offset); // NOTE: This would be the place to snag the datum as well. } // Check for a waypoint entry else if (line[0] == 'W') { char name[50]; char datetime[50]; char lat_c[20]; char lon_c[20]; int i = 1; // NOTE: We should check for the end of the string, skipping this // iteration of the loop if we haven't parsed enough fields. // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into name until tab or whitespace char. We're // assuming that a waypoint name can't have spaces in // it. name[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(name,&line[i],1); i++; } // Find tab character at end of name field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // We skip the comment field, doing nothing with the // data. // // Find tab character at end of comment field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Snag date/time. Use it in the object date/time field. // Copy into datetime until tab char. Include the space // between the time and date portions. datetime[0] = '\0'; while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(datetime,&line[i],1); i++; } // Find tab character at end of date/time field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into lat_c until white space char lat_c[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(lat_c,&line[i],1); i++; } // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into lon_c until tab character lon_c[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(lon_c,&line[i],1); i++; } i++; /* fprintf(stderr, "%s\t%f\t%f\n", name, atof(lat_c), atof(lon_c)); */ // For now we're hard-coding the RINO group to "APRS". Any RINO // waypoints that begin with these four characters will have those // four characters chopped and will be turned into our own APRS // object, which we will then attempt to transmit. if (strncmp(name,"APRS",4) == 0) { // We have a match. Turn this into an APRS Object char line2[100]; int lat_deg, lon_deg; float lat_min, lon_min; char lat_dir, lon_dir; char temp2[50]; int date; int hour; int minute; // Three variables used for Base-91 compressed strings. We have a // bug in this code at the moment so the Base-91 compressed code in // this routine is commented out. // char *compressed_string; // char lat_s[50]; // char lon_s[50]; // Strip off the "APRS" at the beginning of the // name. Add spaces to flush out the length of an // APRS object name. strcpy(temp2, &name[4]); temp2[sizeof(temp2)-1] = '\0'; // Terminate string strcat(temp2, " "); temp2[sizeof(temp2)-1] = '\0'; // Terminate string // Copy it back to the "name" variable. xastir_snprintf(name, sizeof(name), "%s", temp2); // Truncate the name at nine characters. name[9] = '\0'; // We can either snag the UTC Offset from the top of // the file, or we can put the date/time format into // local time. The spec suggests using zulu time // for all future implementations, so we snagged the // UTC Offset earlier in this routine. // 07/09/2004 09:22:28 //fprintf(stderr,"%s %s", name, datetime); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[3]); temp2[2] = '\0'; date = atoi(temp2); //fprintf(stderr, "%02d\n", date); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[11]); temp2[2] = '\0'; hour = atoi(temp2); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[14]); temp2[2] = '\0'; minute = atoi(temp2); //fprintf(stderr,"\t\t%02d%02d%02d/\n", date, hour, minute); // We need to remember to bump the date up if we go // past midnight adding the UTC offset. In that // case we may need to bump the day as well if we're // near the end of the month. Use the Unix time // facilities for this? // Here we're assuming that the UTC offset is // divisible by one hour. Always correct? // hour = (int)(hour - UTC_Offset); lat_deg = atoi(lat_c); if (lat_deg < 0) { lat_deg = -lat_deg; } lon_deg = atoi(lon_c); if (lon_deg < 0) { lon_deg = -lon_deg; } lat_min = atof(lat_c); if (lat_min < 0.0) { lat_min = -lat_min; } lat_min = (lat_min - lat_deg) * 60.0; lon_min = atof(lon_c); if (lon_min < 0.0) { lon_min = -lon_min; } lon_min = (lon_min - lon_deg) * 60.0; if (lat_c[0] == '-') { lat_dir = 'S'; } else { lat_dir = 'N'; } if (lon_c[0] == '-') { lon_dir = 'W'; } else { lon_dir = 'E'; } // Non-Compressed version xastir_snprintf(line2, sizeof(line2), ";%-9s*%02d%02d%02d/%02d%05.2f%c%c%03d%05.2f%c%c", name, date, hour, minute, lat_deg, // Degrees lat_min, // Minutes lat_dir, // N/S '/', // Primary symbol table lon_deg, // Degrees lon_min, // Minutes lon_dir, // E/W '['); // Hiker symbol /* // Compressed version. Gives us more of the // resolution inherent in the RINO waypoints. // Doesn't have an affect on whether we transmit // compressed objects from Xastir over RF. That is // selected from the File->Configure->Defaults // dialog. // // compress_posit expects its lat/long in // // APRS-like format: // "%2d%lf%c", °, &minutes, &ext xastir_snprintf(lat_s, sizeof(lat_s), "%02d%8.5f%c", lat_deg, lat_min, lat_dir); xastir_snprintf(lon_s, sizeof(lon_s), "%02d%8.5f%c", lon_deg, lon_min, lon_dir); compressed_string = compress_posit(lat_s, '/', // group character lon_s, '[', // symbol, 0, // course, 0, // speed, ""); // phg //fprintf(stderr, "compressed: %s\n", compressed_string); xastir_snprintf(line2, sizeof(line2), ";%-9s*%02d%02d%02d/%s", name, date, hour, minute, compressed_string); */ /* fprintf(stderr, "%-9s\t%f\t%f\t\t\t\t\t\t", name, atof(lat_c), atof(lon_c)); fprintf(stderr,"%s\n",line2); */ // Update this object in our save file log_object_item(line2,0,name); if (object_tx_disable) { output_my_data(line2,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line2,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } } } //fprintf(stderr,"\n"); (void)fclose(f); } void GPS_operations_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); GPS_operations_dialog = (Widget)NULL; } // Set up gps_map_filename based on user preferences for filename // and map color. void GPS_operations_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; char short_filename[MAX_FILENAME]; char color_text[50]; temp = XmTextGetString(gpsfilename_text); xastir_snprintf(short_filename, sizeof(short_filename), "%s", temp); XtFree(temp); // Add date/time to filename if no filename is given if (strlen(short_filename) == 0) { int ii; // Compute the date/time and put in string get_timestamp(short_filename); // Change spaces to underlines // Wed Mar 5 15:24:48 PST 2003 for (ii = 0; ii < (int)strlen(short_filename); ii++) { if (short_filename[ii] == ' ') { short_filename[ii] = '_'; } } } (void)remove_trailing_spaces(short_filename); switch (gps_map_color) { case 0: { xastir_snprintf(color_text,sizeof(color_text),"Red"); gps_map_color_offset=0x0c; break; } case 1: { xastir_snprintf(color_text,sizeof(color_text),"Green"); gps_map_color_offset=0x23; break; } case 2: { xastir_snprintf(color_text,sizeof(color_text),"Black"); gps_map_color_offset=0x08; break; } case 3: { xastir_snprintf(color_text,sizeof(color_text),"White"); gps_map_color_offset=0x0f; break; } case 4: { xastir_snprintf(color_text,sizeof(color_text),"Orange"); gps_map_color_offset=0x62; break; } case 5: { xastir_snprintf(color_text,sizeof(color_text),"Blue"); gps_map_color_offset=0x03; break; } case 6: { xastir_snprintf(color_text,sizeof(color_text),"Yellow"); gps_map_color_offset=0x0e; break; } case 7: { xastir_snprintf(color_text,sizeof(color_text),"Purple"); gps_map_color_offset=0x0b; break; } default: { xastir_snprintf(color_text,sizeof(color_text),"Red"); gps_map_color_offset=0x0c; break; } } // If doing waypoints, don't add the color onto the end if (strcmp("Waypoints",gps_map_type) == 0) { strcpy(gps_map_filename, short_filename); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, gps_map_type); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, ".shp"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string // Same without ".shp" strcpy(gps_map_filename_base, short_filename); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, gps_map_type); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string } else // Doing Tracks/Routes { strcpy(gps_map_filename, short_filename); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, gps_map_type); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, color_text); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, ".shp"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string // Same without ".shp" strcpy(gps_map_filename_base, short_filename); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, gps_map_type); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, color_text); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string // Same without ".shp" *or* color strcpy(gps_map_filename_base2, short_filename); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string strcat(gps_map_filename_base2, "_"); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string strcat(gps_map_filename_base2, gps_map_type); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string } //fprintf(stderr,"%s\t%s\n",gps_map_filename,gps_map_filename_base); // Signify that the user has selected the filename and color for // the downloaded file. gps_details_selected++; GPS_operations_destroy_shell(widget,clientData,callData); } void GPS_operations_cancel(Widget widget, XtPointer clientData, XtPointer callData) { // Destroy the GPS selection dialog GPS_operations_destroy_shell(widget,clientData,callData); // Wait for the GPS operation to be finished, then clear out all // of the variables. while (!gps_got_data_from && gps_operation_pending) { usleep(1000000); // 1 second } gps_details_selected = 0; gps_got_data_from = 0; gps_operation_pending = 0; } void GPS_operations_color_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { gps_map_color = atoi(which); } else { gps_map_color = 0; } } // This routine should be called while the transfer is progressing, // or perhaps just after it ends. If we can do it while the // transfer is occurring we can save time overall. Here we'll select // the color and name for the resulting file, then cause it to be // selected and displayed on the map screen. // void GPS_transfer_select( void ) { static Widget pane, scrollwindow, my_form, button_select, button_cancel, frame, type_box, ctyp0, ctyp1, ctyp2, ctyp3, ctyp4, ctyp5, ctyp6, ctyp7, gpsfilename_label; // static Widget color_type; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count if (!GPS_operations_dialog) { // Set args for color ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; GPS_operations_dialog = XtVaCreatePopupShell( langcode("GPS001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget( "GPS_transfer_select pane", xmPanedWindowWidgetClass, GPS_operations_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget( "GPS_transfer_select my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gpsfilename_label = XtVaCreateManagedWidget( // Filename langcode("GPS002"), xmLabelWidgetClass, my_form, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); gpsfilename_text = XtVaCreateManagedWidget( "GPS_transfer_select gpsfilename_text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNwidth, ((20*7)+2), XmNmaxLength, 200, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, gpsfilename_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget( "GPS_transfer_select frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, gpsfilename_label, XmNtopOffset,15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //color_type XtVaCreateManagedWidget( // Select Color langcode("GPS003"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); type_box = XmCreateRadioBox( frame, "GPS_transfer_select Transmit Options box", al, ac); XtVaSetValues(type_box, XmNnumColumns,2, NULL); ctyp0 = XtVaCreateManagedWidget( // Red langcode("GPS004"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp0,XmNvalueChangedCallback,GPS_operations_color_toggle,"0"); ctyp1 = XtVaCreateManagedWidget( // Green langcode("GPS005"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp1,XmNvalueChangedCallback,GPS_operations_color_toggle,"1"); ctyp2 = XtVaCreateManagedWidget( // Black langcode("GPS006"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp2,XmNvalueChangedCallback,GPS_operations_color_toggle,"2"); ctyp3 = XtVaCreateManagedWidget( // White langcode("GPS007"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp3,XmNvalueChangedCallback,GPS_operations_color_toggle,"3"); ctyp4 = XtVaCreateManagedWidget( // Orange langcode("GPS008"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp4,XmNvalueChangedCallback,GPS_operations_color_toggle,"4"); ctyp5 = XtVaCreateManagedWidget( // Blue langcode("GPS009"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp5,XmNvalueChangedCallback,GPS_operations_color_toggle,"5"); ctyp6 = XtVaCreateManagedWidget( // Yellow langcode("GPS010"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp6,XmNvalueChangedCallback,GPS_operations_color_toggle,"6"); ctyp7 = XtVaCreateManagedWidget( // Violet langcode("GPS011"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp7,XmNvalueChangedCallback,GPS_operations_color_toggle,"7"); button_select = XtVaCreateManagedWidget( langcode("WPUPCFS028"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget( langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_select, XmNactivateCallback, GPS_operations_change_data, GPS_operations_dialog); XtAddCallback(button_cancel, XmNactivateCallback, GPS_operations_cancel, GPS_operations_dialog); // Set default color to first selection XmToggleButtonSetState(ctyp0,TRUE,FALSE); gps_map_color = 0; // De-sensitize the color selections if we're doing // waypoints. if (strcmp("Waypoints",gps_map_type) == 0) { XtSetSensitive(frame, FALSE); } pos_dialog(GPS_operations_dialog); delw = XmInternAtom( XtDisplay(GPS_operations_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback( GPS_operations_dialog, delw, GPS_operations_destroy_shell, (XtPointer)GPS_operations_dialog); XtManageChild(my_form); XtManageChild(type_box); XtManageChild(pane); resize_dialog(my_form, GPS_operations_dialog); XtPopup(GPS_operations_dialog,XtGrabNone); // Move focus to the Select button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(GPS_operations_dialog); XmProcessTraversal(button_select, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow( XtDisplay(GPS_operations_dialog), XtWindow(GPS_operations_dialog)); } } time_t check_gps_map_time = (time_t)0; // Function called by UpdateTime periodically. Checks whether // we've just completed a GPS transfer and need to redraw maps as a // result. // void check_for_new_gps_map(int curr_sec) { // Only check once per second if (check_gps_map_time == curr_sec) { return; // Skip it, we already checked once this second. } check_gps_map_time = curr_sec; if ( (gps_operation_pending || gps_got_data_from) && !gps_details_selected) { // A transfer is underway or has just completed. The user // hasn't selected the filename/color yet. Bring up the // selection dialog so that the user can do so. GPS_transfer_select(); } else if (gps_details_selected && gps_got_data_from && !gps_operation_pending) { FILE *f; char temp[MAX_FILENAME * 2]; char gps_base_dir[MAX_VALUE]; char temp_file_name[MAX_VALUE]; get_user_base_dir("gps",gps_base_dir, sizeof(gps_base_dir)); //fprintf(stderr,"check_for_new_gps_map()\n"); // We have new data from a GPS! Add the file to the // selected maps file, cause a reload of the maps to occur, // and then re-index maps (so that map may be deselected by // the user). // // It would be good to verify that we're not duplicating entries. // Add code here to read through the file first looking for a // match before attempting to append any new lines. // // We don't rename if Garmin RINO waypoint file if (strcmp(gps_map_type,"RINO") != 0) { // Rename the temporary file to the new filename. We must // do this three times, once for each piece of the Shapefile // map. #if defined(HAVE_MV) strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } // Done for the ".shp" file. Now repeat for the ".shx" and // ".dbf" files. strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".shx "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".shx"); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".dbf "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".dbf"); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } #endif // HAVE_MV // Write out a WKT in a .prj file to go with this shapefile. xastir_snprintf(temp, sizeof(temp), "%s/%s.prj", gps_base_dir, gps_map_filename_base); xastirWriteWKT(temp); if (strcmp(gps_map_type,"Waypoints") != 0) { // KM5VY: Create a really, really simple dbfawk file to // go with the shapefile. This is a dbfawk file of the // "per file" type, with the color hardcoded into it. // This will enable downloaded gps shapefiles to have // the right color even when they're not placed in the // GPS directory. // We don't do this for waypoint files, because all we need to // do for those is associate the name with the waypoint, and // that can be done by a generic signature-based file. xastir_snprintf(temp, sizeof(temp), "%s/%s.dbfawk", gps_base_dir, gps_map_filename_base); f=fopen(temp,"w"); // open for write if (f != NULL) { fprintf(f,gps_dbfawk_format,gps_map_color_offset, gps_map_filename_base2); fclose(f); } } // Add the new gps map to the list of selected maps f=fopen( get_user_base_dir(SELECTED_MAP_DATA, temp_file_name, sizeof(temp_file_name)), "a" ); // Open for appending if (f!=NULL) { //WE7U: Change this: fprintf(f,"GPS/%s\n",gps_map_filename); (void)fclose(f); // Reindex maps. Use the smart timestamp-checking indexing. map_indexer(0); // Have to have the new map in the index first before we can select it map_chooser_init(); // Re-read the selected_maps.sys file re_sort_maps = 1; // Creates a new sorted list from the selected maps // // We should set some flags here instead of doing the map redraw // ourselves, so that multiple map reloads don't occur sometimes in // UpdateTime. // // Reload maps // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } else { fprintf(stderr,"Couldn't open file: %s\n", get_user_base_dir(SELECTED_MAP_DATA, temp_file_name, sizeof(temp_file_name)) ); } } else { // We're dealing with Garmin RINO waypoints. Go process // the RINO.gpstrans file, creating objects out of them. process_RINO_waypoints(); } // Set up for the next GPS run gps_got_data_from = 0; gps_details_selected = 0; } } // This is the separate execution thread that transfers the data // to/from the GPS. The thread is started up by the // GPS_operations() function below. // static void* gps_transfer_thread(void *arg) { int input_param; char temp[500]; char prefix[100]; char postfix[100]; char gps_base_dir[MAX_VALUE]; get_user_base_dir("gps", gps_base_dir, sizeof(gps_base_dir)); // Set up the prefix string. Note that we depend on the correct // setup of serial ports and such in GPSMan's configs. xastir_snprintf(prefix, sizeof(prefix), "%s", GPSMAN_PATH); // Set up the postfix string. The files will be created in the // "~/.xastir/gps/" directory. strcpy(postfix, "Shapefile dim=2 "); postfix[sizeof(postfix)-1] = '\0'; // Terminate string strcat(postfix, gps_base_dir); postfix[sizeof(postfix)-1] = '\0'; // Terminate string strcat(postfix, "/"); postfix[sizeof(postfix)-1] = '\0'; // Terminate string input_param = atoi((char *)arg); // The pthread_detach() call means we don't care about the // return code and won't use pthread_join() later. Makes // threading more efficient. (void)pthread_detach(pthread_self()); switch (input_param) { case 1: // Fetch track from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite TR Shapefile dim=2 track.date // fprintf(stderr,"Fetch track from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Track_Red.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Track_Red"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Track"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite TR "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps track\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 2: // Fetch route from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite RT Shapefile dim=2 routes.date // fprintf(stderr,"Fetch routes from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Routes_Red.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Routes_Red"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Routes"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite RT "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps routes\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 3: // Fetch waypoints from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite WP Shapefile dim=2 waypoints.date // fprintf(stderr,"Fetch waypoints from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Waypoints.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Waypoints"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Waypoints"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite WP "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps waypoints\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 4: // Send track to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 track.date TR fprintf(stderr,"Send track to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 5: // Send route to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 routes.date RT fprintf(stderr,"Send route to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 6: // Send waypoints to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 waypoints.date WP fprintf(stderr,"Send waypoints to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 7: // Fetch waypoints from GPS in GPSTrans format // gpsman.tcl -dev /dev/ttyS0 getwrite WP GPStrans waypoints.date // fprintf(stderr,"Fetch Garmin RINO waypoints\n"); // The files will be created in the "~/.xastir/gps/" // directory. xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "RINO.gpstrans"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "RINO"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "RINO"); strcpy(temp, "("); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite WP GPStrans "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " 2>&1) >/dev/null"); temp[sizeof(temp)-1] = '\0'; // Terminate string // Execute the command if (system(temp) != 0) { // Ignore the return value as we've always done prior, // in other words: No change to the operation. } // if ( system(temp) ) { // fprintf(stderr,"Couldn't download the gps waypoints\n"); // gps_operation_pending = 0; // We're done // return(NULL); // } // Set the got_data flag gps_got_data_from++; break; default: fprintf(stderr,"Illegal parameter %d passed to gps_transfer_thread!\n", input_param); gps_operation_pending = 0; // We're done break; } // End of switch // Signal to the main thread that we're all done with the // GPS operation. gps_operation_pending = 0; // We're done // End the thread return(NULL); } // GPSMan can't handle multiple '.'s in the filename. It chops at // the first one. // // Note that the permissions on the "~/.xastir/gps/" directory have to be // set so that this user (or the root user?) can create files in // that directory. The permissions on the resulting files may need // to be tweaked. // // When creating files, we should warn the user of a conflict if the // filename already exists, then if the user wishes to overwrite it, // delete the old set of files before downloading the new ones. We // should also make sure we're not adding the filename to the // selected_maps.sys more than once. // // Set up default filenames for each, with an autoincrementing // number at the end? That'd be one way of getting a maps // downloaded in a hurry. Could also ask for a filename after the // download is complete instead of at the start of the download. In // that case, download to a temporary filename and then rename it // later and reload maps. // // Dialog should ask the user to put the unit into Garmin-Garmin // mode before proceeding. // // We could de-sensitize the GPS transfer menu items during a // transfer operation, to make sure we're not called again until the // first operation is over. // void GPS_operations( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { pthread_t gps_operations_thread; int parameter; if (clientData != NULL) { // Check whether we're already doing a GPS operation. // Return if so. if (gps_operation_pending) { fprintf(stderr,"GPS Operation is already pending, can't start another one!\n"); return; } parameter = atoi((char *)clientData); if ( ((parameter < 1) || (parameter > 3)) && parameter != 7) { fprintf(stderr,"GPS_operations: Parameter out-of-range: %d",parameter); return; } gps_operation_pending++; gps_got_data_from = 0; // We don't need to select filename/color if option 7 if (parameter == 7) { gps_details_selected++; } //----- Start New Thread ----- // Here we start a new thread. We'll communicate with the // main thread via global variables. Use mutex locks if // there might be a conflict as to when/how we're updating // those variables. // if (pthread_create(&gps_operations_thread, NULL, gps_transfer_thread, clientData)) { fprintf(stderr,"Error creating gps transfer thread\n"); gps_got_data_from = 0; // No data to present gps_operation_pending = 0; // We're done } else { // We're off and running with the new thread! } } } #endif // HAVE_GPSMAN ///////////////////////////////////////////////////////////////////// // End of GPS operations ///////////////////////////////////////////////////////////////////// void Set_Log_Indicator(void) { if ( (1==log_tnc_data) || (1==log_net_data) || (1==log_wx) || (1==log_igate) || (1==log_wx_alert_data) || (1==log_message_data) ) { XmTextFieldSetString(log_indicator, langcode("BBARSTA043")); // Logging XtVaSetValues(log_indicator, XmNbackground, GetPixelByName(appshell,"RosyBrown"), NULL); } else { XmTextFieldSetString(log_indicator, NULL); XtVaSetValues(log_indicator, MY_BACKGROUND_COLOR, NULL); } } void TNC_Logging_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_tnc_data = atoi(which); } else { log_tnc_data = 0; } Set_Log_Indicator(); } void Net_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_net_data = atoi(which); } else { log_net_data = 0; } Set_Log_Indicator(); } void IGate_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_igate = atoi(which); } else { log_igate = 0; } Set_Log_Indicator(); } void Message_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_message_data = atoi(which); } else { log_message_data = 0; } Set_Log_Indicator(); } void WX_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_wx = atoi(which); } else { log_wx = 0; } Set_Log_Indicator(); } void WX_Alert_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_wx_alert_data = atoi(which); } else { log_wx_alert_data = 0; } Set_Log_Indicator(); } // Filter Data Menu button callbacks // support functions void set_sensitive_select_sources(int sensitive) { XtSetSensitive(select_mine_button, sensitive); XtSetSensitive(select_tnc_button, sensitive); if (!Select_.tnc) { XtSetSensitive(select_direct_button, FALSE); XtSetSensitive(select_via_digi_button, FALSE); } else { XtSetSensitive(select_direct_button, sensitive); XtSetSensitive(select_via_digi_button, sensitive); } XtSetSensitive(select_net_button, sensitive); if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); } else { XtSetSensitive(select_old_data_button, sensitive); } } void set_sensitive_select_types(int sensitive) { XtSetSensitive(select_stations_button, sensitive); if (!Select_.stations) { XtSetSensitive(select_fixed_stations_button, FALSE); XtSetSensitive(select_moving_stations_button, FALSE); XtSetSensitive(select_weather_stations_button, FALSE); XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } else { XtSetSensitive(select_fixed_stations_button, sensitive); XtSetSensitive(select_moving_stations_button, sensitive); XtSetSensitive(select_weather_stations_button, sensitive); if (Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, sensitive); } } XtSetSensitive(select_objects_button, sensitive); if (!Select_.objects) { XtSetSensitive(select_weather_objects_button, FALSE); XtSetSensitive(select_gauge_objects_button, FALSE); XtSetSensitive(select_aircraft_objects_button, FALSE); XtSetSensitive(select_vessel_objects_button, FALSE); XtSetSensitive(select_other_objects_button, FALSE); } else { XtSetSensitive(select_weather_objects_button, sensitive); XtSetSensitive(select_gauge_objects_button, sensitive); XtSetSensitive(select_aircraft_objects_button, sensitive); XtSetSensitive(select_vessel_objects_button, sensitive); XtSetSensitive(select_other_objects_button, sensitive); } } void set_sensitive_display(int sensitive) { XtSetSensitive(display_callsign_button, sensitive); if (!Display_.callsign) { XtSetSensitive(display_label_all_trackpoints_button, FALSE); } else { XtSetSensitive(display_label_all_trackpoints_button, sensitive); } XtSetSensitive(display_symbol_button, sensitive); if (!Display_.symbol) { XtSetSensitive(display_symbol_rotate_button, FALSE); } else { XtSetSensitive(display_symbol_rotate_button, sensitive); } XtSetSensitive(display_phg_button, sensitive); if (!Display_.phg) { XtSetSensitive(display_default_phg_button, FALSE); XtSetSensitive(display_phg_of_moving_button, FALSE); } else { XtSetSensitive(display_default_phg_button, sensitive); XtSetSensitive(display_phg_of_moving_button, sensitive); } XtSetSensitive(display_altitude_button, sensitive); XtSetSensitive(display_course_button, sensitive); XtSetSensitive(display_speed_button, sensitive); if (!Display_.speed) { XtSetSensitive(display_speed_short_button, FALSE); } else { XtSetSensitive(display_speed_short_button, sensitive); } XtSetSensitive(display_dist_bearing_button, sensitive); XtSetSensitive(display_weather_button, sensitive); if (!Display_.weather) { XtSetSensitive(display_weather_text_button, FALSE); XtSetSensitive(display_temperature_only_button, FALSE); XtSetSensitive(display_wind_barb_button, FALSE); } else { XtSetSensitive(display_weather_text_button, sensitive); if (!Display_.weather_text) { XtSetSensitive(display_temperature_only_button, FALSE); } else { XtSetSensitive(display_temperature_only_button, sensitive); } XtSetSensitive(display_wind_barb_button, sensitive); } XtSetSensitive(display_trail_button, sensitive); XtSetSensitive(display_last_heard_button, sensitive); XtSetSensitive(display_ambiguity_button, sensitive); XtSetSensitive(display_df_data_button, sensitive); if (!Display_.df_data) { XtSetSensitive(display_df_beamwidth_data_button, FALSE); XtSetSensitive(display_df_bearing_data_button, FALSE); } else { XtSetSensitive(display_df_beamwidth_data_button, sensitive); XtSetSensitive(display_df_bearing_data_button, sensitive); } XtSetSensitive(display_dr_data_button, sensitive); if (!Display_.dr_data) { XtSetSensitive(display_dr_arc_button, FALSE); XtSetSensitive(display_dr_course_button, FALSE); XtSetSensitive(display_dr_symbol_button, FALSE); } else { XtSetSensitive(display_dr_arc_button, sensitive); XtSetSensitive(display_dr_course_button, sensitive); XtSetSensitive(display_dr_symbol_button, sensitive); } } void Select_none_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.none = atoi(which); set_sensitive_select_sources(FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } else { Select_.none = 0; set_sensitive_select_sources(TRUE); if (no_data_selected()) { set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } else { set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_mine_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.mine = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.mine = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_tnc_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.tnc = atoi(which); XtSetSensitive(select_direct_button, TRUE); XtSetSensitive(select_via_digi_button, TRUE); if (!no_data_selected()) { XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } } else { Select_.tnc = 0; XtSetSensitive(select_direct_button, FALSE); XtSetSensitive(select_via_digi_button, FALSE); if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_direct_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.direct = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.direct = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_via_digi_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.via_digi = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.via_digi = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_net_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.net = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.net = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_tactical_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.tactical = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.tactical = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_old_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.old_data = atoi(which); } else { Select_.old_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.stations = atoi(which); XtSetSensitive(select_fixed_stations_button, TRUE); XtSetSensitive(select_moving_stations_button, TRUE); XtSetSensitive(select_weather_stations_button, TRUE); if (Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, TRUE); } } else { Select_.stations = 0; XtSetSensitive(select_fixed_stations_button, FALSE); XtSetSensitive(select_moving_stations_button, FALSE); XtSetSensitive(select_weather_stations_button, FALSE); XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_fixed_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.fixed_stations = atoi(which); } else { Select_.fixed_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_moving_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.moving_stations = atoi(which); } else { Select_.moving_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_weather_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.weather_stations = atoi(which); XtSetSensitive(select_CWOP_wx_stations_button, atoi(which)); } else { Select_.weather_stations = 0; XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_CWOP_wx_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.CWOP_wx_stations = atoi(which); } else { Select_.CWOP_wx_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.objects = atoi(which); XtSetSensitive(select_weather_objects_button, TRUE); XtSetSensitive(select_gauge_objects_button, TRUE); XtSetSensitive(select_aircraft_objects_button, TRUE); XtSetSensitive(select_vessel_objects_button, TRUE); XtSetSensitive(select_other_objects_button, TRUE); } else { Select_.objects = 0; XtSetSensitive(select_weather_objects_button, FALSE); XtSetSensitive(select_gauge_objects_button, FALSE); XtSetSensitive(select_aircraft_objects_button, FALSE); XtSetSensitive(select_vessel_objects_button, FALSE); XtSetSensitive(select_other_objects_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_weather_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.weather_objects = atoi(which); } else { Select_.weather_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_gauge_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.gauge_objects = atoi(which); } else { Select_.gauge_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_aircraft_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.aircraft_objects = atoi(which); } else { Select_.aircraft_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_vessel_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.vessel_objects = atoi(which); } else { Select_.vessel_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_other_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.other_objects = atoi(which); } else { Select_.other_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } // Display Menu button callbacks void Display_callsign_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.callsign = atoi(which); XtSetSensitive(display_label_all_trackpoints_button, TRUE); } else { Display_.callsign = 0; XtSetSensitive(display_label_all_trackpoints_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_label_all_trackpoints_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.label_all_trackpoints = atoi(which); } else { Display_.label_all_trackpoints = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_symbol_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.symbol = atoi(which); XtSetSensitive(display_symbol_rotate_button, TRUE); } else { Display_.symbol = 0; XtSetSensitive(display_symbol_rotate_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_symbol_rotate_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.symbol_rotate = atoi(which); } else { Display_.symbol_rotate = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_trail_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.trail = atoi(which); } else { Display_.trail = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_course_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.course = atoi(which); } else { Display_.course = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_speed_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.speed = atoi(which); XtSetSensitive(display_speed_short_button, TRUE); } else { Display_.speed = 0; XtSetSensitive(display_speed_short_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_speed_short_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.speed_short = atoi(which); } else { Display_.speed_short = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_altitude_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.altitude = atoi(which); } else { Display_.altitude = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_weather_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.weather = atoi(which); XtSetSensitive(display_weather_text_button, TRUE); XtSetSensitive(display_temperature_only_button, TRUE); XtSetSensitive(display_wind_barb_button, TRUE); } else { Display_.weather = 0; XtSetSensitive(display_weather_text_button, FALSE); XtSetSensitive(display_temperature_only_button, FALSE); XtSetSensitive(display_wind_barb_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_weather_text_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.weather_text = atoi(which); XtSetSensitive(display_temperature_only_button, TRUE); } else { Display_.weather_text = 0; XtSetSensitive(display_temperature_only_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_temperature_only_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.temperature_only = atoi(which); } else { Display_.temperature_only = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_wind_barb_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.wind_barb = atoi(which); } else { Display_.wind_barb = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_aloha_circle_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.aloha_circle = atoi(which); } else { Display_.aloha_circle = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_ambiguity_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.ambiguity = atoi(which); } else { Display_.ambiguity = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_phg_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.phg = atoi(which); XtSetSensitive(display_default_phg_button, TRUE); XtSetSensitive(display_phg_of_moving_button, TRUE); } else { Display_.phg = 0; XtSetSensitive(display_default_phg_button, FALSE); XtSetSensitive(display_phg_of_moving_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_default_phg_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.default_phg = atoi(which); } else { Display_.default_phg = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_phg_of_moving_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.phg_of_moving = atoi(which); } else { Display_.phg_of_moving = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_df_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_data = atoi(which); XtSetSensitive(display_df_beamwidth_data_button, TRUE); XtSetSensitive(display_df_bearing_data_button, TRUE); } else { Display_.df_data = 0; XtSetSensitive(display_df_beamwidth_data_button, FALSE); XtSetSensitive(display_df_bearing_data_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_df_beamwidth_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_beamwidth_data = atoi(which); } else { Display_.df_beamwidth_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_df_bearing_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_bearing_data = atoi(which); } else { Display_.df_bearing_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_data = atoi(which); XtSetSensitive(display_dr_arc_button, TRUE); XtSetSensitive(display_dr_course_button, TRUE); XtSetSensitive(display_dr_symbol_button, TRUE); } else { Display_.dr_data = 0; XtSetSensitive(display_dr_arc_button, FALSE); XtSetSensitive(display_dr_course_button, FALSE); XtSetSensitive(display_dr_symbol_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_arc_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_arc = atoi(which); } else { Display_.dr_arc = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_course_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_course = atoi(which); } else { Display_.dr_course = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_symbol_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_symbol = atoi(which); } else { Display_.dr_symbol = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dist_bearing_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dist_bearing = atoi(which); } else { Display_.dist_bearing = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_last_heard_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.last_heard = atoi(which); } else { Display_.last_heard = 0; } redraw_on_new_data = 2; // Immediate screen update } /* * Toggle unit system (button callbacks) */ void Units_choice_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { english_units = atoi(which); } else { english_units = 0; } redraw_on_new_data=2; update_units(); // setup conversion fill_wx_data(); } /* * Toggle dist/bearing status (button callbacks) */ void Dbstatus_choice_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { do_dbstatus = atoi(which); } else { do_dbstatus = 0; } // we need to rebuild main window now??? XtVaSetValues(text2, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), NULL); redraw_on_new_data=2; } /* * Update global variables for unit conversion * * Be careful using these, as they change based on the value of * english_units! These variable should only be used when * DISPLAYING data, not when converting numbers for use in internal * storage or equations. * */ void update_units(void) { switch (english_units) { case 1: // English xastir_snprintf(un_alt,sizeof(un_alt),"ft"); xastir_snprintf(un_dst,sizeof(un_dst),"mi"); xastir_snprintf(un_spd,sizeof(un_spd),"mph"); cvt_m2len = 3.28084; // m to ft cvt_dm2len = 0.328084; // dm to ft cvt_hm2len = 0.0621504; // hm to mi cvt_kn2len = 1.1508; // knots to mph cvt_mi2len = 1.0; // mph to mph break; case 2: // Nautical // add nautical miles and knots for future use xastir_snprintf(un_alt,sizeof(un_alt),"ft"); xastir_snprintf(un_dst,sizeof(un_dst),"nm"); xastir_snprintf(un_spd,sizeof(un_spd),"kn"); cvt_m2len = 3.28084; // m to ft cvt_dm2len = 0.328084; // dm to ft cvt_hm2len = 0.0539957; // hm to nm cvt_kn2len = 1.0; // knots to knots cvt_mi2len = 0.8689607; // mph to knots / mi to nm break; default: // Metric xastir_snprintf(un_alt,sizeof(un_alt),"m"); xastir_snprintf(un_dst,sizeof(un_dst),"km"); xastir_snprintf(un_spd,sizeof(un_spd),"km/h"); cvt_m2len = 1.0; // m to m cvt_dm2len = 0.1; // dm to m cvt_hm2len = 0.1; // hm to km cvt_kn2len = 1.852; // knots to km/h cvt_mi2len = 1.609; // mph to km/h break; } } void Auto_msg_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { auto_reply = atoi(which); } else { auto_reply = 0; } } void Satellite_msg_ack_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { satellite_ack_mode = atoi(which); } else { satellite_ack_mode = 0; } } void Transmit_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { transmit_disable = atoi(which); XtSetSensitive(iface_transmit_now,FALSE); XtSetSensitive(object_tx_disable_toggle,FALSE); XtSetSensitive(posit_tx_disable_toggle,FALSE); } else { transmit_disable = 0; XtSetSensitive(iface_transmit_now,TRUE); XtSetSensitive(object_tx_disable_toggle,TRUE); XtSetSensitive(posit_tx_disable_toggle,TRUE); } } void Posit_tx_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { posit_tx_disable = atoi(which); } else { posit_tx_disable = 0; } } void Object_tx_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_tx_disable = atoi(which); } else { object_tx_disable = 0; } } void Emergency_beacon_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { emergency_beacon = atoi(which); //WE7U // We need to send a posit or two immediately, shorten the interval // between posits, and add the string "EMERGENCY" to the posit // before anything else in the comment field. transmit_now = 1; } else { emergency_beacon = 0; } } void Server_port_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { // Start the listening socket. If we fork it early we end // up with much smaller process memory allocated for it and // all its children. The server will authenticate each // client that connects. We'll share all of our data with // the server, which will send it to all // connected/authenticated clients. Anything transmitted by // the clients will come back to us and standard igating // rules should apply from there. // enable_server_port = atoi(which); tcp_server_pid = Fork_TCP_server(my_argc, my_argv, my_envp); udp_server_pid = Fork_UDP_server(my_argc, my_argv, my_envp); } else { enable_server_port = 0; shut_down_server(); } } void Help_About( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget about_dialog; Widget child; XmString xms, xa, xb; Arg al[400]; unsigned int ac; float version; char string1[200]; char string2[200]; extern char gitstring[]; char version_str[50]; xastir_snprintf(string2, sizeof(string2),"\nXastir V%s %s\n",xastir_version,gitstring); xms = XmStringCreateLocalized(string2); xa = XmStringCreateLocalized("\n\n" ABOUT_MSG "\n\nLibraries used: " XASTIR_INSTALLED_LIBS "\n\n" ABOUT_OSM); // Add some newlines xb = XmStringConcat(xms, xa); XmStringFree(xa); XmStringFree(xms); //xb is still defined xa = XmStringCreateLocalized("\n" XmVERSION_STRING); // Add the Motif version string xms = XmStringConcat(xb, xa); XmStringFree(xa); XmStringFree(xb); //xms is still defined xa = XmStringCreateLocalized("\n"); // Add a newline xb = XmStringConcat(xms, xa); XmStringFree(xa); XmStringFree(xms); //xb is still defined xms = XmStringCopy(xb); XmStringFree(xb); //xms is still defined #ifdef HAVE_NETAX25_AXLIB_H //if (libax25_version != NULL) { xb = XmStringCreateLocalized("\n"); xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); xb = XmStringCreateLocalized("@(#)LibAX25 (ax25lib_version is broken. Complain to the authors.)\n"); xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //} #endif // AVE_NETAX25_AXLIB_H #ifdef HAVE_MAGICK xb = XmStringCreateLocalized("\n"); // Add a newline xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); //xa is still defined xb = XmStringCreateLocalized( MagickVersion); // Add ImageMagick version string xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //xms is still defined #endif // HAVE_MAGICK xb = XmStringCreateLocalized("\n"); // Add a newline xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); //xa is still defined version = XRotVersion( string1, 99 ); xastir_snprintf(version_str, sizeof(version_str), "%0.2f", version); strcpy(string2, "\n"); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, string1); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, ", Version "); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, version_str); string2[sizeof(string2)-1] = '\0'; // Terminate string xb = XmStringCreateLocalized( string2); // Add Xvertext version string xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //xms is still defined ac = 0; XtSetArg(al[ac], XmNmessageString, xms); ac++; // "About Xastir" XtSetArg(al[ac], XmNtitle, langcode("PULDNHEL05") ); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "About Xastir" about_dialog = XmCreateInformationDialog(appshell, langcode("PULDNHEL05"), al, ac); XmStringFree(xms); XtDestroyWidget(XmMessageBoxGetChild(about_dialog, (unsigned char)XmDIALOG_CANCEL_BUTTON)); XtDestroyWidget(XmMessageBoxGetChild(about_dialog, (unsigned char)XmDIALOG_HELP_BUTTON)); child = XmMessageBoxGetChild(about_dialog, XmDIALOG_MESSAGE_LABEL); XtVaSetValues(child, XmNfontList, fontlist1, NULL); XtManageChild(about_dialog); pos_dialog(about_dialog); } Widget GetTopShell(Widget w) { while(w && !XtIsWMShell(w)) { w = XtParent(w); } return(w); } /*********************** Display incoming data*******************************/ /****************************************************************************/ void Display_data_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); Display_data_dialog = (Widget)NULL; } void Display_packet_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Display_packet_data_type = atoi(which); } else { Display_packet_data_type = 0; } redraw_on_new_packet_data=1; } // Turn on or off "Station Capabilities", callback for capabilities // button. // void Capabilities_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { show_only_station_capabilities = TRUE; } else { show_only_station_capabilities = FALSE; } } // Turn on or off "Mine Only" // void Display_packet_mine_only_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Display_packet_data_mine_only = TRUE; } else { Display_packet_data_mine_only = FALSE; } } void Display_data( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close, option_box, tnc_data, net_data, tnc_net_data, capabilities_button, mine_only_button; unsigned int n; Arg args[50]; Atom delw; if (!Display_data_dialog) { Display_data_dialog = XtVaCreatePopupShell(langcode("WPUPDPD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Display_data pane", xmPanedWindowWidgetClass, Display_data_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Display_data my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* set colors */ n=0; XtSetArg(args[n],XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n],XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; option_box = XmCreateRadioBox(my_form, "Display_data option box", args, n); XtVaSetValues(option_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, NULL); tnc_data = XtVaCreateManagedWidget(langcode("WPUPDPD002"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_data,XmNvalueChangedCallback,Display_packet_toggle,"1"); net_data = XtVaCreateManagedWidget(langcode("WPUPDPD003"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(net_data,XmNvalueChangedCallback,Display_packet_toggle,"2"); tnc_net_data = XtVaCreateManagedWidget(langcode("WPUPDPD004"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_net_data,XmNvalueChangedCallback,Display_packet_toggle,"0"); capabilities_button = XtVaCreateManagedWidget(langcode("WPUPDPD007"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, option_box, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(capabilities_button, XmNvalueChangedCallback,Capabilities_toggle,"1"); mine_only_button = XtVaCreateManagedWidget(langcode("WPUPDPD008"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, capabilities_button, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(mine_only_button, XmNvalueChangedCallback,Display_packet_mine_only_toggle,"1"); n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 100); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNscrollHorizontal, TRUE); n++; XtSetArg(args[n], XmNscrollVertical, TRUE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, option_box); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, 30); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; // XtSetArg(args[n], XmNnavigationType, XmTAB_GROUP); n++; Display_data_text=NULL; Display_data_text = XmCreateScrolledText(my_form, "Display_data text", args, n); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, Display_data_destroy_shell, Display_data_dialog); // I haven't figured out how to get the scrollbars to allow keyboard traversal. // When the ScrolledText widget is in the tab group, once you get there you can't // get out and it beeps at you when you try. Frustrating. For this dialog it's // probably not important enough to worry about. // I now have it set to allow TAB'ing into the ScrolledText widget, but to get // out you must do a . This sucks. Even if you enable the // ScrolledText widget in the tab group, the scrollbars don't work with the // arrow keys. // ScrolledList works. I need to convert to ScrolledList if // possible for output-only windows. pos_dialog(Display_data_dialog); delw = XmInternAtom(XtDisplay(Display_data_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(Display_data_dialog, delw, Display_data_destroy_shell, (XtPointer)Display_data_dialog); switch (Display_packet_data_type) { case(0): XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; case(1): XmToggleButtonSetState(tnc_data,TRUE,FALSE); break; case(2): XmToggleButtonSetState(net_data,TRUE,FALSE); break; default: XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; } if (show_only_station_capabilities) { XmToggleButtonSetState(capabilities_button,TRUE,FALSE); } else { XmToggleButtonSetState(capabilities_button,FALSE,FALSE); } if (Display_packet_data_mine_only) { XmToggleButtonSetState(mine_only_button,TRUE,FALSE); } else { XmToggleButtonSetState(mine_only_button,FALSE,FALSE); } XtManageChild(option_box); XtManageChild(Display_data_text); XtVaSetValues(Display_data_text, XmNbackground, colors[0x0f], NULL); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, Display_data_dialog); redraw_on_new_packet_data=1; XtPopup(Display_data_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(Display_data_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(Display_data_dialog), XtWindow(Display_data_dialog)); } } /****************************** Help menu ***********************************/ /****************************************************************************/ void help_view_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); help_view_dialog = (Widget)NULL; } void help_index_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (help_view_dialog) { help_view_destroy_shell(help_view_dialog, help_view_dialog, NULL); } help_view_dialog = (Widget)NULL; XtPopdown(shell); XtDestroyWidget(shell); help_index_dialog = (Widget)NULL; } void help_view( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close,help_text; int i; Position x, y; unsigned int n; char *temp = NULL; char title[200]; char temp2[200]; char temp3[200]; FILE *f; XmString *list; int open; Arg args[50]; int data_on,pos; int found; Atom delw; char help_file_path[MAX_VALUE]; data_on=0; pos=0; found=0; XtVaGetValues(help_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(help_list,x)) { found=1; temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); x=i+1; } } open=0; if (found) { if (help_view_dialog) { XtVaGetValues(help_view_dialog, XmNx, &x, XmNy, &y, NULL); help_view_destroy_shell(help_view_dialog, help_view_dialog, NULL); help_view_dialog = (Widget)NULL; open=1; } if (!help_view_dialog) { xastir_snprintf(title, sizeof(title), "%s - %s", langcode("MENUTB0009"), temp); help_view_dialog = XtVaCreatePopupShell(title, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("help_view pane", xmPanedWindowWidgetClass, help_view_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("help_view my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); n=0; XtSetArg(args[n], XmNrows, 20); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNscrollHorizontal, FALSE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; help_text=NULL; help_text = XmCreateScrolledText(my_form, "help_view help text", args, n); get_user_base_dir(HELP_FILE, help_file_path, sizeof(help_file_path)); f=fopen( help_file_path, "r" ); if (f!=NULL) { while(!feof(f)) { (void)get_line(f,temp2,200); if (strncmp(temp2,"HELP-INDEX>",11)==0) { if(strcmp((temp2+11),temp)==0) { data_on=1; } else { data_on=0; } } else { if (data_on) { strcpy(temp3, temp2); temp3[sizeof(temp3)-1] = '\0'; // Terminate string strcat(temp3, "\n"); temp3[sizeof(temp3)-1] = '\0'; // Terminate string XmTextInsert(help_text,pos,temp3); pos += strlen(temp3); XmTextShowPosition(help_text,0); } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", help_file_path); } button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_text), XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, help_view_destroy_shell, help_view_dialog); if (!open) { pos_dialog(help_view_dialog); } else { XtVaSetValues(help_view_dialog, XmNx, x, XmNy, y, NULL); } delw = XmInternAtom(XtDisplay(help_view_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(help_view_dialog, delw, help_view_destroy_shell, (XtPointer)help_view_dialog); XtManageChild(my_form); XtManageChild(help_text); XtVaSetValues(help_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, help_view_dialog); XtPopup(help_view_dialog,XtGrabNone); XmTextShowPosition(help_text,0); } XtFree(temp); // Free up the space allocated } } void Help_Index( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel; int n; char temp[600]; FILE *f; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ Atom delw; XmString str_ptr; char help_file_path[MAX_VALUE]; if(!help_index_dialog) { help_index_dialog = XtVaCreatePopupShell(langcode("WPUPHPI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Help_Index pane", xmPanedWindowWidgetClass, help_index_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Help_Index my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0ff]); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; help_list = XmCreateScrolledList(my_form, "Help_Index list", al, ac); n=1; get_user_base_dir(HELP_FILE, help_file_path, sizeof(help_file_path)); f=fopen( help_file_path, "r" ); if (f!=NULL) { while (!feof(f)) { (void)get_line(f,temp,600); if (strncmp(temp,"HELP-INDEX>",11)==0) { XmListAddItem(help_list, str_ptr = XmStringCreateLocalized((temp+11)),n++); XmStringFree(str_ptr); } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", help_file_path ); } button_ok = XtVaCreateManagedWidget(langcode("WPUPHPI002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_list), XmNtopOffset,5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_list), XmNtopOffset,5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, help_index_destroy_shell, help_index_dialog); XtAddCallback(button_ok, XmNactivateCallback, help_view, NULL); pos_dialog(help_index_dialog); delw = XmInternAtom(XtDisplay(help_index_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(help_index_dialog, delw, help_index_destroy_shell, (XtPointer)help_index_dialog); XtManageChild(my_form); XtManageChild(help_list); XtVaSetValues(help_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, help_index_dialog); XtPopup(help_index_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(help_index_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(help_index_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(help_index_dialog), XtWindow(help_index_dialog)); } } /************************** Clear stations *******************************/ /*************************************************************************/ void Stations_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { delete_all_stations(); my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); current_trail_color = 0x00; // restart // Reload saved objects and items from previous runs. // This implements persistent objects. reload_object_item(); redraw_on_new_data=2; } /************************* Map Properties*********************************/ /*************************************************************************/ // Destroys the Map Properties dialog void map_properties_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); map_properties_dialog = (Widget)NULL; re_sort_maps = 1; if (map_chooser_dialog) { XtSetSensitive(map_chooser_button_ok, TRUE); XtSetSensitive(map_chooser_button_cancel, TRUE); } } //WE7U // Possible changes: // *) Save/restore the map selections while changing properties. // Malloc a char array the size of the map_properties_list and // fill it in based on the current highlighting. Free it when // we're done. // *) Change the labels at the top into buttons? Zoom/Layer buttons // would pop up a dialog asking for the number. Others would // just toggle the feature. // *) Change to a single "Apply" button. This won't allow us to // easily change only some parameters unless we skip input fields // that are blank. Run through highlighted items, fill in input // fields if the parameter is the same for all. If different for // some, leave input field blank. // *) Bring up an "Abandon Changes?" confirmation dialog if input // fields are filled in but "Cancel" was pressed instead of // "Apply". // Fills in the map properties file entries. // void map_properties_fill_in (void) { int n; // int i; XmString str_ptr; map_index_record *current = map_index_head; int top_position; busy_cursor(appshell); // i=0; if (map_properties_dialog) { char *current_selections = NULL; int kk, mm; // Save our current place in the dialog XtVaGetValues(map_properties_list, XmNtopItemPosition, &top_position, NULL); // Get the list count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&kk, NULL); if (kk) // If list is not empty { // Allocate enough chars to hold the highlighting info current_selections = (char *)malloc(sizeof(char) * kk); //fprintf(stderr,"List entries:%d\n", kk); // Iterate over the list, saving the highlighting values for (mm = 0; mm < kk; mm++) { if (XmListPosSelected(map_properties_list, mm)) { current_selections[mm] = 1; } else { current_selections[mm] = 0; } } } // fprintf(stderr,"Top Position: %d\n",top_position); // Empty the map_properties_list widget first XmListDeleteAllItems(map_properties_list); // Put all the map files/dirs in the map_index into the Map // Properties dialog list (map_properties_list). Include // the map_layer and draw_filled variables on the line. n=1; // // We wish to only show the files that are currently selected in the // map_chooser_dialog's map_list widget. We'll need to run down // that widget's entries, checking whether each line is selected, // and only display it in the map_properties_list widget if selected // and a match with our string. // // One method would be to make the Map Chooser selections set a bit // in the in-memory index, so that we can tell which ones are // selected without a bunch of string compares. The bit would need // to be tweaked on starting up the map chooser (setting the // selected entries that match the selected_maps.sys file), and when // the user tweaked a selection. // // What we don't want to get into is an n*n set of string compares // between two lists, which would be very slow. If they're both // ordered lists though, we'll end up with at most a 2n multiplier, // which is much better. If we can pass the info between the lists // with a special entry in the record, we don't slow down at all. // // Reasonably fast method: Create a new list that contains only the // selected items from map_list. Run through this list as we // populate map_properties_list from the big linked list. // // Actually, it's probably just as fast to run down through // map_list, looking up records for every line that's selected. // Just keep the pointers incrementing for each list instead of // running through the entire in-memory linked list for every // selected item in map_list. // // For selected directories, we need to add each file that has that // initial directory name. We should be able to do this with a // match that stops at the end of the directory name. // // We need to grey-out the buttons in the Map Chooser until the // Properties dialog closes. Otherwise we might not able to get to // to the map_list widget to re-do the Properties list when a button // is pressed in the Properties dialog (if the user closes the Map // Chooser). // // Set all of the temp_select bits to zero in the in-memory // map index. map_index_temp_select_clear(); if (map_chooser_dialog) { map_index_record *ptr = map_index_head; int jj, x; XmString *list; char *temp; // Get the list and list count from the Map Chooser // dialog. XtVaGetValues(map_list, XmNitemCount,&jj, XmNitems,&list, NULL); // Find all selected files/directories in the Map // Chooser. Set the "temp_select" bits in the in-memory // map index to correspond. // for(x=1; x<=jj; x++) { if (XmListPosSelected(map_list,x)) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory // map index, setting the "temp_select" field to 1. map_index_update_temp_select(temp, &ptr); XtFree(temp); } } } } // We should now have all of the files/directories marked in // the in-memory map index. Files underneath selected // directories should also be marked by this point, as the // map_index_update_temp_select() routine should assure // this. while (current != NULL) { if (current->temp_select) { //fprintf(stderr,"%s\n",current->filename); // Make sure it's a file and not a directory if (current->filename[strlen(current->filename)-1] != '/') { char temp[MAX_FILENAME+100]; char temp_layer[10]; char temp_max_zoom[10]; char temp_min_zoom[10]; char temp_filled[20]; char temp_drg[20]; char temp_auto[20]; int len, start; // We have a file. Construct the line that we wish // to place in the list // JMT - this is a guess if (current->max_zoom == 0) { xastir_snprintf(temp_max_zoom, sizeof(temp_max_zoom), " - "); } else { xastir_snprintf(temp_max_zoom, sizeof(temp_max_zoom), "%5d", current->max_zoom); } if (current->min_zoom == 0) { xastir_snprintf(temp_min_zoom, sizeof(temp_min_zoom), " - "); } else { xastir_snprintf(temp_min_zoom, sizeof(temp_min_zoom), "%5d", current->min_zoom); } if (current->map_layer == 0) { xastir_snprintf(temp_layer, sizeof(temp_layer), " - "); } else { xastir_snprintf(temp_layer, sizeof(temp_layer), "%5d", current->map_layer); } xastir_snprintf(temp_filled, sizeof(temp_filled), " "); switch (current->draw_filled) { case 0: // Global No-Fill (vector) // Center the string in the column len = strlen(langcode("MAPP007")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP007")); // "No" break; case 1: // Global Fill // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP006")); // "Yes" break; case 2: // Auto default: // Center the string in the column len = strlen(langcode("MAPP011")); start = (int)( (5 - len) / 2 + 1.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP011")); // "Auto" break; } // End of switch // Truncate it so it fits our column width. temp_filled[5] = '\0'; xastir_snprintf(temp_drg, sizeof(temp_drg), " "); switch (current->usgs_drg) { case 0: // No // Center the string in the column len = strlen(langcode("MAPP007")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP007")); // "No" break; case 1: // Yes // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP006")); // "Yes" break; case 2: // Auto default: // Center the string in the column len = strlen(langcode("MAPP011")); start = (int)( (5 - len) / 2 + 1.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP011")); // "Auto" break; } // End of switch // Truncate it so it fits our column width. temp_drg[5] = '\0'; xastir_snprintf(temp_auto, sizeof(temp_auto), " "); if (current->auto_maps) { int len, start; // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces on the // end. xastir_snprintf(&temp_auto[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP006")); // Truncate it so it fits our column width. temp_auto[5] = '\0'; } //WARNING WARNING WARNING --- changing this format string // REQUIRES changing the defined constant MPD_FILENAME_OFFSET // at the top of this file, or all the routines that try // to decode the string will be wrong! xastir_snprintf(temp, sizeof(temp), "%s %s %s %s %s %s %s", temp_max_zoom, temp_min_zoom, temp_layer, temp_filled, temp_drg, temp_auto, current->filename); str_ptr = XmStringCreateLocalized(temp); XmListAddItem(map_properties_list, str_ptr, n); n++; XmStringFree(str_ptr); } } current = current->next; } if (kk) // If list is not empty { // Restore the highlighting values for (mm = 0; mm < kk; mm++) { if (current_selections[mm]) { XmListSelectPos(map_properties_list,mm,TRUE); } } // Free the highlighting array we allocated free(current_selections); } // Restore our place in the dialog XtVaSetValues(map_properties_list, XmNtopItemPosition, top_position, NULL); } } // Removes the highlighting for maps in the current view of the map // properties list. // void map_properties_deselect_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, deselecting every line for(x=1; x<=i; x++) { if (XmListPosSelected(map_properties_list,x)) { XmListDeselectPos(map_properties_list,x); } } } // Selects all maps in the current view of the map properties list. // void map_properties_select_all_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, selecting every line for(x=1; x<=i; x++) { // Deselect each one first, in case already selected XmListDeselectPos(map_properties_list,x); // Select/highlight that position XmListSelectPos(map_properties_list,x,TRUE); } } // Change the "draw_filled" field in the in-memory map_index to a // two. void map_index_update_filled_auto(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 2; break; } current = current->next; } } // Change the "draw_filled" field in the in-memory map_index to a // one. void map_index_update_filled_yes(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 1; break; } current = current->next; } } // Change the "draw_filled" field in the in-memory map_index to a // zero. void map_index_update_filled_no(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 0; break; } current = current->next; } } void map_properties_filled_auto(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 2. map_index_update_filled_auto(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_filled_yes(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 1. map_index_update_filled_yes(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_filled_no(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 0. map_index_update_filled_no(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Change the "usgs_drg" field in the in-memory map_index to a // specified value. void map_index_update_usgs_drg(char *filename, int drg_setting) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->usgs_drg = drg_setting; break; } current = current->next; } } // common functionality of all the callbacks. Probably don't even need // all the X data here, either void map_properties_usgs_drg(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData), int drg_setting) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the usgs_drg field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "usgs_drg" field to drg_setting. map_index_update_usgs_drg(&temp[MPD_FILENAME_OFFSET],drg_setting); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // the real callbacks void map_properties_usgs_drg_auto(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 2); } void map_properties_usgs_drg_yes(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 1); } void map_properties_usgs_drg_no(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 0); } // Change the "auto_maps" field in the in-memory map_index to a one. void map_index_update_auto_maps_yes(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->auto_maps = 1; return; } current = current->next; } } // Change the "auto_maps" field in the in-memory map_index to a // zero. void map_index_update_auto_maps_no(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->auto_maps = 0; return; } current = current->next; } } void map_properties_auto_maps_yes(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the auto_maps field // on every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "auto_maps" field to 1. map_index_update_auto_maps_yes(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_auto_maps_no(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the auto_maps field // on every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "auto_maps" field to 0. map_index_update_auto_maps_no(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "map_layer" field in the in-memory map_index based on // the "map_layer" input parameter. void map_index_update_layer(char *filename, int map_layer) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->map_layer = map_layer; return; } current = current->next; } } void map_properties_layer_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_layer; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_map_layer_text); new_layer = atoi(temp); XtFree(temp); //fprintf(stderr,"New layer selected is: %d\n", new_layer); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_layer(&temp[MPD_FILENAME_OFFSET], new_layer); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "max_zoom" field in the in-memory map_index based on // the "max_zoom" input parameter. void map_index_update_max_zoom(char *filename, int max_zoom) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->max_zoom = max_zoom; return; } current = current->next; } } void map_properties_max_zoom_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_max_zoom; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_max_zoom_text); new_max_zoom = atoi(temp); XtFree(temp); // fprintf(stderr,"New max_zoom selected is: %d\n", new_max_zoom); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_max_zoom(&temp[MPD_FILENAME_OFFSET], new_max_zoom); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "min_zoom" field in the in-memory map_index based on // the "min_zoom" input parameter. void map_index_update_min_zoom(char *filename, int min_zoom) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->min_zoom = min_zoom; return; } current = current->next; } } void map_properties_min_zoom_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_min_zoom; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_min_zoom_text); new_min_zoom = atoi(temp); XtFree(temp); //fprintf(stderr,"New layer selected is: %d\n", new_layer); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_min_zoom(&temp[MPD_FILENAME_OFFSET], new_min_zoom); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // JMT -- now supports max and min zoom levels // Allows setting map layer and filled polygon properties for maps // selected in the map chooser. Show a warning or bring up a // confirmation dialog if more than one map is selected when this // function is entered. This is the callback function for the // Properties button in the Map Chooser. // // If the map_layer is a range of values, inform the user here // via a popup, so that they don't make a mistake and change too // many different types of maps to the same map layer. // // We could either show all maps here and allow changing each // one, or just show min/max map_layer draw_filled properties // for the maps selected in the Map Chooser. // // Create the properties dialog. Show the map_layer and // draw_filled properties for the maps. // // Could still create Cancel and OK buttons. Cancel would wipe the // in-memory list and fetch it from file again. OK would write the // in-memory list to disk. // void map_properties( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // int i; // int x; // char *temp; // XmString *list; static Widget pane, my_form, button_clear, button_close, rowcol1, rowcol2, rowcol3, label1, label2, button_filled_auto, button_filled_yes, button_filled_no, button_usgs_drg_auto, button_usgs_drg_yes, button_usgs_drg_no, button_layer_change, button_auto_maps_yes, button_auto_maps_no, button_max_zoom_change, button_min_zoom_change, button_select_all; // static Widget label3, label4, label5; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count busy_cursor(appshell); if (map_chooser_dialog) { XtSetSensitive(map_chooser_button_ok, FALSE); XtSetSensitive(map_chooser_button_cancel, FALSE); } // i=0; if (!map_properties_dialog) { map_properties_dialog = XtVaCreatePopupShell(langcode("MAPP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Map_properties pane", xmPanedWindowWidgetClass, map_properties_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Map_properties my_form", xmFormWidgetClass, pane, XmNfractionBase, 7, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_properties_list = XmCreateScrolledList(my_form, "Map_properties list", al, ac); // Find the names of all the map files on disk and put them // into map_properties_list map_properties_fill_in(); // Attach a rowcolumn manager widget to my_form to handle // the third button row. Attach it to the bottom of the // form. rowcol3 = XtVaCreateManagedWidget("Map properties rowcol3", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Attach a rowcolumn manager widget to my_form to handle // the second button row. Attach it to the top of rowcol3. rowcol2 = XtVaCreateManagedWidget("Map properties rowcol2", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol3, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Attach a rowcolumn manager widget to my_form to handle // the first button row. rowcol1 = XtVaCreateManagedWidget("Map properties rowcol1", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol2, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label1 = XtVaCreateManagedWidget(langcode("MAPP002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label2 = XtVaCreateManagedWidget(langcode("MAPP003"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtVaSetValues(XtParent(map_properties_list), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label2, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol1, XmNbottomOffset, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // JMT -- this is a guess // "Max Zoom" stolen from "Change Layer" button_max_zoom_change = XtVaCreateManagedWidget(langcode("MAPP009"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_max_zoom_text = XtVaCreateManagedWidget("Map Properties max zoom number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // "Min Zoom" stolen from "Change Layer" button_min_zoom_change = XtVaCreateManagedWidget(langcode("MAPP010"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_min_zoom_text = XtVaCreateManagedWidget("Map Properties min zoom number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // "Change Layer" button_layer_change = XtVaCreateManagedWidget(langcode("MAPP004"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_map_layer_text = XtVaCreateManagedWidget("Map Properties new layer number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); //label3 XtVaCreateManagedWidget(langcode("MAPP005"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-Auto" button_filled_auto = XtVaCreateManagedWidget(langcode("MAPP011"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-Yes" button_filled_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-No" button_filled_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Automaps //label4 XtVaCreateManagedWidget(langcode("MAPP008"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Automaps-Yes" button_auto_maps_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Automaps-No" button_auto_maps_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // USGS DRG-> //label5 XtVaCreateManagedWidget(langcode("MAPP012"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG Auto" button_usgs_drg_auto = XtVaCreateManagedWidget(langcode("MAPP011"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG Yes" button_usgs_drg_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG No" button_usgs_drg_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Select All" button_select_all = XtVaCreateManagedWidget(langcode("PULDNMMC09"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Clear" button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC01"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Close" button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, map_properties_destroy_shell, map_properties_dialog); XtAddCallback(button_clear, XmNactivateCallback, map_properties_deselect_maps, map_properties_dialog); XtAddCallback(button_select_all, XmNactivateCallback, map_properties_select_all_maps, map_properties_dialog); XtAddCallback(button_filled_auto, XmNactivateCallback, map_properties_filled_auto, map_properties_dialog); XtAddCallback(button_filled_yes, XmNactivateCallback, map_properties_filled_yes, map_properties_dialog); XtAddCallback(button_filled_no, XmNactivateCallback, map_properties_filled_no, map_properties_dialog); XtAddCallback(button_usgs_drg_auto, XmNactivateCallback, map_properties_usgs_drg_auto, map_properties_dialog); XtAddCallback(button_usgs_drg_yes, XmNactivateCallback, map_properties_usgs_drg_yes, map_properties_dialog); XtAddCallback(button_usgs_drg_no, XmNactivateCallback, map_properties_usgs_drg_no, map_properties_dialog); XtAddCallback(button_max_zoom_change, XmNactivateCallback, map_properties_max_zoom_change, map_properties_dialog); XtAddCallback(button_min_zoom_change, XmNactivateCallback, map_properties_min_zoom_change, map_properties_dialog); XtAddCallback(button_layer_change, XmNactivateCallback, map_properties_layer_change, map_properties_dialog); XtAddCallback(button_auto_maps_yes, XmNactivateCallback, map_properties_auto_maps_yes, map_properties_dialog); XtAddCallback(button_auto_maps_no, XmNactivateCallback, map_properties_auto_maps_no, map_properties_dialog); pos_dialog(map_properties_dialog); delw = XmInternAtom(XtDisplay(map_properties_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_properties_dialog, delw, map_properties_destroy_shell, (XtPointer)map_properties_dialog); XtManageChild(rowcol1); XtManageChild(rowcol2); XtManageChild(rowcol3); XtManageChild(my_form); XtManageChild(map_properties_list); XtVaSetValues(map_properties_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XmTextSetString(new_map_layer_text, "0"); XtPopup(map_properties_dialog,XtGrabNone); // Move focus to the OK button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_properties_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_properties_dialog), XtWindow(map_properties_dialog)); } } /************************* Map Chooser ***********************************/ /*************************************************************************/ // Destroys the Map Chooser dialog void map_chooser_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); map_chooser_dialog = (Widget)NULL; } // Update the "selected" field in the in-memory map_index based on // the "selected" input parameter. void map_index_update_selected(char *filename, int selected, map_index_record **current) { // If we're passed a NULL pointer, start at the head of the // in-memory linked list. // if ( (*current) == NULL) { (*current) = map_index_head; } // Start searching through the list at the pointer we were // given. // while ( (*current) != NULL) { if (strcmp( (*current)->filename,filename) == 0) { // Found a match. Update the field and return. (*current)->selected = selected; return; } (*current) = (*current)->next; } } // Update the "temp_select" field in the in-memory map_index. void map_index_update_temp_select(char *filename, map_index_record **current) { int result; // If we're passed a NULL pointer, start at the head of the // in-memory linked list. // if ( (*current) == NULL) { (*current) = map_index_head; } // Start searching through the list at the pointer we were // given. We need to do a loose match here for directories. If // a selected directory is contained in a filepath, select that // file as well. For the directory case, once we find a match // in the file path, keep walking down the list until we get a // non-match. // while ( (*current) != NULL) { result = strncmp( (*current)->filename,filename,strlen(filename)); if (result == 0) { // Found a match. Update the field. (*current)->temp_select = 1; } else if (result > 0) // We passed the relevant area. { // All done for now. return; } (*current) = (*current)->next; } } // Clear all of the temp_select bits in the in-memory map index void map_index_temp_select_clear(void) { map_index_record *current; current = map_index_head; while (current != NULL) { current->temp_select = 0; current = current->next; } } // Gets the list of selected maps out of the dialog, writes them to // the selected maps disk file, destroys the dialog, then calls // create_image() with the newly selected map set in place. This // should be the _only_ routine in this set of functions that // actually changes the selected maps disk file. The others should // merely manipulate the list in the map chooser dialog. This // function is attached to the "OK" button in the Map Chooser dialog. // // What we'll do here is set/reset the "selected" field in the // in-memory map_index list, then write the info out to the // selected_maps.sys file. Only set the file entries if in file // mode, dir entries if in dir mode. When writing out to file, // write them both out. // // In order to make this fast, we'll send a start pointer to // map_index_update_selected() which is the "next" pointer from the // previous hit. We're relying on the fact that the Map Chooser // list and the in-memory linked list are in the same search order, // so this way we don't search through the entire linked list for // each update. With 30,000 maps, it ended up being up to 30,000 * // 30,000 for the loop iterations, which was unwieldy. // void map_chooser_select_maps(Widget widget, XtPointer clientData, XtPointer callData) { int i, x; char *temp; XmString *list; FILE *f; map_index_record *ptr = map_index_head; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // It'd be nice to turn off auto-maps here, or better perhaps would // be if any button were chosen other than "Cancel". // reset map_refresh in case we no longer have a refreshed map selected map_refresh_interval = 0; // Cause load_maps() and load_automaps() to re-sort the selected // maps by layer. re_sort_maps = 1; // Get the list and the list count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list, updating the equivalent entries in the // in-memory map index. If we're in "directory" mode we'll only // update the directory entries. In "Expanded dirs" mode, we'll // update both file and directory entries. // The end result is that both directories and files may be // selected, not either/or as the code was written earlier. // // Here we basically walk both lists together, the List widget // and the in-memory linked list, as they're both in the same // sort order. We do this by passing "ptr" back and forth, and // updating it to point to one after the last one found each // time. That turns and N*N search into an N search and is a // big speed improvement when you have 1000's of maps. // for(x=1; x<=i; x++) { temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory map // index, setting/resetting the "selected" field as // appropriate. map_index_update_selected(temp, XmListPosSelected(map_list,x), &ptr); XtFree(temp); } //fprintf(stderr,"Passed back: %s\n", ptr->filename); ptr = ptr->next; } // Now we have all of the updates done to the in-memory map // index. Write out the selected maps to disk, overwriting // whatever was there before. ptr = map_index_head; f=fopen( selected_map_path, "w+" ); if (f!=NULL) { while (ptr != NULL) { // Write only selected files/directories out to the disk // file. if (ptr->selected) { fprintf(f,"%s\n",ptr->filename); } ptr = ptr->next; } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } map_chooser_destroy_shell(widget,clientData,callData); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0; // } } // Same as map_chooser_select_maps, but doesn't destroy the Map // Chooser dialog. void map_chooser_apply_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; char *temp; XmString *list; FILE *f; map_index_record *ptr = map_index_head; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // It'd be nice to turn off auto-maps here, or better perhaps would // be if any button were chosen other than "Cancel". // reset map_refresh in case we no longer have a refreshed map selected map_refresh_interval = 0; // Cause load_maps() and load_automaps() to re-sort the selected // maps by layer. re_sort_maps = 1; // Get the list and the list count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list, updating the equivalent entries in the // in-memory map index. If we're in "directory" mode we'll only // update the directory entries. In "Expanded dirs" mode, we'll // update both file and directory entries. // The end result is that both directories and files may be // selected, not either/or as the code was written earlier. // // Here we basically walk both lists together, the List widget // and the in-memory linked list, as they're both in the same // sort order. We do this by passing "ptr" back and forth, and // updating it to point to one after the last one found each // time. That turns and N*N search into an N search and is a // big speed improvement when you have 1000's of maps. // for(x=1; x<=i; x++) { temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory map // index, setting/resetting the "selected" field as // appropriate. map_index_update_selected(temp, XmListPosSelected(map_list,x), &ptr); XtFree(temp); } //fprintf(stderr,"Passed back: %s\n", ptr->filename); ptr = ptr->next; } // Now we have all of the updates done to the in-memory map // index. Write out the selected maps to disk, overwriting // whatever was there before. ptr = map_index_head; f=fopen( selected_map_path, "w+" ); if (f!=NULL) { while (ptr != NULL) { // Write only selected files/directories out to the disk // file. if (ptr->selected) { fprintf(f,"%s\n",ptr->filename); } ptr = ptr->next; } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } // map_chooser_destroy_shell(widget,clientData,callData); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } // Counts the number of "selected" fields with a value of 1 in the // in-memory map index. Updates the "Dirs/Maps Selected" count in // the map chooser. void map_chooser_update_quantity(void) { int dir_quantity = 0; int map_quantity = 0; static char str_quantity[100]; map_index_record *current = map_index_head; XmString x_str; // Count the "selected" fields in the map index with value of 1 while (current != NULL) { if (current->selected) { if (current->filename[strlen(current->filename)-1] == '/') { // It's a directory dir_quantity++; } else { // It's a map map_quantity++; } } current = current->next; } // Update the "Dirs/Maps Selected" label in the Map Chooser xastir_snprintf(str_quantity, sizeof(str_quantity), "%d/%d", dir_quantity, map_quantity); x_str = XmStringCreateLocalized(str_quantity); XtVaSetValues(map_chooser_maps_selected_data, XmNlabelString, x_str, NULL); XmStringFree(x_str); } void map_chooser_select_vector_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); if ( (ext != NULL) && ( (strcasecmp(ext,"map") == 0) || (strcasecmp(ext,"shp") == 0) || (strcasecmp(ext,"gnis") == 0) || (strcasecmp(ext,"rt1") == 0) || (strcasecmp(ext,"rt2") == 0) || (strcasecmp(ext,"rt4") == 0) || (strcasecmp(ext,"rt5") == 0) || (strcasecmp(ext,"rt6") == 0) || (strcasecmp(ext,"rt7") == 0) || (strcasecmp(ext,"rt8") == 0) || (strcasecmp(ext,"rta") == 0) || (strcasecmp(ext,"rtc") == 0) || (strcasecmp(ext,"rth") == 0) || (strcasecmp(ext,"rti") == 0) || (strcasecmp(ext,"rtp") == 0) || (strcasecmp(ext,"rtr") == 0) || (strcasecmp(ext,"rts") == 0) || (strcasecmp(ext,"rtt") == 0) || (strcasecmp(ext,"rtz") == 0) || (strcasecmp(ext,"tab") == 0) ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_250k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'c') || (temp[length - 12] == 'C') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_100k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'f') || (temp[length - 12] == 'F') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_24k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'o') || (temp[length - 12] == 'O') || (temp[length - 12] == 'k') || (temp[length - 12] == 'K') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } // Removes the highlighting for maps in the current view of the map // chooser. In order to de-select all maps, must flip through both // map chooser views and hit the "none" button each time, then hit // the "ok" button. // // Changed the code to clear all of the "selected" bits in the // in-memory map index as well. The "None" and "OK" buttons take // immediate effect, all others do not (until the "OK" button is // pressed). Decided that this was too inconsistent, so changed it // back and changed "None" to "Clear", which means to clear the // currently seen selections, but not the selections in the other // mode. // void map_chooser_deselect_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // map_index_record *current = map_index_head; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, deselecting every line for(x=1; x<=i; x++) { if (XmListPosSelected(map_list,x)) { XmListDeselectPos(map_list,x); } } /* // Run through the in-memory map list, deselecting every line while (current != NULL) { current->selected = 0; // Not Selected current = current->next; } */ map_chooser_update_quantity(); } void sort_list(char *filename,int size, Widget list, int *item) { FILE *f_data; FILE *f_pointer; char fill[2000]; long file_ptr; // long ptr; char ptr_filename[400]; XmString str_ptr; // Clear the list widget first XmListDeleteAllItems(list); xastir_snprintf(ptr_filename, sizeof(ptr_filename), "%s-ptr", filename); f_pointer=fopen(ptr_filename,"r"); f_data=fopen(filename,"r"); if (f_pointer!=NULL && f_data !=NULL) { while (!feof(f_pointer)) { // ptr=ftell(f_pointer); if (fread(&file_ptr,sizeof(file_ptr),1,f_pointer)==1) { (void)fseek(f_data,file_ptr,SEEK_SET); if (fread(fill,(size_t)size,1,f_data)==1) { str_ptr = XmStringCreateLocalized(fill); XmListAddItem(list, str_ptr,*item); XmStringFree(str_ptr); (*item)++; } } } } if(f_pointer!=NULL) { (void)fclose(f_pointer); } else { fprintf(stderr,"Couldn't open file: %s\n", ptr_filename); } if(f_data!=NULL) { (void)fclose(f_data); } else { fprintf(stderr,"Couldn't open file: %s\n", filename); } } // Mark the "selected" field in the in-memory map index based on the // contents of the selected_maps.sys file. Called from main() right // after map_indexer() is called on startup. void map_chooser_init (void) { FILE *f; char temp[600]; map_index_record *current; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); busy_cursor(appshell); // First run through our in-memory map index, clearing all of // the selected bits. current = map_index_head; while (current != NULL) { current->selected = 0; current = current->next; } (void)filecreate( selected_map_path ); // Create empty file if it doesn't exist f=fopen( selected_map_path, "r" ); if (f!=NULL) { while(!feof(f)) { int done; (void)get_line(f,temp,600); // We have a line from the file. Find the matching line // in the in-memory map index. current = map_index_head; done = 0; while (current != NULL && !done) { //fprintf(stderr,"%s\n",current->filename); if (strcmp(temp,current->filename) == 0) { current->selected = 1; done++; } current = current->next; } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } } // Fills in the map chooser file/directory entries based on the // current view and whether the "selected" field in the in-memory // map_index is set for each file/directory. // // We also check the XmStringPtr field in the map index records. If // NULL, then we call XmStringCreateLocalized() to allocate and fill in // the XmString value corresponding to the filename. We use that to // speed up Map Chooser later. // void map_chooser_fill_in (void) { int n,i; map_index_record *current = map_index_head; busy_cursor(appshell); i=0; if (map_chooser_dialog) { // Empty the map_list widget first XmListDeleteAllItems(map_list); // Put all the map files/dirs in the map_index into the Map // Chooser dialog list (map_list). n=1; while (current != NULL) { //fprintf(stderr,"%s\n",current->filename); // Check whether we're supposed to show dirs and files or // just dirs. Directories are always shown. if (map_chooser_expand_dirs // Show all || current->filename[strlen(current->filename)-1] == '/') { // Try XmListAddItems() here? Could also create XmString's for each // filename and keep them in the map index. Then we wouldn't have to // free that malloc/free that storage space all the time. // XmListAddItems() // XmListAddItemsUnselected() // XmListReplaceItems() // XmListReplaceItemsUnselected() // If pointer is NULL, malloc and create the // XmString corresponding to the filename, attach it // to the record. The 2nd and succeeding times we // bring up Map Chooser, things will be faster. if (current->XmStringPtr == NULL) { current->XmStringPtr = XmStringCreateLocalized(current->filename); } XmListAddItem(map_list, current->XmStringPtr, n); // If a selected map, highlight it in the list if (current->selected) { XmListSelectPos(map_list,i,TRUE); } n++; } current = current->next; } } } /////////////////////////////////////// Configure DRG Dialog ////////////////////////////////////////////// #if defined(HAVE_LIBGEOTIFF) void Configure_DRG_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (configure_DRG_dialog) { XtPopdown(shell); XtDestroyWidget(shell); configure_DRG_dialog = (Widget)NULL; } } void Configure_DRG_change_data(Widget widget, XtPointer clientData, XtPointer callData) { if (configure_DRG_dialog) { if(XmToggleButtonGetState(DRG_XOR)) { DRG_XOR_colors=TRUE; } else { DRG_XOR_colors=FALSE; } if(XmToggleButtonGetState(DRG_color0)) { DRG_show_colors[0]=TRUE; } else { DRG_show_colors[0]=FALSE; } if(XmToggleButtonGetState(DRG_color1)) { DRG_show_colors[1]=TRUE; } else { DRG_show_colors[1]=FALSE; } if(XmToggleButtonGetState(DRG_color2)) { DRG_show_colors[2]=TRUE; } else { DRG_show_colors[2]=FALSE; } if(XmToggleButtonGetState(DRG_color3)) { DRG_show_colors[3]=TRUE; } else { DRG_show_colors[3]=FALSE; } if(XmToggleButtonGetState(DRG_color4)) { DRG_show_colors[4]=TRUE; } else { DRG_show_colors[4]=FALSE; } if(XmToggleButtonGetState(DRG_color5)) { DRG_show_colors[5]=TRUE; } else { DRG_show_colors[5]=FALSE; } if(XmToggleButtonGetState(DRG_color6)) { DRG_show_colors[6]=TRUE; } else { DRG_show_colors[6]=FALSE; } if(XmToggleButtonGetState(DRG_color7)) { DRG_show_colors[7]=TRUE; } else { DRG_show_colors[7]=FALSE; } if(XmToggleButtonGetState(DRG_color8)) { DRG_show_colors[8]=TRUE; } else { DRG_show_colors[8]=FALSE; } if(XmToggleButtonGetState(DRG_color9)) { DRG_show_colors[9]=TRUE; } else { DRG_show_colors[9]=FALSE; } if(XmToggleButtonGetState(DRG_color10)) { DRG_show_colors[10]=TRUE; } else { DRG_show_colors[10]=FALSE; } if(XmToggleButtonGetState(DRG_color11)) { DRG_show_colors[11]=TRUE; } else { DRG_show_colors[11]=FALSE; } if(XmToggleButtonGetState(DRG_color12)) { DRG_show_colors[12]=TRUE; } else { DRG_show_colors[12]=FALSE; } Configure_DRG_destroy_shell(widget,clientData,callData); // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls // create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } void Configure_DRG_all(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (configure_DRG_dialog) { XmToggleButtonSetState(DRG_color0,TRUE,FALSE); XmToggleButtonSetState(DRG_color1,TRUE,FALSE); XmToggleButtonSetState(DRG_color2,TRUE,FALSE); XmToggleButtonSetState(DRG_color3,TRUE,FALSE); XmToggleButtonSetState(DRG_color4,TRUE,FALSE); XmToggleButtonSetState(DRG_color5,TRUE,FALSE); XmToggleButtonSetState(DRG_color6,TRUE,FALSE); XmToggleButtonSetState(DRG_color7,TRUE,FALSE); XmToggleButtonSetState(DRG_color8,TRUE,FALSE); XmToggleButtonSetState(DRG_color9,TRUE,FALSE); XmToggleButtonSetState(DRG_color10,TRUE,FALSE); XmToggleButtonSetState(DRG_color11,TRUE,FALSE); XmToggleButtonSetState(DRG_color12,TRUE,FALSE); } } void Configure_DRG_none(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (configure_DRG_dialog) { XmToggleButtonSetState(DRG_color0,FALSE,FALSE); XmToggleButtonSetState(DRG_color1,FALSE,FALSE); XmToggleButtonSetState(DRG_color2,FALSE,FALSE); XmToggleButtonSetState(DRG_color3,FALSE,FALSE); XmToggleButtonSetState(DRG_color4,FALSE,FALSE); XmToggleButtonSetState(DRG_color5,FALSE,FALSE); XmToggleButtonSetState(DRG_color6,FALSE,FALSE); XmToggleButtonSetState(DRG_color7,FALSE,FALSE); XmToggleButtonSetState(DRG_color8,FALSE,FALSE); XmToggleButtonSetState(DRG_color9,FALSE,FALSE); XmToggleButtonSetState(DRG_color10,FALSE,FALSE); XmToggleButtonSetState(DRG_color11,FALSE,FALSE); XmToggleButtonSetState(DRG_color12,FALSE,FALSE); } } void Config_DRG( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget DRG_pane, scrollwindow, DRG_form, button_ok, button_cancel, DRG_label1, sep1, sep2, button_all, button_none; Atom delw; if (!configure_DRG_dialog) { configure_DRG_dialog = XtVaCreatePopupShell(langcode("PULDNMP030"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); DRG_pane = XtVaCreateWidget("Configure_DRG pane", xmPanedWindowWidgetClass, configure_DRG_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, DRG_pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); DRG_form = XtVaCreateWidget("Configure_DRG DRG_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); DRG_XOR = XtVaCreateManagedWidget(langcode("MPUPDRG002"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep1 = XtVaCreateManagedWidget("Config DRG sep1", xmSeparatorGadgetClass, DRG_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, DRG_XOR, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); DRG_label1 = XtVaCreateManagedWidget(langcode("MPUPDRG001"), xmLabelWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 1 // Black DRG_color0 = XtVaCreateManagedWidget(langcode("MPUPDRG003"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Blue DRG_color2 = XtVaCreateManagedWidget(langcode("MPUPDRG005"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color0, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Red DRG_color3 = XtVaCreateManagedWidget(langcode("MPUPDRG006"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Brown DRG_color4 = XtVaCreateManagedWidget(langcode("MPUPDRG007"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color3, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Purple DRG_color6 = XtVaCreateManagedWidget(langcode("MPUPDRG009"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 2 // Light Gray DRG_color11 = XtVaCreateManagedWidget(langcode("MPUPDRG014"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Blue DRG_color8 = XtVaCreateManagedWidget(langcode("MPUPDRG011"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color11, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Red DRG_color9 = XtVaCreateManagedWidget(langcode("MPUPDRG012"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color8, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Brown DRG_color12 = XtVaCreateManagedWidget(langcode("MPUPDRG015"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color9, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Purple DRG_color10 = XtVaCreateManagedWidget(langcode("MPUPDRG013"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color12, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 3 // White DRG_color1 = XtVaCreateManagedWidget(langcode("MPUPDRG004"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Green DRG_color5 = XtVaCreateManagedWidget(langcode("MPUPDRG008"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Yellow DRG_color7 = XtVaCreateManagedWidget(langcode("MPUPDRG010"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color5, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep2 = XtVaCreateManagedWidget("Config DRG sep2", xmSeparatorGadgetClass, DRG_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, DRG_color6, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_all = XtVaCreateManagedWidget(langcode("PULDNMMC09"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_none = XtVaCreateManagedWidget(langcode("PULDNDP040"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_all, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_none, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_ok, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_all, XmNactivateCallback, Configure_DRG_all, configure_DRG_dialog); XtAddCallback(button_none, XmNactivateCallback, Configure_DRG_none, configure_DRG_dialog); XtAddCallback(button_ok, XmNactivateCallback, Configure_DRG_change_data, configure_DRG_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_DRG_destroy_shell, configure_DRG_dialog); pos_dialog(configure_DRG_dialog); delw = XmInternAtom(XtDisplay(configure_DRG_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_DRG_dialog, delw, Configure_DRG_destroy_shell, (XtPointer)configure_DRG_dialog); if(DRG_XOR_colors) { XmToggleButtonSetState(DRG_XOR,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_XOR,FALSE,FALSE); } if(DRG_show_colors[0]) { XmToggleButtonSetState(DRG_color0,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color0,FALSE,FALSE); } if(DRG_show_colors[1]) { XmToggleButtonSetState(DRG_color1,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color1,FALSE,FALSE); } if(DRG_show_colors[2]) { XmToggleButtonSetState(DRG_color2,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color2,FALSE,FALSE); } if(DRG_show_colors[3]) { XmToggleButtonSetState(DRG_color3,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color3,FALSE,FALSE); } if(DRG_show_colors[4]) { XmToggleButtonSetState(DRG_color4,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color4,FALSE,FALSE); } if(DRG_show_colors[5]) { XmToggleButtonSetState(DRG_color5,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color5,FALSE,FALSE); } if(DRG_show_colors[6]) { XmToggleButtonSetState(DRG_color6,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color6,FALSE,FALSE); } if(DRG_show_colors[7]) { XmToggleButtonSetState(DRG_color7,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color7,FALSE,FALSE); } if(DRG_show_colors[8]) { XmToggleButtonSetState(DRG_color8,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color8,FALSE,FALSE); } if(DRG_show_colors[9]) { XmToggleButtonSetState(DRG_color9,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color9,FALSE,FALSE); } if(DRG_show_colors[10]) { XmToggleButtonSetState(DRG_color10,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color10,FALSE,FALSE); } if(DRG_show_colors[11]) { XmToggleButtonSetState(DRG_color11,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color11,FALSE,FALSE); } if(DRG_show_colors[12]) { XmToggleButtonSetState(DRG_color12,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color12,FALSE,FALSE); } XtManageChild(DRG_form); XtManageChild(DRG_pane); resize_dialog(DRG_form, configure_DRG_dialog); XtPopup(configure_DRG_dialog,XtGrabNone); XmProcessTraversal(button_ok, XmTRAVERSE_CURRENT); } else (void)XRaiseWindow(XtDisplay(configure_DRG_dialog), XtWindow(configure_DRG_dialog)); } #endif // HAVE_LIBGEOTIFF ///////////////////////// End of Configure DRG code /////////////////////////////////// void Expand_Dirs_toggle( Widget w, XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_chooser_expand_dirs = atoi(which); } else { map_chooser_expand_dirs = 0; } // Kill/resurrect the Map Chooser so that the changes take // effect. map_chooser_destroy_shell( w, map_chooser_dialog, (XtPointer) NULL); Map_chooser( w, (XtPointer)NULL, (XtPointer) NULL); map_chooser_update_quantity(); } void Map_chooser( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_clear, button_V, button_C, button_F, button_O, rowcol, expand_dirs_button, button_properties, maps_selected_label, button_apply; Atom delw; // int i; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ busy_cursor(appshell); // i=0; if (!map_chooser_dialog) { map_chooser_dialog = XtVaCreatePopupShell(langcode("WPUPMCP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Map_chooser pane", xmPanedWindowWidgetClass, map_chooser_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Map_chooser my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 7, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_list = XmCreateScrolledList(my_form, "Map_chooser list", al, ac); // Find the names of all the map files on disk and put them into map_list map_chooser_fill_in(); expand_dirs_button = XtVaCreateManagedWidget(langcode("PULDNMMC06"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(expand_dirs_button,XmNvalueChangedCallback,Expand_Dirs_toggle,"1"); if(map_chooser_expand_dirs) { XmToggleButtonSetState(expand_dirs_button,TRUE,FALSE); } else { XmToggleButtonSetState(expand_dirs_button,FALSE,FALSE); } maps_selected_label = XtVaCreateManagedWidget(langcode("PULDNMMC07"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, expand_dirs_button, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); map_chooser_maps_selected_data = XtVaCreateManagedWidget("0/0", xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, maps_selected_label, XmNleftOffset, 2, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Button for configuring properties button_properties = XtVaCreateManagedWidget(langcode("UNIOP00009"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_properties, XmNactivateCallback, map_properties, map_chooser_dialog); // Attach a rowcolumn manager widget to my_form to handle all of the buttons rowcol = XtVaCreateManagedWidget("Map Chooser rowcol", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtVaSetValues(XtParent(map_list), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, expand_dirs_button, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol, XmNbottomOffset, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // "Clear" if(map_chooser_expand_dirs) // "Clear" { button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC01"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } else // "Clear Dirs" { button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC08"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } // "Vector Maps" button_V = XtVaCreateManagedWidget(langcode("PULDNMMC02"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "250k Topos" button_C = XtVaCreateManagedWidget(langcode("PULDNMMC03"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "100k Topos" button_F = XtVaCreateManagedWidget(langcode("PULDNMMC04"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "24k Topos" button_O = XtVaCreateManagedWidget(langcode("PULDNMMC05"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Apply" button_apply = XtVaCreateManagedWidget(langcode("UNIOP00032"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "OK" map_chooser_button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Cancel" map_chooser_button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_apply, XmNactivateCallback, map_chooser_apply_maps, map_chooser_dialog); XtAddCallback(map_chooser_button_cancel, XmNactivateCallback, map_chooser_destroy_shell, map_chooser_dialog); XtAddCallback(map_chooser_button_ok, XmNactivateCallback, map_chooser_select_maps, map_chooser_dialog); XtAddCallback(button_clear, XmNactivateCallback, map_chooser_deselect_maps, map_chooser_dialog); XtAddCallback(button_V, XmNactivateCallback, map_chooser_select_vector_maps, map_chooser_dialog); #ifdef HAVE_LIBGEOTIFF XtAddCallback(button_C, XmNactivateCallback, map_chooser_select_250k_maps, map_chooser_dialog); XtAddCallback(button_F, XmNactivateCallback, map_chooser_select_100k_maps, map_chooser_dialog); XtAddCallback(button_O, XmNactivateCallback, map_chooser_select_24k_maps, map_chooser_dialog); #endif /* HAVE_LIBGEOTIFF */ if(!map_chooser_expand_dirs) { XtSetSensitive(button_V, FALSE); XtSetSensitive(button_C, FALSE); XtSetSensitive(button_F, FALSE); XtSetSensitive(button_O, FALSE); } pos_dialog(map_chooser_dialog); delw = XmInternAtom(XtDisplay(map_chooser_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_chooser_dialog, delw, map_chooser_destroy_shell, (XtPointer)map_chooser_dialog); XtManageChild(rowcol); XtManageChild(my_form); XtManageChild(map_list); XtVaSetValues(map_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, map_chooser_dialog); XtPopup(map_chooser_dialog,XtGrabNone); // Move focus to the OK button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_chooser_dialog); XmProcessTraversal(map_chooser_button_ok, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_chooser_dialog), XtWindow(map_chooser_dialog)); } map_chooser_update_quantity(); } /****** Read in file **********/ void read_file_selection_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtDestroyWidget(shell); read_selection_dialog = (Widget)NULL; } void read_file_selection_now(Widget w, XtPointer clientData, XtPointer callData) { char *file; XmFileSelectionBoxCallbackStruct *cbs =(XmFileSelectionBoxCallbackStruct*)callData; file = XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(file) { // fprintf(stderr,"FILE is %s\n",file); // Make sure we're not already reading a file and the user actually // selected a file (if not, the last character will be a '/'). if ( (!read_file) && (file[strlen(file) - 1] != '/') ) { /* do read file start */ read_file_ptr = fopen(file,"r"); if (read_file_ptr != NULL) { read_file = 1; } else { fprintf(stderr,"Couldn't open file: %s\n", file); } } XtFree(file); } read_file_selection_destroy_shell(w, clientData, callData); // Note that we leave the file in the "open" state. UpdateTime // comes along shortly and reads the file. } void Read_File_Selection( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ Widget fs; Widget child; char temp_base_dir[MAX_VALUE]; if (read_selection_dialog!=NULL) { read_file_selection_destroy_shell(read_selection_dialog, read_selection_dialog, NULL); } if(read_selection_dialog==NULL) { // This is necessary because the resources for setting the // directory in the FileSelectionDialog aren't working in Lesstif. if (chdir( get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)) ) != 0) { fprintf(stderr,"Couldn't chdir to the file selection\n"); return; } /*set args for color */ ac=0; XtSetArg(al[ac], XmNtitle, langcode("PULDNFI002")); ac++; // Open Log File XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; //XtSetArg(al[ac], XmNdirMask, "/home/hacker/.xastir/logs/*"); ac++; //XtSetArg(al[ac], XmNdirectory, "/home/hacker/.xastir/logs/"); ac++; //XtSetArg(al[ac], XmNpattern, "*"); ac++; //XtSetArg(al[ac], XmNdirMask, ".xastir/logs/*"); ac++; read_selection_dialog = XmCreateFileSelectionDialog(appshell, "filesb", al, ac); // Change back to the base directory if (chdir( get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)) ) != 0) { fprintf(stderr,"Couldn't chdir back to the base directory\n"); return; } fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_TEXT); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_FILTER_TEXT); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_DIR_LIST); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_LIST); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); //XtVaSetValues(read_selection_dialog, XmNdirMask, "/home/hacker/.xastir/logs/*", NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_FILTER_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_DIR_LIST_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_LIST_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_SELECTION_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_OK_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_APPLY_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_CANCEL_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_HELP_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); XtAddCallback(read_selection_dialog, XmNcancelCallback,read_file_selection_destroy_shell,read_selection_dialog); XtAddCallback(read_selection_dialog, XmNokCallback,read_file_selection_now,read_selection_dialog); XtAddCallback(read_selection_dialog, XmNhelpCallback, Help_Index, read_selection_dialog); XtManageChild(read_selection_dialog); pos_dialog(read_selection_dialog); } } void Test(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // static char temp[256]; // int port = 7; mdisplay_file(0); // mem_display(); alert_print_list(); /* draw_wind_barb(50000000l, // long x_long, 32000000l, // long y_lat, "169", // char *speed, "005", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(60000000l, // long x_long, 32000000l, // long y_lat, "009", // char *speed, "123", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(70000000l, // long x_long, 32000000l, // long y_lat, "109", // char *speed, "185", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(80000000l, // long x_long, 32000000l, // long y_lat, "079", // char *speed, "275", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); */ // fprintf(stderr,"view_zero_distance_bulletins = %d\n", // view_zero_distance_bulletins); /* // Simulate data coming in from a TNC in order to test igating. // Port 7 in this case is a serial TNC port (in my current test // configuration). xastir_snprintf(temp, sizeof(temp), "WE7U-4>APOT01,SUMAS*,WIDE2-2:!4757.28N/12212.00Wv178/057/A=000208 14.0V 30C\r"); if (begin_critical_section(&data_lock, "main.c" ) > 0) fprintf(stderr,"data_lock, Port = %d\n", port); incoming_data=temp; incoming_data_length = strlen(temp); data_port = port; data_avail = 1; if (end_critical_section(&data_lock, "main.c" ) > 0) fprintf(stderr,"data_lock, Port = %d\n", port); fprintf(stderr, "Sent: %s\n", temp); */ // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); } /****** Save Config data **********/ void Save_Config( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { save_data(); } /////////////////////////////////// Configure Defaults Dialog ////////////////////////////////// void Configure_defaults_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_defaults_dialog = (Widget)NULL; } void Configure_defaults_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; int load_predefined_cb_selected; XmString load_predefined_cb_selection; output_station_type = Station_transmit_type; if ((output_station_type >= 1) && (output_station_type <= 3)) { next_time = 60; max_transmit_time = (time_t)120l; // shorter beacon interval for mobile stations } else { max_transmit_time = (time_t)900l; } // Check for proper symbol in case we're a weather station (void)check_weather_symbol(); // Check for NWS symbol and print warning if so (void)check_nws_weather_symbol(); #ifdef TRANSMIT_RAW_WX transmit_raw_wx = (int)XmToggleButtonGetState(raw_wx_tx); #endif // TRANSMIT_RAW_WX transmit_compressed_objects_items = (int)XmToggleButtonGetState(compressed_objects_items_tx); pop_up_new_bulletins = (int)XmToggleButtonGetState(new_bulletin_popup_enable); view_zero_distance_bulletins = (int)XmToggleButtonGetState(zero_bulletin_popup_enable); // user interface refers to all my trails in one color // my trail diff color as 0 means my trails in one color, so select // button when my trail diff color is 0 rather than 1. my_trail_diff_color = !(int)XmToggleButtonGetState(my_trail_diff_color_enable); // Predefined (SAR/EVENT) objects menu loading (default hardcoded SAR objects or objects from file) predefined_menu_from_file = (int)XmToggleButtonGetState(load_predefined_objects_menu_from_file_enable); // Use the file specified on the picklist if one is selected. load_predefined_cb_selected = 0; #ifdef USE_COMBO_BOX XtVaGetValues(load_predefined_objects_menu_from_file, XmNselectedPosition, &load_predefined_cb_selected, NULL); #else load_predefined_cb_selected = lpomff_value; #endif //USE_COMBO_BOX // Use the file specified on the picklist if one is selected. if (load_predefined_cb_selected > 0) { // XtVaGetValues() expects to be able to write into // allocated memory. // load_predefined_cb_selection = (XmString)malloc(MAX_FILENAME); #ifdef USE_COMBO_BOX XtVaGetValues(load_predefined_objects_menu_from_file, XmNselectedItem, &load_predefined_cb_selection, NULL); #else switch (load_predefined_cb_selected) { case 1: load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); break; case 2: load_predefined_cb_selection = XmStringCreateLocalized("predefined_EVENT.sys"); break; case 3: load_predefined_cb_selection = XmStringCreateLocalized("predefined_USER.sys"); break; case 4: load_predefined_cb_selection = XmStringCreateLocalized(predefined_object_definition_filename); break; default: load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); } #endif //USE_COMBO_BOX } else { load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); } xastir_snprintf(predefined_object_definition_filename, sizeof(predefined_object_definition_filename), "%s", temp = XmStringUnparse(load_predefined_cb_selection, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL) ); XtFree(temp); XmStringFree(load_predefined_cb_selection); // Repopulate the predefined object (SAR/Public service) struct Populate_predefined_objects(predefinedObjects); // Rebuild the predefined objects SAR/Public service menu. BuildPredefinedSARMenu_UI(&sar_object_sub); warn_about_mouse_modifiers = (int)XmToggleButtonGetState(warn_about_mouse_modifiers_enable); altnet = (int)(XmToggleButtonGetState(altnet_active)); skip_dupe_checking = (int)(XmToggleButtonGetState(disable_dupe_check)); temp = XmTextGetString(altnet_text); xastir_snprintf(altnet_call, sizeof(altnet_call), "%s", temp); XtFree(temp); (void)remove_trailing_spaces(altnet_call); if (strlen(altnet_call)==0) { altnet = FALSE; xastir_snprintf(altnet_call, sizeof(altnet_call), "XASTIR"); } operate_as_an_igate=Igate_type; redraw_on_new_data=2; Configure_defaults_destroy_shell(widget,clientData,callData); } /* Station_transmit type radio buttons */ void station_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Station_transmit_type = atoi(which); } else { Station_transmit_type = 0; } } /* Igate type radio buttons */ void igate_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Igate_type = atoi(which); } else { Igate_type = 0; } } #ifndef USE_COMBO_BOX void lpomff_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //clsd_menu is zero based, cad_line_style_data constants are one based. lpomff_value = (int)userData + 1; if (debug_level & 1) { fprintf(stderr,"Selected value on cad line type pulldown: %d\n",lpomff_value); } } #endif // !USE_COMBO_BOX void Configure_defaults( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, frame4, frame5, type_box, styp1, styp2, styp3, styp4, styp5, styp6, igate_box, igtyp0, igtyp1, igtyp2, altnet_label; // static Widget station_type, igate_option; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ #ifndef USE_COMBO_BOX Widget lpomff_menuPane; Widget lpomff_button; Widget lpomff_buttons[4]; Widget lpomff_menu; char buf[18]; int x; #endif // !USE_COMBO_BOX Widget lpomff_widget; int i; XmString cb_items[4]; #ifdef OBJECT_DEF_FILE_USER_BASE char temp_base_dir[MAX_VALUE]; #endif if (!configure_defaults_dialog) { char loadfrom[300]; // Set args for color ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; configure_defaults_dialog = XtVaCreatePopupShell(langcode("WPUPCFD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_defaults pane", xmPanedWindowWidgetClass, configure_defaults_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_defaults my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Transmit Station Options frame4 = XtVaCreateManagedWidget("Configure_defaults frame4", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //station_type XtVaCreateManagedWidget(langcode("WPUPCFD015"), xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); type_box = XmCreateRadioBox(frame4, "Configure_defaults Transmit Options box", al, ac); XtVaSetValues(type_box, XmNnumColumns,2, NULL); styp1 = XtVaCreateManagedWidget(langcode("WPUPCFD016"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp1,XmNvalueChangedCallback,station_type_toggle,"0"); styp2 = XtVaCreateManagedWidget(langcode("WPUPCFD017"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp2,XmNvalueChangedCallback,station_type_toggle,"1"); styp3 = XtVaCreateManagedWidget(langcode("WPUPCFD018"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp3,XmNvalueChangedCallback,station_type_toggle,"2"); styp4 = XtVaCreateManagedWidget(langcode("WPUPCFD019"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp4,XmNvalueChangedCallback,station_type_toggle,"3"); styp5 = XtVaCreateManagedWidget(langcode("WPUPCFD021"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp5,XmNvalueChangedCallback,station_type_toggle,"4"); styp6 = XtVaCreateManagedWidget(langcode("WPUPCFD022"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp6,XmNvalueChangedCallback,station_type_toggle,"5"); // Igate Options frame5 = XtVaCreateManagedWidget("Configure_defaults frame5", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //igate_option XtVaCreateManagedWidget(langcode("IGPUPCF000"), xmLabelWidgetClass, frame5, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); igate_box = XmCreateRadioBox(frame5, "Configure_defaults Igate Options box", al, ac); XtVaSetValues(igate_box, XmNnumColumns,2, NULL); igtyp0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp0,XmNvalueChangedCallback,igate_type_toggle,"0"); igtyp1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp1,XmNvalueChangedCallback,igate_type_toggle,"1"); igtyp2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp2,XmNvalueChangedCallback,igate_type_toggle,"2"); // Miscellaneous Options compressed_objects_items_tx = XtVaCreateManagedWidget(langcode("WPUPCFD024"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_bulletin_popup_enable = XtVaCreateManagedWidget(langcode("WPUPCFD027"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, compressed_objects_items_tx, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); zero_bulletin_popup_enable = XtVaCreateManagedWidget(langcode("WPUPCFD029"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); warn_about_mouse_modifiers_enable = XtVaCreateManagedWidget(langcode("WPUPCFD028"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zero_bulletin_popup_enable, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Show all My trails in one color my_trail_diff_color_enable = XtVaCreateManagedWidget(langcode("WPUPCFD032"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, warn_about_mouse_modifiers_enable, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Check box to load predefined (SAR/Event) objects menu from a file or not. xastir_snprintf(loadfrom, sizeof(loadfrom), "%s %s", langcode("WPUPCFD031"), #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir))); #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config")); #endif // OBJECT_DEF_FILE_USER_BASE load_predefined_objects_menu_from_file_enable = XtVaCreateManagedWidget(loadfrom, xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zero_bulletin_popup_enable, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lesstif as of 0.95 in 2008 doesn't fully support combo boxes // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. cb_items[0] = XmStringCreateLocalized("predefined_SAR.sys"); cb_items[1] = XmStringCreateLocalized("predefined_EVENT.sys"); cb_items[2] = XmStringCreateLocalized("predefined_USER.sys"); #ifdef USE_COMBO_BOX // Combo box to pick file from which to load predefined objects menu load_predefined_objects_menu_from_file = XtVaCreateManagedWidget("Load objects menu filename ComboBox", xmComboBoxWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zero_bulletin_popup_enable, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, load_predefined_objects_menu_from_file_enable, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[0],1,1); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[1],2,1); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[2],3,1); lpomff_widget = load_predefined_objects_menu_from_file; #else // Menu replacement for combo box when using lesstif. // Not a full replacement, as combo box in motif can have editable values, // not just selection from predefined list as is the case here. ac = 0; XtSetArg(al[ac], XmNmarginWidth, 0); ac++; XtSetArg(al[ac], XmNmarginHeight, 0); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; lpomff_menuPane = XmCreatePulldownMenu(my_form,"lpomff_menuPane", al, ac); //lpomff_menu is zero based, constants for filenames are one based //lpomff_value is set to match constants in callback. for (i=0; i<3; i++) { ac = 0; XtSetArg(al[ac], XmNlabelString, cb_items[i]); ac++; XtSetArg(al[ac], XmNuserData, (XtPointer)i); ac++; sprintf(buf,"button%d",i); lpomff_button = XmCreatePushButton(lpomff_menuPane, buf, al, ac); XtManageChild(lpomff_button); XtAddCallback(lpomff_button, XmNactivateCallback, lpomff_menuCallback, Configure_defaults); lpomff_buttons[i] = lpomff_button; } ac = 0; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ++ac; XtSetArg(al[ac], XmNleftWidget, load_predefined_objects_menu_from_file_enable); ++ac; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ++ac; XtSetArg(al[ac], XmNtopWidget, zero_bulletin_popup_enable); ++ac; XtSetArg(al[ac], XmNmarginWidth, 0); ++ac; XtSetArg(al[ac], XmNmarginHeight, 0); ++ac; XtSetArg(al[ac], XmNtopOffset, 5); ++ac; XtSetArg(al[ac], XmNleftOffset, 10); ++ac; XtSetArg(al[ac], XmNsubMenuId, lpomff_menuPane); ++ac; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; lpomff_menu = XmCreateOptionMenu(my_form, "sddd_Menu", al, ac); XtManageChild(lpomff_menu); lpomff_value = 2; // set a default value (line on off dash) lpomff_widget = lpomff_menu; #endif // USE_COMBO_BOX // free up space from combo box strings for (i=0; i<3; i++) { XmStringFree(cb_items[i]); } #ifdef TRANSMIT_RAW_WX raw_wx_tx = XtVaCreateManagedWidget(langcode("WPUPCFD023"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lpomff_widget, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); #endif // TRANSMIT_RAW_WX altnet_active = XtVaCreateManagedWidget(langcode("WPUPCFD025"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, compressed_objects_items_tx, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "ALTNET:" altnet_label = XtVaCreateManagedWidget(langcode("WPUPCFD033"), xmLabelWidgetClass, my_form, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, altnet_active, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, compressed_objects_items_tx, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); altnet_text = XtVaCreateManagedWidget("Configure_defaults Altnet_text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNwidth, ((10*7)+2), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, altnet_active, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, altnet_label, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); disable_dupe_check = XtVaCreateManagedWidget(langcode("WPUPCFD030"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, altnet_active, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, #ifdef TRANSMIT_RAW_WX XmNtopWidget, raw_wx_tx, #else // TRANSMIT_RAW_WX XmNtopWidget, lpomff_widget, #endif // TRANSMIT_RAW_WX XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, #ifdef TRANSMIT_RAW_WX XmNtopWidget, raw_wx_tx, #else // TRANSMIT_RAW_WX XmNtopWidget, lpomff_widget, #endif // TRANSMIT_RAW_WX XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_defaults_change_data, configure_defaults_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_defaults_destroy_shell, configure_defaults_dialog); switch(output_station_type) { case(0): XmToggleButtonSetState(styp1,TRUE,FALSE); Station_transmit_type=0; break; case(1): XmToggleButtonSetState(styp2,TRUE,FALSE); Station_transmit_type=1; break; case(2): XmToggleButtonSetState(styp3,TRUE,FALSE); Station_transmit_type=2; break; case(3): XmToggleButtonSetState(styp4,TRUE,FALSE); Station_transmit_type=3; break; case(4): XmToggleButtonSetState(styp5,TRUE,FALSE); Station_transmit_type=4; break; case(5): XmToggleButtonSetState(styp6,TRUE,FALSE); Station_transmit_type=5; break; default: XmToggleButtonSetState(styp1,TRUE,FALSE); Station_transmit_type=0; break; } #ifdef TRANSMIT_RAW_WX if (transmit_raw_wx) { XmToggleButtonSetState(raw_wx_tx,TRUE,FALSE); } else { XmToggleButtonSetState(raw_wx_tx,FALSE,FALSE); } #endif // TRANSMIT_RAW_WX if(transmit_compressed_objects_items) { XmToggleButtonSetState(compressed_objects_items_tx,TRUE,FALSE); } else { XmToggleButtonSetState(compressed_objects_items_tx,FALSE,FALSE); } if(pop_up_new_bulletins) { XmToggleButtonSetState(new_bulletin_popup_enable,TRUE,FALSE); } else { XmToggleButtonSetState(new_bulletin_popup_enable,FALSE,FALSE); } if(view_zero_distance_bulletins) { XmToggleButtonSetState(zero_bulletin_popup_enable,TRUE,FALSE); } else { XmToggleButtonSetState(zero_bulletin_popup_enable,FALSE,FALSE); } if(warn_about_mouse_modifiers) { XmToggleButtonSetState(warn_about_mouse_modifiers_enable,TRUE,FALSE); } else { XmToggleButtonSetState(warn_about_mouse_modifiers_enable,FALSE,FALSE); } // user interface refers to all my trails in one color // my trail diff color as 0 means my trails in one color, so select // button when my trail diff color is 0 rather than 1. if(my_trail_diff_color) { XmToggleButtonSetState(my_trail_diff_color_enable,FALSE,FALSE); } else { XmToggleButtonSetState(my_trail_diff_color_enable,TRUE,FALSE); } if(predefined_menu_from_file) { // Option to load the predefined SAR objects menu items from a file. // Display the filename if one is currently selected and option is enabled. #ifdef USE_COMBO_BOX XmString tempSelection = XmStringCreateLocalized(predefined_object_definition_filename); XmComboBoxSelectItem(load_predefined_objects_menu_from_file, tempSelection); XmStringFree(tempSelection); #else x = -1; if (strncmp(predefined_object_definition_filename,"predefined_SAR.sys",strlen(predefined_object_definition_filename)) == 0) { x = 0; } if (strncmp(predefined_object_definition_filename,"predefined_EVENT.sys",strlen(predefined_object_definition_filename)) == 0) { x = 1; } if (strncmp(predefined_object_definition_filename,"predefined_USER.sys",strlen(predefined_object_definition_filename)) == 0) { x = 2; } i = 3; // allow display of another filename from the config file. // user won't be able to edit it, but they will see it. if (x==-1) { ac = 0; cb_items[i] = XmStringCreateLocalized(predefined_object_definition_filename); XtSetArg(al[ac], XmNlabelString, cb_items[i]); ac++; XtSetArg(al[ac], XmNuserData, (XtPointer)i); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; sprintf(buf,"button%d",i); lpomff_button = XmCreatePushButton(lpomff_menuPane, buf, al, ac); XtManageChild(lpomff_button); XtAddCallback(lpomff_button, XmNactivateCallback, lpomff_menuCallback, Configure_defaults); lpomff_buttons[i] = lpomff_button; XmStringFree(cb_items[i]); x = i; } XtVaSetValues(lpomff_menu, XmNmenuHistory, lpomff_buttons[x], NULL); lpomff_value = x+1; #endif // USE_COMBO_BOX XmToggleButtonSetState(load_predefined_objects_menu_from_file_enable,TRUE,FALSE); } else { // by default combo box is created with no selection // make sure that toggle button is unchecked XmToggleButtonSetState(load_predefined_objects_menu_from_file_enable,FALSE,FALSE); } XmToggleButtonSetState(altnet_active, altnet, FALSE); XmToggleButtonSetState(disable_dupe_check, skip_dupe_checking, FALSE); // Known to have memory leaks in some Motif versions: //XmTextSetString(altnet_text, altnet_call); XmTextReplace(altnet_text, (XmTextPosition) 0, XmTextGetLastPosition(altnet_text), altnet_call); switch(operate_as_an_igate) { case(0): XmToggleButtonSetState(igtyp0,TRUE,FALSE); Igate_type=0; break; case(1): XmToggleButtonSetState(igtyp1,TRUE,FALSE); Igate_type=1; break; case(2): XmToggleButtonSetState(igtyp2,TRUE,FALSE); Igate_type=2; break; default: XmToggleButtonSetState(igtyp0,TRUE,FALSE); Igate_type=0; break; } pos_dialog(configure_defaults_dialog); delw = XmInternAtom(XtDisplay(configure_defaults_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_defaults_dialog, delw, Configure_defaults_destroy_shell, (XtPointer)configure_defaults_dialog); XtManageChild(my_form); XtManageChild(type_box); XtManageChild(igate_box); XtManageChild(pane); resize_dialog(my_form, configure_defaults_dialog); XtPopup(configure_defaults_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_defaults_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_defaults_dialog), XtWindow(configure_defaults_dialog)); } } /////////////////////////////////// Configure Timing Dialog ////////////////////////////////// void Configure_timing_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_timing_dialog = (Widget)NULL; } void Configure_timing_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int value; XmScaleGetValue(ghosting_time, &value); // Minutes sec_old = (time_t)(value * 60); // Convert to seconds XmScaleGetValue(clearing_time, &value); // Hours sec_clear = (time_t)(value * 60 * 60); // Convert to seconds XmScaleGetValue(posit_interval, &value); // Minutes * 10 POSIT_rate = (long)(value * 60 / 10); // Convert to seconds XmScaleGetValue(gps_interval, &value); // Seconds gps_time = (long)value; XmScaleGetValue(dead_reckoning_time, &value);// Minutes dead_reckoning_timeout = value * 60; // Convert to seconds XmScaleGetValue(object_item_interval, &value);// Minutes OBJECT_rate = value * 60; // Convert to seconds XmScaleGetValue(removal_time, &value); // Days sec_remove = (time_t)(value * 60 * 60 * 24);// Convert to seconds // Set the new posit rate into effect immediately posit_next_time = posit_last_time + POSIT_rate; // Set the new GPS rate into effect immediately sec_next_gps = sec_now() + gps_time; // Set the serial port inter-character delay XmScaleGetValue(serial_pacing_time, &serial_char_pacing); // Milliseconds XmScaleGetValue(trail_segment_timeout, &value); // Minutes trail_segment_time = (int)value; XmScaleGetValue(trail_segment_distance_max, &value); // Degrees trail_segment_distance = (int)value; #ifdef HAVE_GPSMAN XmScaleGetValue(RINO_download_timeout, &value); // Degrees RINO_download_interval = (int)value; #endif // HAVE_GPSMAN XmScaleGetValue(net_map_slider, &net_map_timeout); XmScaleGetValue(snapshot_interval_slider, &snapshot_interval); XmScaleGetValue(aircraft_clearing_time, &value); // Minutes aircraft_sec_clear = (time_t)(value * 60); // Convert to seconds redraw_on_new_data=2; Configure_timing_destroy_shell(widget,clientData,callData); } void Configure_timing( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel; Atom delw; XmString x_str; if (!configure_timing_dialog) { configure_timing_dialog = XtVaCreatePopupShell(langcode("WPUPCFTM01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_timing pane", xmPanedWindowWidgetClass, configure_timing_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_timing my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Posit Time x_str = XmStringCreateLocalized(langcode("WPUPCFTM02")); posit_interval = XtVaCreateManagedWidget("Posit Interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes (disables the function) XmNmaximum, 60*10, // 60 minutes XmNdecimalPoints, 1, // Move decimal point over one XmNscaleMultiple, 5, // Move 30 seconds per left mouse XmNshowValue, TRUE, XmNvalue, (int)((POSIT_rate * 10) / 60), // Minutes * 10 XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for stations being considered old (symbol ghosting) x_str = XmStringCreateLocalized(langcode("WPUPCFTM03")); ghosting_time = XtVaCreateManagedWidget("Station Ghosting Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One minute XmNmaximum, 3*60, // Three hours XmNshowValue, TRUE, XmNvalue, (int)(sec_old/60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Object Item Transmit Interval x_str = XmStringCreateLocalized(langcode("WPUPCFTM04")); object_item_interval = XtVaCreateManagedWidget("Object/Item Transmit Interval (min)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, posit_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 5, // Five minutes XmNmaximum, 120, // 120 minutes XmNscaleMultiple, 5, // Move 5 minutes per left mouse XmNshowValue, TRUE, XmNvalue, (int)(OBJECT_rate / 60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for station not being displayed x_str = XmStringCreateLocalized(langcode("WPUPCFTM05")); clearing_time = XtVaCreateManagedWidget("Station Clear Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, posit_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One hour XmNmaximum, 24*7, // One week XmNshowValue, TRUE, XmNvalue, (int)(sec_clear/(60*60)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // GPS Time x_str = XmStringCreateLocalized(langcode("WPUPCFTM06")); gps_interval = XtVaCreateManagedWidget("GPS Interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_item_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One second XmNmaximum, 60, // Sixty seconds XmNshowValue, TRUE, XmNvalue, (int)gps_time, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for station being removed from database x_str = XmStringCreateLocalized(langcode("WPUPCFTM07")); removal_time = XtVaCreateManagedWidget("Station Delete Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_item_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One Day XmNmaximum, 14, // Two weeks XmNshowValue, TRUE, XmNvalue, (int)(sec_remove/(60*60*24)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Dead Reckoning Timeout x_str = XmStringCreateLocalized(langcode("WPUPCFTM08")); dead_reckoning_time = XtVaCreateManagedWidget("DR Time (min)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gps_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One minute XmNmaximum, 60, // Sixty minutes XmNshowValue, TRUE, XmNvalue, (int)(dead_reckoning_timeout / 60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Serial Pacing Time (delay between each serial character) x_str = XmStringCreateLocalized(langcode("WPUPCFTM09")); serial_pacing_time = XtVaCreateManagedWidget("Serial Pacing Time (ms)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, removal_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero XmNmaximum, 50, // Fifty milliseconds XmNshowValue, TRUE, XmNvalue, (int)(serial_char_pacing), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Time below which track segment will get drawn, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM10")); trail_segment_timeout = XtVaCreateManagedWidget("Trail segment timeout", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dead_reckoning_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes XmNmaximum, 12*60, // 12 hours XmNshowValue, TRUE, XmNvalue, trail_segment_time, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval at track segment will not get drawn, in degrees x_str = XmStringCreateLocalized(langcode("WPUPCFTM11")); trail_segment_distance_max = XtVaCreateManagedWidget("Trail segment interval degrees", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dead_reckoning_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero degrees XmNmaximum, 45, // 90 degrees XmNshowValue, TRUE, XmNvalue, trail_segment_distance, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Time below which track segment will get drawn, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM12")); RINO_download_timeout = XtVaCreateManagedWidget("RINO download interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trail_segment_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes (disables the function) XmNmaximum, 30, // 30 minutes XmNshowValue, TRUE, XmNvalue, RINO_download_interval, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); #ifndef HAVE_GPSMAN XtSetSensitive(RINO_download_timeout, FALSE); #endif // HAVE_GPSMAN x_str = XmStringCreateLocalized(langcode("MPUPTGR017")); net_map_slider = XtVaCreateManagedWidget("Net Map Timeout", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trail_segment_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 10, XmNmaximum, 300, XmNshowValue, TRUE, XmNvalue, net_map_timeout, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval at which snapshots will be taken, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM13")); snapshot_interval_slider = XtVaCreateManagedWidget("Snapshot interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, RINO_download_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // 0.5 minutes XmNmaximum, 30, // 30 minutes XmNshowValue, TRUE, XmNvalue, snapshot_interval, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for aircraft not being displayed x_str = XmStringCreateLocalized(langcode("WPUPCFTM14")); aircraft_clearing_time = XtVaCreateManagedWidget("Aircraft Clear Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, clearing_time, XmNtopWidget, RINO_download_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // zero disables - this is the default XmNmaximum, 60*8, // 8 hours XmNshowValue, TRUE, XmNvalue, (int)(aircraft_sec_clear/(60)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, snapshot_interval_slider, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, snapshot_interval_slider, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_timing_change_data, configure_timing_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_timing_destroy_shell, configure_timing_dialog); pos_dialog(configure_timing_dialog); delw = XmInternAtom(XtDisplay(configure_timing_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_timing_dialog, delw, Configure_timing_destroy_shell, (XtPointer)configure_timing_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_timing_dialog); XtPopup(configure_timing_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_timing_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_timing_dialog), XtWindow(configure_timing_dialog)); } } /////////////////////////////////// Configure Coordinates Dialog ////////////////////////////////// void coordinates_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { coordinate_system = atoi(which); } else { coordinate_system = USE_DDMMMM; } // Update any active view lists so their coordinates get updated Station_List_fill(1,0); // Update View->Mobile Station list (has lat/lon or UTM info on it) // Force redraw redraw_on_new_data = 2; } void Configure_coordinates_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_coordinates_dialog = (Widget)NULL; } void Configure_coordinates( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, frame, coord_box, coord_0, coord_1, coord_2, coord_3, coord_4, coord_5; // static Widget label; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if (!configure_coordinates_dialog) { configure_coordinates_dialog = XtVaCreatePopupShell(langcode("WPUPCFC001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_coordinates pane", xmPanedWindowWidgetClass, configure_coordinates_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_coordinates my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interval for station being considered old frame = XtVaCreateManagedWidget("Configure_coordinates frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //label XtVaCreateManagedWidget(langcode("WPUPCFC002"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; coord_box = XmCreateRadioBox(frame,"Configure_coordinates coord_box", al, ac); XtVaSetValues(coord_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNnumColumns,5, NULL); coord_0 = XtVaCreateManagedWidget(langcode("WPUPCFC003"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_0,XmNvalueChangedCallback,coordinates_toggle,"0"); coord_1 = XtVaCreateManagedWidget(langcode("WPUPCFC004"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_1,XmNvalueChangedCallback,coordinates_toggle,"1"); coord_2 = XtVaCreateManagedWidget(langcode("WPUPCFC005"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_2,XmNvalueChangedCallback,coordinates_toggle,"2"); coord_3 = XtVaCreateManagedWidget(langcode("WPUPCFC006"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_3,XmNvalueChangedCallback,coordinates_toggle,"3"); coord_4 = XtVaCreateManagedWidget(langcode("WPUPCFC008"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_4,XmNvalueChangedCallback,coordinates_toggle,"4"); coord_5 = XtVaCreateManagedWidget(langcode("WPUPCFC007"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_5,XmNvalueChangedCallback,coordinates_toggle,"5"); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_coordinates_destroy_shell, configure_coordinates_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_coordinates_destroy_shell, configure_coordinates_dialog); // Set the toggle buttons based on current data switch (coordinate_system) { case(USE_DDDDDD): XmToggleButtonSetState(coord_0,TRUE,FALSE); break; case(USE_DDMMSS): XmToggleButtonSetState(coord_2,TRUE,FALSE); break; case(USE_UTM): XmToggleButtonSetState(coord_3,TRUE,FALSE); break; case(USE_UTM_SPECIAL): XmToggleButtonSetState(coord_4,TRUE,FALSE); break; case(USE_MGRS): XmToggleButtonSetState(coord_5,TRUE,FALSE); break; case(USE_DDMMMM): default: XmToggleButtonSetState(coord_1,TRUE,FALSE); break; } pos_dialog(configure_coordinates_dialog); delw = XmInternAtom(XtDisplay(configure_coordinates_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_coordinates_dialog, delw, Configure_coordinates_destroy_shell, (XtPointer)configure_coordinates_dialog); XtManageChild(my_form); XtManageChild(coord_box); XtManageChild(pane); resize_dialog(my_form, configure_coordinates_dialog); XtPopup(configure_coordinates_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_coordinates_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_coordinates_dialog), XtWindow(configure_coordinates_dialog)); } } ///////////////////////////////// Configure Audio Alarms Dialog //////////////////////////////// void Configure_audio_alarm_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_audio_alarm_dialog = (Widget)NULL; } void Configure_audio_alarm_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; temp_ptr = XmTextFieldGetString(audio_alarm_config_play_data); xastir_snprintf(sound_command, sizeof(sound_command), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_command); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_ons_data); xastir_snprintf(sound_new_station, sizeof(sound_new_station), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_new_station); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onm_data); xastir_snprintf(sound_new_message, sizeof(sound_new_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_new_message); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onpx_data); xastir_snprintf(sound_prox_message, sizeof(sound_prox_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_prox_message); temp_ptr = XmTextFieldGetString(prox_min_data); xastir_snprintf(prox_min, sizeof(prox_min), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(prox_min); temp_ptr = XmTextFieldGetString(prox_max_data); xastir_snprintf(prox_max, sizeof(prox_max), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(prox_max); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onbo_data); xastir_snprintf(sound_band_open_message, sizeof(sound_band_open_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_band_open_message); temp_ptr = XmTextFieldGetString(bando_min_data); xastir_snprintf(bando_min, sizeof(bando_min), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(bando_min); temp_ptr = XmTextFieldGetString(bando_max_data); xastir_snprintf(bando_max, sizeof(bando_max), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(bando_max); temp_ptr = XmTextFieldGetString(audio_alarm_config_wx_alert_data); xastir_snprintf(sound_wx_alert_message, sizeof(sound_wx_alert_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_wx_alert_message); if(XmToggleButtonGetState(audio_alarm_config_play_on_new_station)) { sound_play_new_station=1; } else { sound_play_new_station=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_new_message)) { sound_play_new_message=1; } else { sound_play_new_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_prox)) { sound_play_prox_message=1; } else { sound_play_prox_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_bando)) { sound_play_band_open_message=1; } else { sound_play_band_open_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_wx_alert)) { sound_play_wx_alert_message=1; } else { sound_play_wx_alert_message=0; } Configure_audio_alarm_destroy_shell(widget,clientData,callData); } void Configure_audio_alarms( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, audio_play, file1, file2, min1, max1, minb1, maxb2, sep; // static Widget min2, max2, minb2, maxb1; Atom delw; if (!configure_audio_alarm_dialog) { configure_audio_alarm_dialog = XtVaCreatePopupShell(langcode("WPUPCFA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_audio_alarms pane", xmPanedWindowWidgetClass, configure_audio_alarm_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_audio_alarms my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); audio_play = XtVaCreateManagedWidget(langcode("WPUPCFA002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); file1 = XtVaCreateManagedWidget(langcode("WPUPCFA003"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_play, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); file2 = XtVaCreateManagedWidget(langcode("WPUPCFA004"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_play, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_new_station = XtVaCreateManagedWidget(langcode("WPUPCFA005"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, file1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_ons_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command NS", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, file2, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftWidget, audio_alarm_config_play_on_new_station, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_new_message = XtVaCreateManagedWidget(langcode("WPUPCFA006"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_station, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onm_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command NM", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_station, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_prox = XtVaCreateManagedWidget(langcode("WPUPCFA007"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_message, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onpx_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command PROX", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_message, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); min1 = XtVaCreateManagedWidget(langcode("WPUPCFA009"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_prox, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); prox_min_data = XtVaCreateManagedWidget("Configure_audio_alarms prox min", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_onpx_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //min2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_prox, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); max1 = XtVaCreateManagedWidget(langcode("WPUPCFA010"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, min1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); prox_max_data = XtVaCreateManagedWidget("Configure_audio_alarms prox max", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, prox_min_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //max2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, min1, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_bando = XtVaCreateManagedWidget(langcode("WPUPCFA008"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, max1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onbo_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command BAND", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, prox_max_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); minb1 = XtVaCreateManagedWidget(langcode("WPUPCFA009"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_bando, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); bando_min_data = XtVaCreateManagedWidget("Configure_audio_alarms bando min", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_onbo_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //minb2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_bando, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //maxb1 XtVaCreateManagedWidget(langcode("WPUPCFA010"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, minb1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); bando_max_data = XtVaCreateManagedWidget("Configure_audio_alarms bando max", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bando_min_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); maxb2 = XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, minb1, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_wx_alert = XtVaCreateManagedWidget(langcode("WPUPCFA011"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, maxb2, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_wx_alert_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command WxAlert", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bando_max_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Configure_audio_alarms sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_wx_alert, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_audio_alarm_change_data, configure_audio_alarm_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_audio_alarm_destroy_shell, configure_audio_alarm_dialog); pos_dialog(configure_audio_alarm_dialog); delw = XmInternAtom(XtDisplay(configure_audio_alarm_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_audio_alarm_dialog, delw, Configure_audio_alarm_destroy_shell, (XtPointer)configure_audio_alarm_dialog); XmTextFieldSetString(audio_alarm_config_play_data,sound_command); XmTextFieldSetString(audio_alarm_config_play_ons_data,sound_new_station); XmTextFieldSetString(audio_alarm_config_play_onm_data,sound_new_message); XmTextFieldSetString(audio_alarm_config_play_onpx_data,sound_prox_message); XmTextFieldSetString(prox_min_data,prox_min); XmTextFieldSetString(prox_max_data,prox_max); XmTextFieldSetString(audio_alarm_config_play_onbo_data,sound_band_open_message); XmTextFieldSetString(bando_min_data,bando_min); XmTextFieldSetString(bando_max_data,bando_max); XmTextFieldSetString(audio_alarm_config_wx_alert_data, sound_wx_alert_message); if(sound_play_new_station) { XmToggleButtonSetState(audio_alarm_config_play_on_new_station,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_new_station,FALSE,FALSE); } if(sound_play_new_message) { XmToggleButtonSetState(audio_alarm_config_play_on_new_message,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_new_message,FALSE,FALSE); } if(sound_play_prox_message) { XmToggleButtonSetState(audio_alarm_config_play_on_prox,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_prox,FALSE,FALSE); } if(sound_play_band_open_message) { XmToggleButtonSetState(audio_alarm_config_play_on_bando,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_bando,FALSE,FALSE); } if (sound_play_wx_alert_message) { XmToggleButtonSetState(audio_alarm_config_play_on_wx_alert, TRUE, FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_wx_alert, FALSE, FALSE); } XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_audio_alarm_dialog); XtPopup(configure_audio_alarm_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_audio_alarm_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_audio_alarm_dialog), XtWindow(configure_audio_alarm_dialog)); } } ///////////////////////////////////// Configure Speech Dialog ////////////////////////////////// void Configure_speech_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_speech_dialog = (Widget)NULL; } void Test_speech(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { SayText(SPEECH_TEST_STRING); } void Configure_speech_change_data(Widget widget, XtPointer clientData, XtPointer callData) { if(XmToggleButtonGetState(speech_config_play_on_new_station)) { festival_speak_new_station=1; } else { festival_speak_new_station=0; } if(XmToggleButtonGetState(speech_config_play_on_new_message_alert)) { festival_speak_new_message_alert=1; } else { festival_speak_new_message_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_new_message_body)) { festival_speak_new_message_body=1; } else { festival_speak_new_message_body=0; } if(XmToggleButtonGetState(speech_config_play_on_prox)) { festival_speak_proximity_alert=1; } else { festival_speak_proximity_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_trak)) { festival_speak_tracked_proximity_alert=1; } else { festival_speak_tracked_proximity_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_bando)) { festival_speak_band_opening=1; } else { festival_speak_band_opening=0; } if(XmToggleButtonGetState(speech_config_play_on_new_wx_alert)) { festival_speak_new_weather_alert=1; } else { festival_speak_new_weather_alert=0; } Configure_speech_destroy_shell(widget,clientData,callData); } //Make it helpful - Gray the config selections, but add a choice //that basically pops up a box that says where to get Festival, have //it be ungrayed if Festival isn't installed. void Configure_speech( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, file1, sep, button_test; Atom delw; if (!configure_speech_dialog) { configure_speech_dialog = XtVaCreatePopupShell(langcode("WPUPCFSP01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_speech pane", xmPanedWindowWidgetClass, configure_speech_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_speech my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); file1 = XtVaCreateManagedWidget(langcode("WPUPCFSP02"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_station = XtVaCreateManagedWidget(langcode("WPUPCFSP03"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, file1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_message_alert = XtVaCreateManagedWidget(langcode("WPUPCFSP04"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_station, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_message_body = XtVaCreateManagedWidget(langcode("WPUPCFSP05"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_message_alert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_prox = XtVaCreateManagedWidget(langcode("WPUPCFSP06"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_message_body, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_trak = XtVaCreateManagedWidget(langcode("WPUPCFSP09"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_prox, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_bando = XtVaCreateManagedWidget(langcode("WPUPCFSP07"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_trak, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_wx_alert = XtVaCreateManagedWidget(langcode("WPUPCFSP08"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_bando, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Configure_speech sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_wx_alert, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_test = XtVaCreateManagedWidget(langcode("PULDNFI003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_test, XmNactivateCallback, Test_speech, configure_speech_dialog); XtAddCallback(button_ok, XmNactivateCallback, Configure_speech_change_data, configure_speech_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_speech_destroy_shell, configure_speech_dialog); pos_dialog(configure_speech_dialog); delw = XmInternAtom(XtDisplay(configure_speech_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_speech_dialog, delw, Configure_speech_destroy_shell, (XtPointer)configure_speech_dialog); if(festival_speak_new_station) { XmToggleButtonSetState(speech_config_play_on_new_station,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_station,FALSE,FALSE); } if(festival_speak_new_message_alert) { XmToggleButtonSetState(speech_config_play_on_new_message_alert,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_message_alert,FALSE,FALSE); } if(festival_speak_new_message_body) { XmToggleButtonSetState(speech_config_play_on_new_message_body,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_message_body,FALSE,FALSE); } if(festival_speak_proximity_alert) { XmToggleButtonSetState(speech_config_play_on_prox,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_prox,FALSE,FALSE); } if(festival_speak_tracked_proximity_alert) { XmToggleButtonSetState(speech_config_play_on_trak,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_trak,FALSE,FALSE); } if(festival_speak_band_opening) { XmToggleButtonSetState(speech_config_play_on_bando,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_bando,FALSE,FALSE); } if(festival_speak_new_weather_alert) { XmToggleButtonSetState(speech_config_play_on_new_wx_alert,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_wx_alert,FALSE,FALSE); } XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_speech_dialog); XtPopup(configure_speech_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_speech_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_speech_dialog), XtWindow(configure_speech_dialog)); } } /* * Track_Me * */ void Track_Me( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", my_callsign); track_me = atoi(which); track_station_on = atoi(which); display_zoom_status(); } else { track_me = 0; track_station_on = 0; display_zoom_status(); } } // Pointer to the Move/Measure cursor object static Cursor cs_move_measure = (Cursor)NULL; /* * Move_Object * */ void Move_Object( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { moving_object = atoi(which); XmToggleButtonSetState(measure_button, FALSE, FALSE); measuring_distance = 0; // Change the cursor if(!cs_move_measure) { cs_move_measure=XCreateFontCursor(XtDisplay(da),XC_crosshair); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_move_measure); (void)XFlush(XtDisplay(da)); } else { moving_object = 0; // Remove the special "crosshair" cursor (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); } } /* * Measure_Distance * */ void Measure_Distance( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { measuring_distance = atoi(which); XmToggleButtonSetState(move_button, FALSE, FALSE); moving_object = 0; // Change the cursor if(!cs_move_measure) { cs_move_measure=XCreateFontCursor(XtDisplay(da),XC_crosshair); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_move_measure); (void)XFlush(XtDisplay(da)); } else { measuring_distance = 0; // Remove the special "crosshair" cursor (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); } } ///////////////////////////////////////////////////////////////////////// /* * Destroy Configure Station Dialog Popup Window */ void Configure_station_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),CS_icon0); // ???? DK7IN: avoid possible memory leak ? (void)XFreePixmap(XtDisplay(appshell),CS_icon); XtDestroyWidget(shell); configure_station_dialog = (Widget)NULL; // Take down the symbol selection dialog as well (if it's up) if (select_symbol_dialog) { Select_symbol_destroy_shell( widget, select_symbol_dialog, callData); } // NULL out the dialog field in the global struct used for // Coordinate Calculator. Prevents segfaults if the calculator is // still up and trying to write to us. coordinate_calc_array.calling_dialog = NULL; } void Configure_station_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Configure_station_pos_amb = atoi(which); } else { Configure_station_pos_amb = 0; } } /* * Process changes to station data */ void Configure_station_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char temp[40]; char old_callsign[MAX_CALLSIGN+1]; int ok = 1; int temp2; int temp3; char *temp_ptr; char *temp_ptr2; transmit_compressed_posit = (int)XmToggleButtonGetState(compressed_posit_tx); xastir_snprintf(old_callsign, sizeof(old_callsign), "%s", my_callsign); /*fprintf(stderr,"Changing Configure station data\n");*/ temp_ptr = XmTextFieldGetString(station_config_call_data); xastir_snprintf(my_callsign, sizeof(my_callsign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(my_callsign); (void)to_upper(my_callsign); (void)remove_trailing_dash_zero(my_callsign); // Enter NOCALL if there's nothing left. if (my_callsign[0] == '\0') xastir_snprintf(my_callsign, sizeof(my_callsign), "NOCALL"); temp_ptr = XmTextFieldGetString(station_config_slat_data_ns); if((char)toupper((int)temp_ptr[0])=='S') { temp[0]='S'; } else { temp[0]='N'; } XtFree(temp_ptr); // Check latitude for out-of-bounds temp_ptr = XmTextFieldGetString(station_config_slat_data_deg); temp2 = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp2 > 90) || (temp2 < 0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slat_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { ok = 0; } if ( (temp2 == 90) && (temp3 != 0.0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slat_data_deg); temp_ptr2 = XmTextFieldGetString(station_config_slat_data_min); xastir_snprintf(my_lat, sizeof(my_lat), "%02d%06.3f%c", atoi(temp_ptr), atof(temp_ptr2),temp[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(station_config_slong_data_ew); if((char)toupper((int)temp_ptr[0])=='E') { temp[0]='E'; } else { temp[0]='W'; } XtFree(temp_ptr); // Check longitude for out-of-bounds temp_ptr = XmTextFieldGetString(station_config_slong_data_deg); temp2 = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp2 > 180) || (temp2 < 0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slong_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { ok = 0; } if ( (temp2 == 180) && (temp3 != 0.0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slong_data_deg); temp_ptr2 = XmTextFieldGetString(station_config_slong_data_min); xastir_snprintf(my_long, sizeof(my_long), "%03d%06.3f%c", atoi(temp_ptr), atof(temp_ptr2),temp[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(station_config_group_data); my_group=temp_ptr[0]; if(isalpha((int)my_group)) { my_group = toupper((int)temp_ptr[0]); } XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(station_config_symbol_data); my_symbol = temp_ptr[0]; XtFree(temp_ptr); if(isdigit((int)my_phg[3]) && isdigit((int)my_phg[4]) && isdigit((int)my_phg[5]) && isdigit((int)my_phg[6])) { my_phg[0] = 'P'; my_phg[1] = 'H'; my_phg[2] = 'G'; my_phg[7] = '\0'; } else { my_phg[0]='\0'; } /* set station ambiguity*/ position_amb_chars = Configure_station_pos_amb; if (transmit_compressed_posit) { position_amb_chars = 0; } temp_ptr = XmTextFieldGetString(station_config_comment_data); xastir_snprintf(my_comment, sizeof(my_comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(my_comment); /* TO DO: KILL only my station data? */ if (ok) // If entered data was valid { // Check whether we changed our callsign if (strcasecmp(old_callsign,my_callsign) != 0) { station_del(old_callsign); // move to new sort location... // If TrackMe is enabled, copy the new callsign into the // track_station_call variable. If we don't do this, we // will still be tracking our old callsign. if (track_me) { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", my_callsign); } } // Update our parameters my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; Configure_station_destroy_shell(widget,clientData,callData); } // Check for proper weather symbols if a weather station (void)check_weather_symbol(); // Check for use of NWS symbols (void)check_nws_weather_symbol(); } /* * Update symbol picture for changed symbol or table */ void updateSymbolPictureCallback( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char table, overlay; char symb, group; char *temp_ptr; XtVaSetValues(station_config_icon, XmNlabelPixmap, CS_icon0, NULL); // clear old icon XtManageChild(station_config_icon); temp_ptr = XmTextFieldGetString(station_config_group_data); group = temp_ptr[0]; XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(station_config_symbol_data); symb = temp_ptr[0]; XtFree(temp_ptr); if (group == '/' || group == '\\') { table = group; overlay = ' '; } else { table = '\\'; overlay = group; } symbol(station_config_icon,0,table,symb,overlay,CS_icon,0,0,0,' '); // create icon XtVaSetValues(station_config_icon,XmNlabelPixmap,CS_icon,NULL); // draw new icon XtManageChild(station_config_icon); } /* Power radio buttons */ void Power_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[3] = which[0]; // Set to power desired if (which[0] == 'x') // Disable PHG field if 'x' found { my_phg[0] = '\0'; } } else { my_phg[3] = '3'; // 10 Watts (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Height radio buttons */ void Height_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[4] = which[0]; // Set to height desired } else { my_phg[4] = '1'; // 20 Feet above average terrain (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Gain radio buttons */ void Gain_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[5] = which[0]; // Set to gain desired } else { my_phg[5] = '3'; // 3dB gain antenna (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Directivity radio buttons */ void Directivity_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[6] = which[0]; // Set to directivity desired } else { my_phg[6] = '0'; // Omni-directional antenna (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } void Posit_compressed_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { transmit_compressed_posit = atoi(which); } else { transmit_compressed_posit = 0; } if(transmit_compressed_posit) { // Compressed posits don't allow position ambiguity position_amb_chars = 0; XtSetSensitive(posamb0,FALSE); XtSetSensitive(posamb1,FALSE); XtSetSensitive(posamb2,FALSE); XtSetSensitive(posamb3,FALSE); XtSetSensitive(posamb4,FALSE); } else // Position ambiguity ok for this mode { XtSetSensitive(posamb0,TRUE); XtSetSensitive(posamb1,TRUE); XtSetSensitive(posamb2,TRUE); XtSetSensitive(posamb3,TRUE); XtSetSensitive(posamb4,TRUE); } } /* * Select a symbol graphically */ void Configure_change_symbol(Widget widget, XtPointer clientData, XtPointer callData) { //fprintf(stderr,"Trying to change a symbol\n"); symbol_change_requested_from = 1; // Tell Select_symbol who to return the data to Select_symbol(widget, clientData, callData); } /* * Setup Configure Station dialog */ void Configure_station( Widget UNUSED(ww), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, cs_form, cs_form1, button_ok, button_cancel, call, frame, frame2, framephg, formphg, power_box,poption0,poption1,poption2,poption3,poption4,poption5,poption6,poption7,poption8,poption9,poption10, height_box,hoption1,hoption2,hoption3,hoption4,hoption5,hoption6,hoption7,hoption8,hoption9,hoption10, gain_box,goption1,goption2,goption3,goption4,goption5,goption6,goption7,goption8,goption9,goption10, directivity_box,doption1,doption2,doption3,doption4,doption5,doption6,doption7,doption8,doption9, slat, slat_deg, slat_min, slong_deg, slong_min, slong_ew, group, st_symbol, comment, option_box, sep, configure_button_symbol, compute_button; // static Widget pg2, slat_ns, slong, sts, posamb; char temp_data[40]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!configure_station_dialog) { configure_station_dialog = XtVaCreatePopupShell(langcode("WPUPCFS001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_station pane", xmPanedWindowWidgetClass, configure_station_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); cs_form = XtVaCreateWidget("Configure_station cs_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPCFS002"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_call_data = XtVaCreateManagedWidget("Configure_station call_data", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); compressed_posit_tx = XtVaCreateManagedWidget(langcode("WPUPCFS029"), xmToggleButtonWidgetClass, cs_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(compressed_posit_tx,XmNvalueChangedCallback,Posit_compressed_toggle,"1"); slat = XtVaCreateManagedWidget(langcode("WPUPCFS003"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_deg = XtVaCreateManagedWidget("Configure_station lat_deg", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 2, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slat_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_min = XtVaCreateManagedWidget("Configure_station lat_min", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slat_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slat_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_ns = XtVaCreateManagedWidget("Configure_station lat_ns", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slat_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //slat_n XtVaCreateManagedWidget(langcode("WPUPCFS006"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_ns, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //slong XtVaCreateManagedWidget(langcode("WPUPCFS007"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_deg = XtVaCreateManagedWidget("Configure_station long_deg", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_min = XtVaCreateManagedWidget("Configure_station long_min", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_ew = XtVaCreateManagedWidget("Configure_station long_ew", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_ew = XtVaCreateManagedWidget(langcode("WPUPCFS008"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_ew, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); compute_button = XtVaCreateManagedWidget(langcode("COORD002"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_ew, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Fill in the pointers to our input textfields so that the // coordinate calculator can fiddle with them. coordinate_calc_array.calling_dialog = configure_station_dialog; coordinate_calc_array.input_lat_deg = station_config_slat_data_deg; coordinate_calc_array.input_lat_min = station_config_slat_data_min; coordinate_calc_array.input_lat_dir = station_config_slat_data_ns; coordinate_calc_array.input_lon_deg = station_config_slong_data_deg; coordinate_calc_array.input_lon_min = station_config_slong_data_min; coordinate_calc_array.input_lon_dir = station_config_slong_data_ew; // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, configure_station_dialog); // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, "Configure_station"); XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, langcode("WPUPCFS001")); //----- Frame for table / symbol frame = XtVaCreateManagedWidget("Configure_station frame", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slong_ew, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Station Symbol" //sts XtVaCreateManagedWidget(langcode("WPUPCFS009"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); cs_form1 = XtVaCreateWidget("Configure_station cs_form1", xmFormWidgetClass, frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Group/overlay" group = XtVaCreateManagedWidget(langcode("WPUPCFS010"), xmLabelWidgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 100, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // table station_config_group_data = XtVaCreateManagedWidget("Configure_station group", xmTextFieldWidgetClass, cs_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, group, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Symbol" st_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS011"), xmLabelWidgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_group_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // symbol station_config_symbol_data = XtVaCreateManagedWidget("Configure_station symbol", xmTextFieldWidgetClass, cs_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, st_symbol, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // icon CS_icon0 = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); CS_icon = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); station_config_icon = XtVaCreateManagedWidget("Configure_station icon", xmLabelWidgetClass, cs_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, CS_icon, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_symbol_data, XmNleftOffset, 15, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); configure_button_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS028"), xmPushButtonGadgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 6, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_icon, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(configure_button_symbol, XmNactivateCallback, Configure_change_symbol, configure_station_dialog); //----- Frame for Power-Gain framephg = XtVaCreateManagedWidget("Configure_station framephg", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //pg2 XtVaCreateManagedWidget(langcode("WPUPCFS012"), xmLabelWidgetClass, framephg, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formphg = XtVaCreateWidget("Configure_station power_form", xmFormWidgetClass, framephg, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Power ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; power_box = XmCreateRadioBox(formphg, "Configure_station Power Radio Box", al, ac); XtVaSetValues(power_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,11, NULL); poption0 = XtVaCreateManagedWidget(langcode("WPUPCFS013"), xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption0,XmNvalueChangedCallback,Power_toggle,"x"); // 0 Watts poption1 = XtVaCreateManagedWidget("0W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption1,XmNvalueChangedCallback,Power_toggle,"0"); // 1 Watt poption2 = XtVaCreateManagedWidget("1W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption2,XmNvalueChangedCallback,Power_toggle,"1"); // 4 Watts poption3 = XtVaCreateManagedWidget("4W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption3,XmNvalueChangedCallback,Power_toggle,"2"); // 9 Watts poption4 = XtVaCreateManagedWidget("9W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption4,XmNvalueChangedCallback,Power_toggle,"3"); // 16 Watts poption5 = XtVaCreateManagedWidget("16W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption5,XmNvalueChangedCallback,Power_toggle,"4"); // 25 Watts poption6 = XtVaCreateManagedWidget("25W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption6,XmNvalueChangedCallback,Power_toggle,"5"); // 36 Watts poption7 = XtVaCreateManagedWidget("36W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption7,XmNvalueChangedCallback,Power_toggle,"6"); // 49 Watts poption8 = XtVaCreateManagedWidget("49W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption8,XmNvalueChangedCallback,Power_toggle,"7"); // 64 Watts poption9 = XtVaCreateManagedWidget("64W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption9,XmNvalueChangedCallback,Power_toggle,"8"); // 81 Watts poption10 = XtVaCreateManagedWidget("81W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption10,XmNvalueChangedCallback,Power_toggle,"9"); // Height height_box = XmCreateRadioBox(formphg, "Configure_station Height Radio Box", al, ac); XtVaSetValues(height_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,power_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 10 Feet hoption1 = XtVaCreateManagedWidget( (english_units) ? "10ft" : "3m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption1,XmNvalueChangedCallback,Height_toggle,"0"); // 20 Feet hoption2 = XtVaCreateManagedWidget( (english_units) ? "20ft" : "6m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption2,XmNvalueChangedCallback,Height_toggle,"1"); // 40 Feet hoption3 = XtVaCreateManagedWidget( (english_units) ? "40ft" : "12m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption3,XmNvalueChangedCallback,Height_toggle,"2"); // 80 Feet hoption4 = XtVaCreateManagedWidget( (english_units) ? "80ft" : "24m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption4,XmNvalueChangedCallback,Height_toggle,"3"); // 160 Feet hoption5 = XtVaCreateManagedWidget( (english_units) ? "160ft" : "49m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption5,XmNvalueChangedCallback,Height_toggle,"4"); // 320 Feet hoption6 = XtVaCreateManagedWidget( (english_units) ? "320ft" : "98m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption6,XmNvalueChangedCallback,Height_toggle,"5"); // 640 Feet hoption7 = XtVaCreateManagedWidget( (english_units) ? "640ft" : "195m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption7,XmNvalueChangedCallback,Height_toggle,"6"); // 1280 Feet hoption8 = XtVaCreateManagedWidget( (english_units) ? "1280ft" : "390m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption8,XmNvalueChangedCallback,Height_toggle,"7"); // 2560 Feet hoption9 = XtVaCreateManagedWidget( (english_units) ? "2560ft" : "780m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption9,XmNvalueChangedCallback,Height_toggle,"8"); // 5120 Feet hoption10 = XtVaCreateManagedWidget( (english_units) ? "5120ft" : "1561m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption10,XmNvalueChangedCallback,Height_toggle,"9"); // Gain gain_box = XmCreateRadioBox(formphg, "Configure_station Gain Radio Box", al, ac); XtVaSetValues(gain_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,height_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 0 dB goption1 = XtVaCreateManagedWidget("0dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption1,XmNvalueChangedCallback,Gain_toggle,"0"); // 1 dB goption2 = XtVaCreateManagedWidget("1dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption2,XmNvalueChangedCallback,Gain_toggle,"1"); // 2 dB goption3 = XtVaCreateManagedWidget("2dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption3,XmNvalueChangedCallback,Gain_toggle,"2"); // 3 dB goption4 = XtVaCreateManagedWidget("3dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption4,XmNvalueChangedCallback,Gain_toggle,"3"); // 4 dB goption5 = XtVaCreateManagedWidget("4dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption5,XmNvalueChangedCallback,Gain_toggle,"4"); // 5 dB goption6 = XtVaCreateManagedWidget("5dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption6,XmNvalueChangedCallback,Gain_toggle,"5"); // 6 dB goption7 = XtVaCreateManagedWidget("6dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption7,XmNvalueChangedCallback,Gain_toggle,"6"); // 7 dB goption8 = XtVaCreateManagedWidget("7dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption8,XmNvalueChangedCallback,Gain_toggle,"7"); // 8 dB goption9 = XtVaCreateManagedWidget("8dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption9,XmNvalueChangedCallback,Gain_toggle,"8"); // 9 dB goption10 = XtVaCreateManagedWidget("9dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption10,XmNvalueChangedCallback,Gain_toggle,"9"); // Gain directivity_box = XmCreateRadioBox(formphg, "Configure_station Directivity Radio Box", al, ac); XtVaSetValues(directivity_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,gain_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // Omni-directional doption1 = XtVaCreateManagedWidget(langcode("WPUPCFS016"), // Omni xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption1,XmNvalueChangedCallback,Directivity_toggle,"0"); // 45 NE doption2 = XtVaCreateManagedWidget("45\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption2,XmNvalueChangedCallback,Directivity_toggle,"1"); // 90 E doption3 = XtVaCreateManagedWidget("90\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption3,XmNvalueChangedCallback,Directivity_toggle,"2"); // 135 SE doption4 = XtVaCreateManagedWidget("135\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption4,XmNvalueChangedCallback,Directivity_toggle,"3"); // 180 S doption5 = XtVaCreateManagedWidget("180\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption5,XmNvalueChangedCallback,Directivity_toggle,"4"); // 225 SW doption6 = XtVaCreateManagedWidget("225\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption6,XmNvalueChangedCallback,Directivity_toggle,"5"); // 270 W doption7 = XtVaCreateManagedWidget("270\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption7,XmNvalueChangedCallback,Directivity_toggle,"6"); // 315 NW doption8 = XtVaCreateManagedWidget("315\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption8,XmNvalueChangedCallback,Directivity_toggle,"7"); // 360 N doption9 = XtVaCreateManagedWidget("360\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption9,XmNvalueChangedCallback,Directivity_toggle,"8"); //----------------------- comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framephg, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_comment_data = XtVaCreateManagedWidget("Configure_station comment", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 60, XmNwidth, ((60*7)+2), XmNmaxLength, MAX_COMMENT, XmNtopOffset, 11, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framephg, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //Position Ambiguity Frame frame2 = XtVaCreateManagedWidget("Configure_station frame2", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //posamb XtVaCreateManagedWidget(langcode("WPUPCFS018"), xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; option_box = XmCreateRadioBox(frame2, "Configure_station Option box", al, ac); XtVaSetValues(option_box, XmNnumColumns,5, NULL); posamb0 = XtVaCreateManagedWidget(langcode("WPUPCFS019"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb0,XmNvalueChangedCallback,Configure_station_toggle,"0"); posamb1 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS020"):langcode("WPUPCFS024"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb1,XmNvalueChangedCallback,Configure_station_toggle,"1"); posamb2 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS021"):langcode("WPUPCFS025"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb2,XmNvalueChangedCallback,Configure_station_toggle,"2"); posamb3 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS022"):langcode("WPUPCFS026"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb3,XmNvalueChangedCallback,Configure_station_toggle,"3"); posamb4 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS023"):langcode("WPUPCFS027"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb4,XmNvalueChangedCallback,Configure_station_toggle,"4"); sep = XtVaCreateManagedWidget("Configure_station sep", xmSeparatorGadgetClass, cs_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_station_change_data, configure_station_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_station_destroy_shell, configure_station_dialog); // fill in current data XmTextFieldSetString(station_config_call_data,my_callsign); substr(temp_data,my_lat,2); XmTextFieldSetString(station_config_slat_data_deg,temp_data); substr(temp_data,my_lat+2,6); XmTextFieldSetString(station_config_slat_data_min,temp_data); substr(temp_data,my_lat+8,1); XmTextFieldSetString(station_config_slat_data_ns,temp_data); substr(temp_data,my_long,3); XmTextFieldSetString(station_config_slong_data_deg,temp_data); substr(temp_data,my_long+3,6); XmTextFieldSetString(station_config_slong_data_min,temp_data); substr(temp_data,my_long+9,1); XmTextFieldSetString(station_config_slong_data_ew,temp_data); temp_data[0] = my_group; temp_data[1] = '\0'; XmTextFieldSetString(station_config_group_data,temp_data); XtAddCallback(station_config_group_data, XmNvalueChangedCallback, updateSymbolPictureCallback, configure_station_dialog); temp_data[0] = my_symbol; temp_data[1] = '\0'; XmTextFieldSetString(station_config_symbol_data,temp_data); XtAddCallback(station_config_symbol_data, XmNvalueChangedCallback, updateSymbolPictureCallback, configure_station_dialog); // update symbol picture (void)updateSymbolPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); if (my_phg[0]=='P') { switch (my_phg[3]) { case '0': XmToggleButtonGadgetSetState(poption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(poption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(poption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(poption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(poption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(poption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(poption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(poption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(poption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(poption10, TRUE, TRUE); break; case 'x': default: XmToggleButtonGadgetSetState(poption0, TRUE, TRUE); break; } switch (my_phg[4]) { case '0': XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(hoption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(hoption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(hoption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(hoption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(hoption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(hoption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(hoption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(hoption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(hoption10, TRUE, TRUE); break; default: break; } switch (my_phg[5]) { case '0': XmToggleButtonGadgetSetState(goption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(goption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(goption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(goption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(goption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(goption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(goption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(goption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(goption10, TRUE, TRUE); break; default: break; } switch (my_phg[6]) { case '0': XmToggleButtonGadgetSetState(doption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(doption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(doption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(doption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(doption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(doption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(doption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(doption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(doption9, TRUE, TRUE); break; default: break; } } else // PHG field disabled { XmToggleButtonGadgetSetState(poption0, TRUE, TRUE); } XmTextFieldSetString(station_config_comment_data,my_comment); if(transmit_compressed_posit) { // Compressed posits don't allow position ambiguity XmToggleButtonSetState(compressed_posit_tx,TRUE,FALSE); position_amb_chars = 0; XtSetSensitive(posamb0,FALSE); XtSetSensitive(posamb1,FALSE); XtSetSensitive(posamb2,FALSE); XtSetSensitive(posamb3,FALSE); XtSetSensitive(posamb4,FALSE); } else // Position ambiguity ok for this mode { XmToggleButtonSetState(compressed_posit_tx,FALSE,FALSE); XtSetSensitive(posamb0,TRUE); XtSetSensitive(posamb1,TRUE); XtSetSensitive(posamb2,TRUE); XtSetSensitive(posamb3,TRUE); XtSetSensitive(posamb4,TRUE); } Configure_station_pos_amb = position_amb_chars; switch (Configure_station_pos_amb) { case(0): XmToggleButtonSetState(posamb0,TRUE,FALSE); break; case(1): XmToggleButtonSetState(posamb1,TRUE,FALSE); break; case(2): XmToggleButtonSetState(posamb2,TRUE,FALSE); break; case(3): XmToggleButtonSetState(posamb3,TRUE,FALSE); break; case(4): XmToggleButtonSetState(posamb4,TRUE,FALSE); break; default: XmToggleButtonSetState(posamb0,TRUE,FALSE); break; } pos_dialog(configure_station_dialog); delw = XmInternAtom(XtDisplay(configure_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_station_dialog, delw, Configure_station_destroy_shell, (XtPointer)configure_station_dialog); XtManageChild(cs_form); XtManageChild(cs_form1); XtManageChild(option_box); XtManageChild(power_box); XtManageChild(height_box); XtManageChild(gain_box); XtManageChild(directivity_box); XtManageChild(formphg); XtManageChild(pane); resize_dialog(cs_form, configure_station_dialog); XtPopup(configure_station_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_station_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_station_dialog), XtWindow(configure_station_dialog)); } } // Borrowed from the libiberty library, a GPL'ed program. // void freeargv (char **vector) { register char **scan; if (vector != NULL) { for (scan = vector; *scan != NULL; scan++) { free (*scan); } free (vector); } } // Borrowed from the libiberty library, a GPL'ed program. // char **dupargv (char **argv) { int argc; char **copy; if (argv == NULL) { return NULL; } /* the vector */ for (argc = 0; argv[argc] != NULL; argc++); copy = (char **) calloc ((argc + 1), sizeof (char *)); if (copy == NULL) { return NULL; } /* the strings */ for (argc = 0; argv[argc] != NULL; argc++) { int len = strlen (argv[argc]); copy[argc] = malloc (sizeof (char *) * (len + 1)); if (copy[argc] == NULL) { freeargv (copy); return NULL; } strcpy (copy[argc], argv[argc]); } copy[argc] = NULL; return copy; } ///////////////////////////////////////////// main ///////////////////////////////////////////// // Third argument is now deprecated //int main(int argc, char *argv[], char *envp[]) { int main(int argc, char *argv[], char *envp[]) { int ag, ag_error, trap_segfault, deselect_maps_on_startup; uid_t user_id; struct passwd *user_info; static char lang_to_use_or[30]; char temp[100]; static char *Geometry = NULL; static int xt = 0; char temp_base_dir[MAX_VALUE]; // Define some overriding resources for the widgets. // Look at files in /usr/X11/lib/X11/app-defaults for ideas. String fallback_resources[] = { // "Mwm*iconImageForeground: #000000000000\n", "*initialResourcesPersistent: False\n", // Default font if nothing else overrides it: "*.fontList: fixed\n", "*List.Translations: #override \n\ Return: Select(children)\n\ space: Select(children)\n", "*List.baseTranslations: #override \n\ Return: Select(children)\n\ space: Select(children)\n", "*XmTextField.translations: #override \ Return: activate()\n\ Enter: activate()\n", "*.Text.Translations: #override\n\ CtrlS: no-op(RingBell)\n\ CtrlR: no-op(RingBell)\n\ space: next-page()\n\ F: next-page()\n\ CtrlB: previous-page()\n\ B: previous-page()\n\ K: scroll-one-line-down()\n\ Y: scroll-one-line-down()\n\ J: scroll-one-line-up()\n\ E: scroll-one-line-up()\n\ Return: scroll-one-line-up()\n\ q: quit()\n", "*.Text.baseTranslations: #override\n\ space: next-page()\n\ F: next-page()\n\ CtrlB: previous-page()\n\ K: scroll-one-line-down()\n\ Y: scroll-one-line-down()\n\ J: scroll-one-line-up()\n\ E: scroll-one-line-up()\n\ Return: scroll-one-line-up()\n\ q: quit()\n", "*.vertical.Translations: #override\n\ space: StartScroll(Forward) NotifyScroll(FullLength) EndScroll() \n\ Delete: StartScroll(Backward) NotifyScroll(FullLength) EndScroll() \n\ CtrlUp: KbdScroll(up,50) EndScroll()\n\ CtrlDown: KbdScroll(down,50) EndScroll()\n\ Up: KbdScroll(up,10) EndScroll()\n\ Down: KbdScroll(down,10) EndScroll()\n\ Page_Up: KbdScroll(up,90) EndScroll()\n\ Page_Down: KbdScroll(down,90) EndScroll()\n", "*.horizontal.translations: #override \n\ CtrlLeft: KbdScroll(left,50) EndScroll()\n\ CtrlRight: KbdScroll(right,50) EndScroll()\n\ Left: KbdScroll(left,10) EndScroll()\n\ Right: KbdScroll(right,10) EndScroll()\n", "*.horizontal.accelerators: #override \n\ CtrlLeft: KbdScroll(left,50) EndScroll()\n\ CtrlRight: KbdScroll(right,50) EndScroll()\n\ Left: KbdScroll(left,10) EndScroll()\n\ Right: KbdScroll(right,10) EndScroll()\n", "*.vertical.accelerators: #override \n\ CtrlUp: KbdScroll(up,50) EndScroll()\n\ CtrlDown: KbdScroll(down,50) EndScroll()\n\ Up: KbdScroll(up,10) EndScroll()\n\ Down: KbdScroll(down,10) EndScroll()\n\ Page_Up: KbdScroll(up,90) EndScroll()\n\ Page_Down: KbdScroll(down,90) EndScroll()\n", "*.nodeText.Translations: #override \n\ Noneb: beginning-of-file() \n\ Home: beginning-of-file() \n\ Delete: previous-page() \n\ Prior: previous-page() \n\ Next: next-page() \n\ space: next-page() \n\ None: select-end() info_click() \n", "*.arg.translations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n", "*.pane.text.translations: #override \n\ Noneq: MenuPopdown(help) \n\ Noneb: beginning-of-file() \n\ Home: beginning-of-file() \n\ Delete: previous-page() \n\ Prior: previous-page() \n\ Next: next-page() \n\ space: next-page() \n", "*.dialog.value.translations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n\ Tab: Complete()\n", "*.dialog.value.baseTranslations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n", "*.baseTranslations: #override \n\ Ctrlq: Quit()\n\ Ctrlc: Quit()\n\ Return: Accept()\n", "*Translations: #override \n\ q: Quit()\n\ c: Quit()\n\ Ctrl n: Next()\n\ Ctrl p: Prev()\n", "*minWidth: 200\n", "*minHeight: 100\n", NULL }; #ifndef optarg extern char *optarg; #endif // optarg extern char gitstring[]; #ifdef USING_LIBGC GC_find_leak = 1; GC_INIT(); #endif // USING_LIBGC // Make copies of argc/argv/envp so that we can start other // processes and know the environment we were started with. // my_argc = argc; // my_argv = argv; my_argv = dupargv(argv); my_envp = (void *)&envp[0]; euid = geteuid(); egid = getegid(); DISABLE_SETUID_PRIVILEGE; program_start_time = sec_now(); // For use by "Display Uptime" (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); #ifdef HAVE_LIBCURL curl_global_init(CURL_GLOBAL_ALL); #endif #ifdef HAVE_GRAPHICSMAGICK InitializeMagick(*argv); #else // HAVE_GRAPHICSMAGICK #ifdef HAVE_IMAGEMAGICK MagickCoreGenesis(*argv, MagickTrue); #endif // HAVE_IMAGEMAGICK #endif //HAVE_GRAPHICSMAGICK /* check fhs directories ?*/ /* setup values */ redo_list = FALSE; // init lists xa_config_dir[0]='\0'; delay_time = 0; last_weather_cycle = sec_now(); redraw_on_new_packet_data = 0; next_file_read = sec_now(); // init file replay timing redraw_on_new_data = 0; display_up = 0; display_up_first = 0; max_transmit_time = (time_t)900l; sec_next_gps = 0l; gprmc_save_string[0] = '\0'; gpgga_save_string[0] = '\0'; sec_next_raw_wx = 0l; auto_reply = 0; satellite_ack_mode = 0; last_time = 0l; next_time = (time_t)120l; net_last_time = 0l; net_next_time = (time_t)120l; posit_last_time = 0l; posit_next_time = 0l; wait_to_redraw=1; last_popup_x = 0; last_popup_y = 0; trap_segfault = 0; // Default is to dump core deselect_maps_on_startup = 0; debug_level = 0; install_colormap = 0; last_sound_pid = 0; my_last_course = 0; my_last_speed = 0; my_last_altitude = 0l; my_last_altitude_time = 0l; wx_station_type[0] = '\0'; last_alert_redraw = 0; igate_msgs_tx = 0; last_statusline = 0; // inactive statusline last_object[0] = '\0'; // initialize object dialog last_obj_grp = '\\'; last_obj_sym = '!'; clear_rain_data(); // init weather data clear_local_wx_data(); next_redraw = sec_now()+60; // init redraw timing last_redraw = sec_now(); lang_to_use_or[0] = '\0'; ag_error=0; // Reset the gps variables. xastir_snprintf(gps_sats, sizeof(gps_sats), "00"); gps_valid = 0; memset(&appshell, 0, sizeof(appshell)); // Here we had to add "g:" in order to allow -geometry to be // used and x: to allow xt arguments, which is actually parsed out // by the XtIntrinsics code, not directly in Xastir code. // while ((ag = getopt(argc, argv, "c:f:v:l:g:x:012346789timpV")) != EOF) { switch (ag) { case 'c': if (optarg) { xastir_snprintf(xa_config_dir,sizeof(xa_config_dir),"%s", optarg); fprintf(stderr,"Using config dir %s\n",xa_config_dir); } break; case 'f': // Track callsign if (optarg) { xastir_snprintf(temp_tracking_station_call, sizeof(temp_tracking_station_call), "%s", optarg); fprintf(stderr, "Tracking callsign %s\n", temp_tracking_station_call); (void)remove_leading_spaces(temp_tracking_station_call); (void)remove_trailing_spaces(temp_tracking_station_call); (void)remove_trailing_dash_zero(temp_tracking_station_call); (void)to_upper(temp_tracking_station_call); } break; case 't': fprintf(stderr,"Internal SIGSEGV handler enabled\n"); trap_segfault = 1; break; case 'v': fprintf(stderr,"debug"); if (optarg) { debug_level = atoi(optarg); fprintf(stderr," level %d", debug_level); } fprintf(stderr,"\n"); break; case 'V': printf("\nXastir V%s %s\n",xastir_version, gitstring); exit(0); break; case 'l': fprintf(stderr,"Language is"); if (optarg) { lang_to_use_or[0] = '\0'; if (strncasecmp(optarg,"ENGLISH", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "English"); } else if (strncasecmp(optarg,"DUTCH", 5) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Dutch"); } else if (strncasecmp(optarg,"FRENCH", 6) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "French"); } else if (strncasecmp(optarg,"GERMAN", 6) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "German"); } else if (strncasecmp(optarg,"SPANISH", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Spanish"); } else if (strncasecmp(optarg,"ITALIAN", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Italian"); } else if (strncasecmp(optarg,"PORTUGUESE",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Portuguese"); } else if (strncasecmp(optarg,"ELMERFUDD",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "ElmerFudd"); } else if (strncasecmp(optarg,"MUPPETSCHEF",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "MuppetsChef"); } else if (strncasecmp(optarg,"OLDEENGLISH",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "OldeEnglish"); } else if (strncasecmp(optarg,"PIGLATIN",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "PigLatin"); } else if (strncasecmp(optarg,"PIRATEENGLISH",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "PirateEnglish"); } else { ag_error++; fprintf(stderr," INVALID"); } if (!ag_error) { fprintf(stderr," %s", lang_to_use_or); } } fprintf(stderr,"\n"); break; case 'i': fprintf(stderr,"Install Colormap\n"); install_colormap = (int)TRUE; break; case 'm': fprintf(stderr,"De-select Maps\n"); deselect_maps_on_startup = (int)TRUE; break; case 'g': // -geometry Geometry = argv[optind++]; break; case 'x': // -xtsessionID optind++; // swallow argument, let XtIntrinsics deal with it. xt = 1; break; case 'p': // Disable popups disable_all_popups = 1; pop_up_new_bulletins = 0; warn_about_mouse_modifiers = 0; break; default: ag_error++; break; } } if (ag_error) { fprintf(stderr,"\nXastir Command line Options\n\n"); fprintf(stderr,"-c /path/dir Xastir config dir\n"); fprintf(stderr,"-f callsign Track callsign\n"); fprintf(stderr,"-i Install private Colormap\n"); fprintf(stderr,"-geometry WxH+X+Y Set Window Geometry\n"); fprintf(stderr,"-l Dutch Set the language to Dutch\n"); fprintf(stderr,"-l English Set the language to English\n"); fprintf(stderr,"-l French Set the language to French\n"); fprintf(stderr,"-l German Set the language to German\n"); fprintf(stderr,"-l Italian Set the language to Italian\n"); fprintf(stderr,"-l Portuguese Set the language to Portuguese\n"); fprintf(stderr,"-l Spanish Set the language to Spanish\n"); fprintf(stderr,"-l ElmerFudd Set the language to ElmerFudd\n"); fprintf(stderr,"-l MuppetsChef Set the language to MuppetsChef\n"); fprintf(stderr,"-l OldeEnglish Set the language to OldeEnglish\n"); fprintf(stderr,"-l PigLatin Set the language to PigLatin\n"); fprintf(stderr,"-l PirateEnglish Set the language to PirateEnglish\n"); fprintf(stderr,"-m Deselect Maps\n"); fprintf(stderr,"-p Disable popups\n"); fprintf(stderr,"-t Internal SIGSEGV handler enabled\n"); fprintf(stderr,"-v level Set the debug level\n"); fprintf(stderr,"-V Print version number and exit\n\n"); fprintf(stderr,"\n"); exit(0); // Exiting after dumping out command-line options } // If we don't make this call, we can't access Xt or // Xlib calls from multiple threads at the same time. // Note that Motif from the OSF (including OpenMotif) // still can't handle multiple threads talking to it at // the same time. See: // http://www.faqs.org/faqs/x-faq/part7/section-46.html // We'll probably have to add in a global mutex lock in // order to keep from accessing the widget set from more // than one thread. // XInitThreads(); // Set language attribs. Must be called prior to // XtVaOpenApplication(). (void)XtSetLanguageProc((XtAppContext) NULL, XtSetLanguageProc(NULL, NULL, NULL), (XtPointer) NULL ); if (Geometry) { // // Really we should be merging with the RDB database as well // and then parsing the final geometry (Xlib Programming // Manual section 14.4.3 and 14.4.4). // geometry_flags = XParseGeometry(Geometry, &geometry_x, &geometry_y, &geometry_width, &geometry_height); /* if ((WidthValue|HeightValue) & geometry_flags) { fprintf(stderr,"Found width/height\n"); } if (XValue & geometry_flags) { fprintf(stderr,"Found X-offset\n"); } if (YValue & geometry_flags) { fprintf(stderr,"Found Y-offset\n"); } fprintf(stderr, "appshell: Width:%4d Height:%4d X-offset:%4d Y-offset:%4d\n", (int)geometry_width, (int)geometry_height, (int)geometry_x, (int)geometry_y); */ } /* get User info */ user_id = getuid(); user_info = getpwuid(user_id); xastir_snprintf(user_dir, sizeof(user_dir), "%s", user_info->pw_dir); /* fprintf(stderr,"User %s, Dir %s\n",user_info->pw_name,user_dir); fprintf(stderr,"User dir %s\n",get_user_base_dir("")); fprintf(stderr,"Data dir %s\n",get_data_base_dir("")); */ /* check user directories */ if (filethere(get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user dir\n"); if (mkdir(get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); // Creature to feep later? // needs // fprintf(stderr,"Check to see if '%s' exists \n", // dirname(get_user_base_dir("")) ); exit(errno); } } if (filethere(get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user config dir\n"); if (mkdir(get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user data dir\n"); if (mkdir(get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user log dir\n"); if (mkdir(get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user tracklogs dir\n"); if (mkdir(get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user tmp dir\n"); if (mkdir(get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user gps dir\n"); if ( mkdir(get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making map_cache dir\n"); if (mkdir(get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } /* done checking user dirs */ #ifdef USE_PID_FILE_CHECK if (pid_file_check(xt) !=0 ) { fprintf(stderr,"pid_file_check failed:\t%s \n", strerror(errno) ); exit(errno); } #endif // initialize interfaces init_critical_section(&port_data_lock); // Protects the port_data[] array of structs init_critical_section(&output_data_lock); // Protects interface.c:channel_data() function only init_critical_section(&data_lock); // Protects global incoming_data_queue init_critical_section(&connect_lock); // Protects port_data[].thread_status and port_data[].connect_status // We should probably protect redraw_on_new_data, alert_redraw_on_update, and // redraw_on_new_packet_data variables as well? // Also need to protect dialogs. #ifdef HAVE_DB connections_initialized = 0; #endif // HAVE_DB #ifdef USE_MAP_CACHE map_cache_init(); #endif // USE_MAP_CACHE (void)bulletin_gui_init(); (void)db_init(); (void)draw_symbols_init(); (void)interface_gui_init(); (void)list_gui_init(); (void)locate_gui_init(); (void)geocoder_gui_init(); (void)location_gui_init(); (void)maps_init(); (void)messages_gui_init(); (void)popup_gui_init(); (void)track_gui_init(); (void)view_message_gui_init(); (void)wx_gui_init(); (void)igate_init(); clear_all_port_data(); // clear interface port data (void) signal(SIGINT,quit); // set signal on stop (void) signal(SIGQUIT,quit); (void) signal(SIGTERM,quit); // Make sure that we reset to SIG_DFL handler any time we spawn // a child process. This is so the child process doesn't call // restart() as well. Only the main process needs to call // restart() on receiving a SIGHUP. We can do this via the // following call: // // (void)signal(SIGHUP,SIG_DFL); // (void) signal(SIGHUP,restart); // Shut down/restart if SIGHUP received #ifndef OLD_PTHREADS (void) signal(SIGUSR1,usr1sig); // take a snapshot on demand (void) signal(SIGUSR2,usr2sig); // transmit now on demand #else // OLD_PTHREADS # warning ***** Old kernel detected: Disabling SIGUSR1 handler (snapshot on demand) ***** #endif // OLD_PTHREADS #ifdef HAVE_SIGIGNORE (void) sigignore(SIGPIPE); #else // HAVE_SIGIGNORE (void) signal(SIGPIPE,SIG_IGN); // set sigpipe signal to ignore #endif // HAVE_SIGIGNORE if (trap_segfault) { (void) signal(SIGSEGV,segfault); // set segfault signal to check } // Load program parameters or set to default values load_data_or_default(); // Start the listening socket. If we fork it early we end up // with much smaller process memory allocated for it and all its // children. The server will authenticate each client that // connects. We'll share all of our data with the server, which // will send it to all connected/authenticated clients. // Anything transmitted by the clients will come back to us and // standard igating rules should apply from there. if (enable_server_port) { tcp_server_pid = Fork_TCP_server(my_argc, my_argv, my_envp); udp_server_pid = Fork_UDP_server(my_argc, my_argv, my_envp); } if (deselect_maps_on_startup) { unlink( get_user_base_dir(SELECTED_MAP_DATA, temp_base_dir, sizeof(temp_base_dir)) ); // Remove the selected_maps.sys file } update_units(); // set up conversion factors and strings /* do language links */ if (strlen(lang_to_use_or) > 0) xastir_snprintf(lang_to_use, sizeof(lang_to_use), "%s", lang_to_use_or); xastir_snprintf(temp, sizeof(temp), "help/help-%s.dat", lang_to_use); (void)unlink(get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir))); // Note that this symlink will probably not fail. It's easy to // create a symlink that points to nowhere. if (symlink(get_data_base_dir(temp),get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir))) == -1) { fprintf(stderr,"Error creating database link for help.dat\n"); fprintf(stderr, "Couldn't create symlink: %s -> %s\n", get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir)), get_data_base_dir(temp)); exit(0); // Exiting 'cuz online help won't work. } xastir_snprintf(temp, sizeof(temp), "config/language-%s.sys", lang_to_use); (void)unlink(get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir))); // Note that this symlink will probably not fail. It's easy to // create a symlink that points to nowhere. if (symlink(get_data_base_dir(temp),get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir))) == -1) { fprintf(stderr,"Error creating database link for language.sys\n"); fprintf(stderr, "Couldn't create symlink: %s -> %s\n", get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir)), get_data_base_dir(temp)); exit(0); // We can't set our language, so exit. } /* (NEW) set help file area */ xastir_snprintf(HELP_FILE, sizeof(HELP_FILE), "%s", "config/help.dat"); #ifdef HAVE_FESTIVAL /* Initialize the festival speech synthesis port */ if (SayTextInit()) { fprintf(stderr,"Error connecting to Festival speech server.\n"); //exit(0); // Not worth exiting just because we can't talk! } #endif // HAVE_FESTIVAL /* populate the predefined object (SAR/Public service) struct */ Populate_predefined_objects(predefinedObjects); if (load_color_file()) { if (load_language_file(get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir)))) { init_device_names(); // set interface names clear_message_windows(); clear_popup_message_windows(); init_station_data(); // init station storage init_message_data(); // init messages reset_outgoing_messages(); // This convenience function calls (in turn): // XtToolkitInitialize() // XtCreateApplicationContext() // XtOpenDisplay() // XtAppCreateShell(). // appshell = XtVaOpenApplication( &app_context, "Xastir", NULL, 0, &argc, argv, fallback_resources, sessionShellWidgetClass, XmNmappedWhenManaged, FALSE, NULL); display = XtDisplay(appshell); if (!display) { fprintf(stderr,"%s: can't open display, exiting...\n", argv[0]); exit(-1); // Must exit here as we can't get our display. } XtSetValues(XmGetXmDisplay(display), NULL, 0); // DK7IN: now scanf and printf use "," instead of "." // that leads to several problems in the initialization. // // DK7IN: inserted next line here for avoiding scanf // errors during init! // // (void)setlocale(LC_NUMERIC, "C"); // DK7IN: It's now ok (void)setlocale(LC_CTYPE, "C"); // K4INT: Make sure strings work OK. setup_visual_info(display, DefaultScreen(display)); // Get colormap (N7TAP: do we need this if the screen // visual is TRUE or DIRECT? // cmap = DefaultColormapOfScreen(XtScreen(appshell)); if (visual_type == NOT_TRUE_NOR_DIRECT) { if (install_colormap) { cmap = XCopyColormapAndFree(display, cmap); XtVaSetValues(appshell, XmNcolormap, cmap, NULL); } } //fprintf(stderr,"***index_restore_from_file\n"); // Read the current map index file into the index linked list index_restore_from_file(); // Reload tactical calls. This implements persistence // for this type. reload_tactical_calls(); //fprintf(stderr,"***create_appshell\n"); // This call fills in the top-level window and then // calls XtRealize. // create_appshell(display, argv[0], argc, argv); // reset language attribs for numeric, program needs // decimal in US for all data! (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); // DK7IN: now scanf and printf work as wanted... //fprintf(stderr,"***check_fcc_data\n"); /* check for ham databases */ (void)check_rac_data(); (void)check_fcc_data(); // Find the extents of every map we have. Use the smart // timestamp-checking reindexing (quicker). if ( index_maps_on_startup ) { map_indexer(0); } // Check whether we're running Xastir for the first time. // If so, my_callsign will be "NOCALL". In this case // write "worldhi.map" into ~/.xastir/config/selected_maps.sys // so that we get the default map on startup. Also // request to bring up the Configure->Station dialog in // this case. // if (strncasecmp(my_callsign,"NOCALL",6) == 0) { FILE *ff; // fprintf(stderr,"***** First time run *****\n"); // Set the flag first_time_run = 1; // Write the default map into the selected map file ff = fopen( get_user_base_dir(SELECTED_MAP_DATA, temp_base_dir, sizeof(temp_base_dir)), "a"); if (ff != NULL) { fprintf(ff,"worldhi.map\n"); (void)fclose(ff); } } // Mark the "selected" field in the in-memory map index // to correspond to the selected_maps.sys file. map_chooser_init(); // Warn the user if altnet is enabled on startup. This // is so that the people who are button pushers/knob turners // will know what's wrong when they don't see stations on their // screen anymore. // if (altnet) { // "Warning" // "Altnet is enabled (File->Configure->Defaults dialog)"); popup_message_always( langcode("POPEM00035"), langcode("POPEM00051") ); } // Start UpdateTime. It schedules itself to be run // again each time. This is also the process that // starts up the interfaces. UpdateTime( (XtPointer) da, (XtIntervalId) NULL ); // Update the logging indicator Set_Log_Indicator(); XtAppMainLoop(app_context); } else { fprintf(stderr,"Error in language file! Exiting...\n"); } } else { fprintf(stderr,"Error in Color file! Exiting...\n"); } quit(0); return 0; } Xastir-Release-2.2.2/src/main.h000066400000000000000000000352131501463444000162360ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_MAIN_H #define XASTIR_MAIN_H #include // For mutex debugging with Linux threads only #ifdef __linux__ #define MUTEX_DEBUG 1 #endif // __linux__ // This gets defined if pthreads implementation uses SIGUSR1/SIGUSR2 // signals. This disables our SIGUSR1 handler which disallows // creating snapshots on receipt of that signal. Old kernels (2.0 // and early 2.1) had only 32 signals available so only USR1/USR2 // were available for LinuxThreads use. Newer kernels have more // signals available, making USR1/USR2 available to programs again. // _NSIG is defined in /usr/include/bits/signum.h // #ifdef __linux__ #ifdef _NSIG #if (_NSIG <= 32) #define OLD_PTHREADS //# warning ***** OLD_PTHREADS DETECTED ***** #else //# warning ***** NEW_PTHREADS DETECTED ***** #endif // if (_NSIG...) #endif // _NSIG #endif // __linux__ // To enable the "Transmit Raw WX data" button in // Configure->Defaults dialog. Warning: If you enable this, enable // the button in Configure->Defaults, and are running a weather // station that puts out raw data that is NOT allowed by the APRS // spec, you'll be putting out garbage and trashing the channel. // //#define TRANSMIT_RAW_WX // To use predefined object configuration files from within the // user's base directory e.g. ~/.xastir/config/predefined_SAR.sys // rather than from the main base directory, enable this definition. //#define OBJECT_DEF_FILE_USER_BASE extern int enable_server_port; extern char altnet_call[MAX_CALLSIGN+1]; extern int altnet; extern Widget iface_da; extern FILE *read_file_ptr; extern int interrupt_drawing_now; #define VERSIONFRM (!altnet?XASTIR_TOCALL:altnet_call) /* Packet version info */ #ifdef __LCLINT__ #define PACKAGE "xastir" #define VERSION "lclint" #define VERSIONTXT "xastir lclint debug version" #else // __LCLINT__ #define VERSIONTXT PACKAGE " " VERSION #endif // __LCLINT__ #define VERSIONLABEL VERSIONTXT // NOTE: This is out of date and not used anymore anyway. #define VERSIONMESSAGE "XASTIR Version: " VERSION "\n\nAmateur Station Tracking and Information Reporting\nby Frank Giannandrea, KC2GJS was KC0DGE\n Code added by:\n Richard Hagemeyer - VE3UNW, Curt Mills - WE7U,\n Mike Sims - KA9KIM, Gerald Stueve - K4INT was KE4NFJ,\n Mark Grennan - KD5AMB, Henk de Groot - PE1DNN,\n Jim Sevilla - KD6VPE, Jose R. Marte A. - HI8GN,\n Michael G. Petry - N3NYN, Lloyd Miller - VE6LFM,\n Alessandro Frigeri - IK0YUP,\n Chuck Byam - KG4IJB, Rolf Bleher - DK7IN, Ken Koster - N7IPB" // NOTE: This is out of date and not used anymore anyway. #define ABOUTGNUL "XASTIR, Copyright (C) 1999, 2000 Frank Giannandrea\nXASTIR comes with ABSOLUTELY NO WARRANTY;\nThis is free software, and you are welcome\nto redistribute it under certain conditions;\nsee the GNU LICENSE for details.\n" #define MAX_PHG 8 #define MAX_COMMENT 80 ////////////////////////////////////////////////////////////////////// // These globals and prototypes are from: // http://lightconsulting.com/~thalakan/process-title-notes.html // They seems to work fine on Linux, but they only change the "ps" // listings, not the top listings. I don't know why yet. /* Globals */ //extern char **Argv = ((void *)0); //extern char *__progname, *__progname_full; //extern char *LastArgv = ((void *)0); /* Prototypes */ extern void set_proc_title(char *fmt,...); extern void init_set_proc_title(int argc, char *argv[], char *envp[]); // New stuff defined by Xastir project: extern int my_argc; extern char **my_argv; extern char **my_envp; ////////////////////////////////////////////////////////////////////// extern int input_x; extern int input_y; #define MAX_RELAY_DIGIPEATER_CALLS 50 extern char relay_digipeater_calls[10*MAX_RELAY_DIGIPEATER_CALLS]; extern int skip_dupe_checking; extern int serial_char_pacing; // Inter-character delay in ms. extern int disable_all_maps; extern int re_sort_maps; extern Widget trackme_button; extern Widget CAD_close_polygon_menu_item; extern int debug_level; extern int my_position_valid; extern int using_gps_position; extern int transmit_now; extern char DATABASE_FILE[]; extern char DATABASE_POINTER_FILE[]; extern char DATABASE_POINTER_TEMP[]; extern char ALERT_MAP_DIR[400]; extern char SELECTED_MAP_DIR[400]; extern char SELECTED_MAP_DATA[400]; extern char MAP_INDEX_DATA[400]; extern char AUTO_MAP_DIR[400]; extern char SYMBOLS_DIR[400]; extern char LOGFILE_IGATE[400]; extern char LOGFILE_TNC[400]; extern char LOGFILE_NET[400]; extern char LOGFILE_MESSAGE[400]; extern char LOGFILE_WX[400]; extern char LOGFILE_WX_ALERT[400]; extern char HELP_FILE[]; extern char SOUND_DIR[400]; extern time_t WX_ALERTS_REFRESH_TIME; extern time_t remove_ID_message_time; extern int pending_ID_message; extern time_t gps_time; extern time_t POSIT_rate; extern time_t OBJECT_rate; extern time_t update_DR_rate; extern time_t posit_last_time; extern time_t posit_next_time; extern int smart_beaconing; extern int sb_POSIT_rate; extern int sb_last_heading; extern int sb_current_heading; extern time_t sb_last_posit_time; extern int sb_turn_min; extern int sb_turn_slope; extern int sb_turn_time; extern int sb_posit_fast; extern int sb_posit_slow; extern int sb_low_speed_limit; extern int sb_high_speed_limit; extern int pop_up_new_bulletins; extern int view_zero_distance_bulletins; extern int warn_about_mouse_modifiers; extern int predefined_menu_from_file; extern int draw_labeled_grid_border; // used to turn on or off border on map extern int my_trail_diff_color; // trails for mycall with different ssids have the same or a different color extern int output_station_type; extern int emergency_beacon; typedef struct _selections { int none; int mine; int tnc; int direct; int via_digi; int net; int tactical; int old_data; int stations; int fixed_stations; int moving_stations; int weather_stations; int CWOP_wx_stations; int objects; int weather_objects; int gauge_objects; int other_objects; int aircraft_objects; int vessel_objects; } Selections; extern Selections Select_; typedef struct _what_to_display { int callsign; int label_all_trackpoints; int symbol; int symbol_rotate; int trail; int course; int speed; int speed_short; int altitude; int weather; int weather_text; int temperature_only; int wind_barb; int aloha_circle; int ambiguity; int phg; int default_phg; int phg_of_moving; int df_data; int df_beamwidth_data; int df_bearing_data; int dr_data; int dr_arc; int dr_course; int dr_symbol; int dist_bearing; int last_heard; } What_to_display; extern What_to_display Display_; extern int currently_selected_stations; extern int currently_selected_stations_save; extern Pixel colors[256]; #define MAX_TRAIL_COLORS 32 extern Pixel trail_colors[MAX_TRAIL_COLORS]; extern int current_trail_color; extern int english_units; extern int do_dbstatus; extern int redraw_on_new_data; extern int redo_list; extern int operate_as_an_igate; #ifdef TRANSMIT_RAW_WX extern int transmit_raw_wx; #endif // TRANSMIT_RAW_WX extern int transmit_compressed_posit; extern int transmit_compressed_objects_items; extern int log_igate; extern int log_tnc_data; extern int log_net_data; extern int log_message_data; extern int log_wx_alert_data; extern int log_wx; extern int snapshots_enabled; extern int kmlsnapshots_enabled; extern char user_dir[]; extern char lang_to_use[30]; extern char my_group; extern char my_symbol; extern char my_phg[MAX_PHG+1]; extern char my_comment[MAX_COMMENT+1]; extern int map_background_color; extern int map_color_fill; extern int letter_style; extern int icon_outline_style; extern int wx_alert_style; extern time_t map_refresh_interval; extern time_t map_refresh_time; extern char sound_command[90]; extern pid_t last_sound_pid; extern int sound_play_new_station; extern int sound_play_new_message; extern int sound_play_prox_message; extern int sound_play_band_open_message; extern int sound_play_wx_alert_message; extern char sound_new_station[90]; extern char sound_new_message[90]; extern char sound_prox_message[90]; extern char sound_band_open_message[90]; extern char sound_wx_alert_message[90]; extern int ATV_screen_ID; extern int festival_speak_ID; extern int festival_speak_new_station; extern int festival_speak_proximity_alert; extern int festival_speak_tracked_proximity_alert; extern int festival_speak_band_opening; extern int festival_speak_new_message_alert; extern int festival_speak_new_message_body; extern int festival_speak_new_weather_alert; extern char prox_min[30]; extern char prox_max[30]; extern time_t sec_old; extern time_t sec_clear; extern time_t aircraft_sec_clear; extern int trail_segment_time; extern int trail_segment_distance; extern int RINO_download_interval; extern int dead_reckoning_timeout; extern char bando_min[30]; extern char bando_max[30]; extern int Display_packet_data_type; extern int show_only_station_capabilities; extern int Display_packet_data_mine_only; extern int menu_x; extern int menu_y; extern long my_last_altitude; extern time_t my_last_altitude_time; extern int my_last_course; extern int my_last_speed; // in knots extern unsigned igate_msgs_tx; extern int symbols_loaded; extern GC gc2; extern GC gc_tint; extern GC gc_stipple; extern GC gc_bigfont; extern int read_file; extern float x_screen_distance; extern time_t max_transmit_time; extern int transmit_disable; extern int posit_tx_disable; extern int object_tx_disable; extern int map_chooser_expand_dirs; extern int request_new_image; extern int disable_all_popups; extern char temp_tracking_station_call[30]; extern int coordinate_system; #define USE_DDDDDD 0 #define USE_DDMMMM 1 #define USE_DDMMSS 2 #define USE_UTM 3 #define USE_UTM_SPECIAL 4 #define USE_MGRS 5 typedef struct { Widget calling_dialog; // NULL if the calling dialog has been closed. Widget input_lat_deg; // Pointers to calling dialog's widgets Widget input_lat_min; // (Where to get/put the data) Widget input_lat_dir; Widget input_lon_deg; Widget input_lon_min; Widget input_lon_dir; } coordinate_calc_array_type; extern coordinate_calc_array_type coordinate_calc_array; extern void Coordinate_calc(Widget w, XtPointer clientData, XtPointer callData); extern void HandlePendingEvents(XtAppContext app); extern void create_gc(Widget w); extern void Station_info(Widget w, XtPointer clientData, XtPointer calldata); extern void Station_List(Widget w, XtPointer clientData, XtPointer calldata); extern void Tracks_All_Clear(Widget w, XtPointer clientData, XtPointer callData); extern void Locate_station(Widget w, XtPointer clientData, XtPointer callData); extern void Locate_place(Widget w, XtPointer clientData, XtPointer callData); extern void Geocoder_place(Widget w, XtPointer clientData, XtPointer callData); extern void Display_Wx_Alert(Widget w, XtPointer clientData, XtPointer callData); extern void Auto_msg_option(Widget w, XtPointer clientData, XtPointer calldata); extern void Auto_msg_set(Widget w, XtPointer clientData, XtPointer calldata); extern void Bulletins(Widget w, XtPointer clientData, XtPointer callData); extern void on_off_switch(int switchpos, Widget first, Widget second); extern void busy_cursor(Widget w); extern void pos_dialog(Widget w); extern int create_image(Widget w); typedef struct _transparent_color_record { unsigned long trans_color; struct _transparent_color_record *next; } transparent_color_record; extern int check_trans (XColor c, transparent_color_record *c_trans_color_head); extern void draw_WMS_map (Widget w, char *filenm, int destination_pixmap, char *URL, transparent_color_record *c_trans_color_head, int nocache); extern void locate_gui_init(void); extern void geocoder_gui_init(void); extern void location_gui_init(void); extern void view_message_gui_init(void); extern void wx_gui_init(void); extern long get_x_scale(long x, long y, long ysc); extern Widget Display_data_dialog; extern Widget Display_data_text; extern Widget text3; extern Widget text4; extern Widget log_indicator; extern void display_zoom_status(void); extern void Center_Zoom(Widget w, XtPointer clientData, XtPointer calldata); extern int center_zoom_override; extern void statusline(char *status_text,int update); extern void stderr_and_statusline(char *message); extern int SayTextInit(void); extern int SayText(char *text); extern Widget auto_msg_toggle; // Symbol update stuff extern Widget configure_station_dialog; extern Widget station_config_group_data; extern Widget station_config_symbol_data; extern void updateSymbolPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern Widget object_dialog; extern Widget object_group_data; extern Widget object_symbol_data; extern void updateObjectPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern void Draw_All_CAD_Objects(Widget w); // unit conversion extern char un_alt[2+1]; extern char un_dst[2+1]; extern char un_spd[4+1]; extern double cvt_m2len; extern double cvt_dm2len; extern double cvt_hm2len; extern double cvt_kn2len; extern double cvt_mi2len; // euid and egid extern uid_t euid; extern gid_t egid; /* JMT - works in FreeBSD */ // Note: weird conditional thing is there just to shut up // "ignoring return value" warnings from GCC on newer Linux systems #define DISABLE_SETUID_PRIVILEGE do { \ if (seteuid(getuid())==0){/* all is well*/} \ if (setegid(getgid())==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)getuid(), (int)getgid()); } \ } while(0) #define ENABLE_SETUID_PRIVILEGE do { \ if (seteuid(euid)==0){/* all is well*/} \ if (setegid(egid)==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)euid, (int)egid); } \ } while(0) #ifdef HAVE_LIBSHP extern void create_map_from_trail(char *call_sign); #endif // HAVE_LIBSHP #endif /* XASTIR_MAIN_H */ Xastir-Release-2.2.2/src/map_OSM.c000066400000000000000000001574241501463444000166110ustar00rootroot00000000000000/* * * * Copyright (C) 2000-2023 The Xastir Group * * This file was contributed by Jerry Dunmire, KA6HLD. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * This file derived from map_tiger.c which has the following copyrights: * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "color.h" #include "xa_config.h" #include "map_cache.h" #include "tile_mgmnt.h" #include "dlm.h" #include "map_OSM.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION // This matte color was chosen emphirically to work well with the // contours from topOSM. #if (QuantumDepth == 8) #define MATTE_RED (0xa7) #define MATTE_GREEN (0xa7) #define MATTE_BLUE (0xa7) #define MATTE_OPACITY (0x00) #define MATTE_COLOR_STRING "xc:#a7a7a7" //#define MATTE_COLOR_STRING "xc:#a7a7a700" //#define MATTE_OPACITY (0xff) //#define MATTE_COLOR_STRING "xc:#a7a7a7ff" #elif (QuantumDepth == 16) #define MATTE_RED (0xa700) #define MATTE_GREEN (0xa700) #define MATTE_BLUE (0xa700) #define MATTE_OPACITY (0x0000) #define MATTE_COLOR_STRING "xc:#a700a700a700" //#define MATTE_COLOR_STRING "xc:#a700a700a700ffff" #else #error "QuantumDepth != 16 or 8" #endif // QuantumDepth #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" #define xastirColorsMatch(p,q) (((p).red == (q).red) && ((p).blue == (q).blue) \ && ((p).green == (q).green)) // osm_scale_x - map Xastir scale_x value to an OSM binned value // // Note that the terms 'higher' and 'lower' are confusing because a // smaller Xastir scale number is a larger OSM zoom level. OSM zoom level // 0 would show the whole world in a 256x256 pixel tile, OSM zoom level // 18 (the max) would require 2^18 tiles to simple wrap the equator. // // On the equator, OSM zoom level 0 equates to ~97 miles/pixel // and OSM zoom level 18 equates to ~2 ft/pixel // // direction = -1, zoom in // direction = 1, zoom out // direction = 0, nearst level out from the xastir scale // #define MAX_OSM_ZOOM_LEVEL 18 #define OSM_ZOOM_LEVELS (MAX_OSM_ZOOM_LEVEL + 1) static long osm_scale_x(long xastir_scale_x) { long osm_level[OSM_ZOOM_LEVELS] = {1, 2, 4, 8, 15, 31, 62, 124, \ 247, 494, 989, 1978, 3955, 7910, 15820, 31641,\ 63281, 126563, 253125 }; long osm_scale_x = osm_level[0]; int i = 0; for (i=1; i <= MAX_OSM_ZOOM_LEVEL; i++) { if (xastir_scale_x > osm_level[i]) { continue; } else { if (labs(osm_level[i - 1] - xastir_scale_x) < labs(osm_level[i] - xastir_scale_x)) { osm_scale_x = osm_level[i - 1]; } else { osm_scale_x = osm_level[i]; } break; } } if (i > MAX_OSM_ZOOM_LEVEL) { i = MAX_OSM_ZOOM_LEVEL; osm_scale_x = osm_level[i]; } return(osm_scale_x); } // osm_scale_x() /* * adj_to_OSM_level - adjust scale_x and scale_y to approximate an OSM zoom level * * The OSM zoom level closest to the scale_x value will be chosen and scale_x is modified. * The scale_y value (pointed to by the second argument) is scaled proportionaly. Both * values pointed to by the arguments are modified. */ void adj_to_OSM_level( long *new_scale_x, long *new_scale_y) { long scale; scale = osm_scale_x(*new_scale_x); // the y scale must also be adjusted. *new_scale_y = (int)(((double)(*new_scale_y) * ((double)scale / (double)(*new_scale_x)) + 0.5)); *new_scale_x = scale; return; } // adj_to_OSM_level() /* * osm_zoom_level - translate the longitude scale to the nearest OSM zoom level * * OSM tile scaling is based on the number of tiles needed to wrap the earth at the equator. * A tile is 256x256 pixels. */ unsigned int osm_zoom_level(long scale_x) { double circumference = 360.0*3600.0*100.0; // Xastir Units = 1/100 second. double zf; int z; zf = (log(circumference / (double)scale_x) / log(2.0)) - 8.0; z = (int)(zf + 0.5); // OSM levels run from 0 to 18. Not all levels are available for all views. if (z < 0) { z = 0; } if (z > 18) { z = 18; } return((unsigned int)z); } // osm_zoom_level() static KeySym OptimizeKey = 0; static KeySym ReportScaleKey = 0; void init_OSM_values(void) { OptimizeKey = 0; ReportScaleKey = 0; return; } int OSM_optimize_key(KeySym key) { return (key == OptimizeKey ? TRUE : FALSE); } void set_OSM_optimize_key(KeySym key) { OptimizeKey = key; return; } int OSM_report_scale_key(KeySym key) { return (key == ReportScaleKey ? TRUE : FALSE); } void set_OSM_report_scale_key(KeySym key) { ReportScaleKey = key; return; } #ifdef HAVE_MAGICK static void get_OSM_local_file(char * local_filename, char * fileimg) { time_t query_start_time, query_end_time; #ifdef USE_MAP_CACHE int map_cache_return = 1; // Default = cache miss char *cache_file_id; #endif // USE_MAP_CACHE char temp_file_path[MAX_VALUE]; if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (!map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } set_dangerous("map_OSM: map_cache_get"); map_cache_return = map_cache_get(fileimg,local_filename); clear_dangerous(); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: <%d> bytes returned: %d\n", map_cache_return, (int) strlen(local_filename)); } if (map_cache_return != 0 ) { set_dangerous("map_OSM: map_cache_fileid"); cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, MAX_FILENAME, // hardcoded to avoid sizeof() "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, "png"); free(cache_file_id); clear_dangerous(); #else // USE_MAP_CACHE xastir_snprintf(local_filename, MAX_FILENAME, // hardcoded to avoid sizeof() "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same name. // This avoids the problem of having an old map image here and // the code trying to display it when the download fails. unlink( local_filename ); if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // For debugging the MagickError/MagickWarning segfaults. //system("cat /dev/null >/var/tmp/xastir_hacker_map.png"); #ifdef USE_MAP_CACHE set_dangerous("map_OSM: map_cache_put"); map_cache_put(fileimg,local_filename); clear_dangerous(); } // end if is cached DHBROWN #endif // MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); } // end get_OSM_local_file #endif //HAVE_MAGICK #ifdef HAVE_MAGICK static long xastirLat2pixelLat( long xlat, int osm_zoom ) { double lat; // in radians double projection, y; long pixelLat; lat = convert_lat_l2r(xlat); // xastir latitude values can exceed +/- 90.0 degrees because // the latitude is the extent of the display window. Limit the // OSM latitude to less than +/- 90.0 degrees so that the projection // calculation does not blow up or return unreasonable values. if (lat > ((89.0/180.0) * M_PI)) { lat = ((89.0/180.0) * M_PI); } else if (lat < ((-89.0/180.0) * M_PI)) { lat = ((-89.0/180.0) * M_PI); } projection = log(tan(lat) + (1.0 / cos(lat))); y = projection / M_PI; y = 1.0 - y; pixelLat = (long)((y * (double)(1<<(osm_zoom + 8))) / 2.0); return(pixelLat); } // xastirLat2pixelLat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static double pixelLat2Lat(long osm_lat, int osm_zoom) { double lat, projection, y; y = (double)osm_lat * 2.0 / (double)(1<<(osm_zoom + 8)); y = 1.0 - y; projection = y * M_PI; lat = 2.0 * atan(exp(projection)) - (M_PI / 2.0); lat = (lat * 180.0 ) / M_PI; return(lat); } // pixelLat2Lat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long pixelLat2xastirLat(long osm_lat, int osm_zoom) { double lat; long xastirLat; lat = pixelLat2Lat(osm_lat, osm_zoom); xastirLat = (long)((90.0 - lat) * 3600.0 * 100.0); return (xastirLat); } // pixelLat2xastirLat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long xastirLon2pixelLon( long xlon, int osm_zoom) { double lon; long pixelLon; lon = xlon / (3600.0 * 100.0); lon = lon * (1<<(osm_zoom +8)); lon = lon / 360.0; pixelLon = lon; return(pixelLon); } // xastirLon2pixelLon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static double pixelLon2Lon(long osm_lon, int osm_zoom) { double lon; lon = osm_lon * 360.0 ; lon = lon / (1<<(osm_zoom + 8)); return(lon); } // pixelLon2Lon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long pixelLon2xastirLon(long osm_lon, int osm_zoom) { long xastirLon; xastirLon = (long)(pixelLon2Lon(osm_lon, osm_zoom) * 3600.0 * 100.0); return(xastirLon); } // pixelLon2xastirLon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK /********************************************************** * draw_image() - copy a image onto the display **********************************************************/ static void draw_image( Widget w, Image *image, ExceptionInfo *except_ptr, unsigned offsetx, unsigned offsety) { int l; XColor my_colors[256]; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; unsigned image_row; unsigned image_col; unsigned scr_x, scr_y; // screen pixel plot positions //if (debug_level & 512) // fprintf(stderr,"Color depth is %i \n", (int)image->depth); /* if (image->colorspace != RGBColorspace) { TransformImageColorspace(image, RGBColorspace); //fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); //return; } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, except_ptr) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, except_ptr); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as // ImageMagick can read in all sorts of image files temp_pack = image->colormap[l]; //if (debug_level & 512) // fprintf(stderr,"Colormap color is %i %i %i \n", // temp_pack.red, temp_pack.green, temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as // Quantum's. Quantum is defined in // /usr/include/magick/image.h as either an unsigned short // or an unsigned char, depending on what "configure" // decided when ImageMagick was installed. We can determine // which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } //if (debug_level & 512) // fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, // my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } // loop over image pixel rows for (image_row = 0; image_row < image->rows; image_row++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = image_row + offsety; // loop over image pixel columns for (image_col = 0; image_col < image->columns; image_col++) { scr_x = image_col + offsetx; // now copy a pixel from the image to the screen l = image_col + (image_row * image->columns); if (image->storage_class == PseudoClass) { // Make matte transparent if (xastirColorsMatch(pixel_pack[l],image->matte_color)) { continue; } XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); } else { // Skip transparent pixels if (pixel_pack[l].opacity == TransparentOpacity) { continue; } // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); } // write the pixel from the map image to the // screen. (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,1,1); } // loop over map pixel columns } // loop over map pixel rows return; } // end draw_image() /********************************************************** * draw_OSM_image() - copy map image to display **********************************************************/ static void draw_OSM_image( Widget w, Image *image, ExceptionInfo *except_ptr, tiepoint *tpNW, tiepoint *tpSE, int osm_zl) { int l; XColor my_colors[256]; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; long map_image_row; long map_image_col; long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; int map_seen = 0; int map_act; int map_done; long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions //if (debug_level & 512) // fprintf(stderr,"Color depth is %i \n", (int)image->depth); /* if (image->colorspace != RGBColorspace) { TransformImageColorspace(image, RGBColorspace); //fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); //return; } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, except_ptr) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, except_ptr); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as // ImageMagick can read in all sorts of image files temp_pack = image->colormap[l]; //if (debug_level & 512) // fprintf(stderr,"Colormap color is %i %i %i \n", // temp_pack.red, temp_pack.green, temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as // Quantum's. Quantum is defined in // /usr/include/magick/image.h as either an unsigned short // or an unsigned char, depending on what "configure" // decided when ImageMagick was installed. We can determine // which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { //if (debug_level & 512) // fprintf(stderr,"Color quantum is [0..65535]\n"); my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { //if (debug_level & 512) // fprintf(stderr,"Color quantum is [0..255]\n"); my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } //if (debug_level & 512) // fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, // my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our image were calculated and stored * above as tiepoints using OSM units (pixels/circle). They are: * * left edge of map = tp[0].x_long * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ scr_dx = 1; scr_dy = 1; // calculate map pixel range in y direction that falls into screen area map_y_min = map_y_max = 0l; for (map_image_row = 0; map_image_row < (long)image->rows; map_image_row++) { scr_y = (pixelLat2xastirLat(map_image_row + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y; if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_image_row; // update last map pixel in y } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_image_row; // update first map pixel in y } } // Calculate the position of the map image relative to the screen map_x_min = map_x_max = 0l; for (map_image_col = 0; map_image_col < (long)image->columns; map_image_col++) { scr_x = (pixelLon2xastirLon(map_image_col + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x; if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_image_col; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_image_col; // update first map pixel in x } } scr_yp = -1; map_done = 0; map_act = 0; map_seen = 0; // loop over map pixel rows for (map_image_row = map_y_min; (map_image_row <= map_y_max); map_image_row++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = (pixelLat2xastirLat(map_image_row + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y; // image rows do not match 1:1 with screen rows due to Mercator // scaling, so scr_dy will be passed to XFillRectangle to // handle that issue. // scr_dy is in rows and must be a minimum of 1 row. scr_dy = (( pixelLat2xastirLat(map_image_row + 1 + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y) - scr_y; if (scr_dy < 1) { scr_dy = 1; } if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y scr_xp = -1; // loop over map pixel columns map_act = 0; for (map_image_col = map_x_min; map_image_col <= map_x_max; map_image_col++) { scr_x = ( pixelLon2xastirLon(map_image_col + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x; // handle the case when here the horizontal resolution // of the image is less than the horizontal resolution // displayed. scr_dx is passed to XFillRectangle() below // and must be at least 1 column. scr_dx = ( (pixelLon2xastirLon(map_image_col + 1 + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x) - scr_x; if (scr_dx < 1) { scr_dx = 1; } if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x // check map boundaries in y direction if (map_image_row >= 0 && map_image_row <= tpSE->img_y) { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // now copy a pixel from the map image to the screen l = map_image_col + map_image_row * image->columns; if (image->storage_class == PseudoClass) { // Make matte transparent by skipping pixels if (xastirColorsMatch(pixel_pack[l],image->matte_color)) { continue; } XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); } else { // Skip transparent pixels and make matte // colored pixels transparent (by skipping) if ((pixel_pack[l].opacity == TransparentOpacity) || (xastirColorsMatch(pixel_pack[l], image->matte_color))) { continue; } // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); } // write the pixel from the map image to the // screen. Stretch to a rectangle as needed // specified by scr_dx and scr_dy. (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } // check map boundaries in y direction } // don't do a screen pixel twice (in the same row) } // loop over map pixel columns if (map_seen && !map_act) { map_done = 1; } (void)map_done; // map_done is never used, but this takes away the compile warning. } // don't do a screen row twice. } // loop over map pixel rows } // end draw_OSM_image() /********************************************************** * draw_OSM_tiles() - retrieve enough map tiles to fill the display **********************************************************/ // MaxTextExtent is an ImageMagick/GraphicMagick constant #define MAX_TMPSTRING MaxTextExtent void draw_OSM_tiles (Widget w, char *filenm, // this is the name of the xastir map file int destination_pixmap, char *server_url, // if specified in xastir map file char *tileCacheDir, // if specified in xastir map file char *mapName, // if specified in xastir map file char *tileExt) // if specified in xastir map file { char serverURL[MAX_FILENAME]; char tileRootDir[MAX_FILENAME]; char map_it[MAX_FILENAME]; char short_filenm[MAX_FILENAME]; int osm_zl; tileArea_t tiles; coord_t corner; tiepoint NWcorner; tiepoint SEcorner; unsigned long tilex, tiley; unsigned long tileCnt = 0; unsigned long numTiles; int interrupted = 0; ExceptionInfo exception; Image *canvas = NULL; Image *tile = NULL; ImageInfo *canvas_info = NULL; ImageInfo *tile_info = NULL; unsigned int row, col; unsigned int offset_x, offset_y; char tmpString[MAX_TMPSTRING]; char temp_file_path[MAX_VALUE]; // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), // Indexing %s short_filenm); statusline(map_it,0); // Indexing return; // Done indexing this file } if (tileCacheDir[0] != '\0') { if (tileCacheDir[0] == '/') { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", tileCacheDir); } else { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", get_user_base_dir(tileCacheDir, temp_file_path, sizeof(temp_file_path))); } } else { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", get_user_base_dir("OSMtiles", temp_file_path, sizeof(temp_file_path))); } if (mapName[0] != '\0') { xastir_snprintf(tmpString, sizeof(tmpString), "/%s", mapName); strncat(tileRootDir, tmpString, sizeof(tileRootDir) - 1 - strlen(tileRootDir)); } if (server_url[0] != '\0') { xastir_snprintf(serverURL, sizeof(serverURL), "%s", server_url); } else { xastir_snprintf(serverURL, sizeof(serverURL), "%s", "http://tile.openstreetmap.org"); } if (server_url[strlen(serverURL) - 1] == '/') { serverURL[strlen(serverURL) - 1] = '\0'; } // Create a shorter filename for display (one that fits the // status line more closely). Allow space for the // "Indexing " or "Loading " strings. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } GetExceptionInfo(&exception); if (debug_level & 512) { unsigned long lat, lon; (void)convert_to_xastir_coordinates(&lon, &lat, f_NW_corner_longitude, f_NW_corner_latitude); fprintf(stderr, "NW_corner_longitude = %f, %ld, %ld\n", f_NW_corner_longitude, NW_corner_longitude, lon); fprintf(stderr, "NW_corner_latitude = %f, %ld, %ld\n", f_NW_corner_latitude, NW_corner_latitude, lat); (void)convert_to_xastir_coordinates(&lon, &lat, f_SE_corner_longitude, f_SE_corner_latitude); fprintf(stderr, "SE_corner_longitude = %f, %ld, %ld\n", f_SE_corner_longitude, SE_corner_longitude, lon); fprintf(stderr, "SE_corner_latitude = %f, %ld, %ld\n", f_SE_corner_latitude, SE_corner_latitude, lat); } osm_zl = osm_zoom_level(scale_x); calcTileArea(f_NW_corner_longitude, f_NW_corner_latitude, f_SE_corner_longitude, f_SE_corner_latitude, osm_zl, &tiles); xastir_snprintf(map_it, sizeof(map_it), "%s", langcode ("BBARSTA050")); // Downloading tiles... statusline(map_it,0); XmUpdateDisplay(text); // make sure all the map directories exist mkOSMmapDirs(tileRootDir, tiles.startx, tiles.endx, osm_zl); // Check to see how many tiles need to be downloaded // A simple calculation doesn't work well here because some // (possibly all) of the tiles may exist in the cache. numTiles = tilesMissing(tiles.startx, tiles.endx, tiles.starty, tiles.endy, osm_zl, tileRootDir, tileExt[0] != '\0' ? tileExt : "png"); // get the tiles tileCnt = 1; for (tilex = tiles.startx; tilex <= tiles.endx; tilex++) { for (tiley = tiles.starty; tiley <= tiles.endy; tiley++) { if ((numTiles > 0) & (tileCnt <= numTiles)) { xastir_snprintf(map_it, sizeof(map_it), langcode("BBARSTA051"), tileCnt, numTiles); // Downloading tile %ls of %ls statusline(map_it,0); XmUpdateDisplay(text); } DLM_queue_tile(serverURL, tilex, tiley, osm_zl, tileRootDir, tileExt[0] != '\0' ? tileExt : "png"); } } // if the Download Manager is not using threaded (background) mode, // we need this to actually do the downloads. // In threaded mode, it does nothing DLM_do_transfers(); if (interrupt_drawing_now) { interrupted = 1; } if (interrupted != 1) { // calculate tie points NWcorner.img_x = 0; NWcorner.img_y = 0; NWcorner.x_long = tiles.startx * 256; NWcorner.y_lat = tiles.starty * 256; if (debug_level & 512) { fprintf(stderr, "scale = %ld, zoom = %d\n", scale_x, osm_zl); fprintf(stderr, "NW corner:\n"); fprintf(stderr, " img_x = %d, img_y = %d\n", NWcorner.img_x, NWcorner.img_y); fprintf(stderr, " x_long = %ld, y_lat = %ld\n", NWcorner.x_long, NWcorner.y_lat); fprintf(stderr, "req. lon = %f, lat = %f\n", f_NW_corner_longitude, f_NW_corner_latitude); tile2coord(tiles.startx, tiles.starty, osm_zl, &corner); fprintf(stderr, "ret. lon = %f, lat = %f\n", corner.lon, corner.lat); fprintf(stderr, "tile x = %li, y = %li\n", tiles.startx, tiles.starty); } // The NW corner of the next tile is the SE corner of the last tile // we fetched. So add one to the end tile numbers before calculating // the coordinates. SEcorner.img_x = (256 * ((tiles.endx + 1) - tiles.startx)) - 1; SEcorner.img_y = (256 * ((tiles.endy + 1) - tiles.starty)) - 1; SEcorner.x_long = (tiles.endx + 1) * 256; SEcorner.y_lat = (tiles.endy + 1) * 256; if (debug_level & 512) { fprintf(stderr, "SE corner:\n"); fprintf(stderr, " img_x = %d, img_y = %d\n", SEcorner.img_x, SEcorner.img_y); fprintf(stderr, " x_long = %ld, y_lat = %ld\n", SEcorner.x_long, SEcorner.y_lat); fprintf(stderr, "req. lon = %f, lat = %f\n", f_SE_corner_longitude, f_SE_corner_latitude); tile2coord(tiles.endx + 1, tiles.endy + 1, osm_zl, &corner); fprintf(stderr, "ret. lon = %f, lat = %f\n", corner.lon, corner.lat); fprintf(stderr, "tile x = %li, y = %li\n", tiles.endx, tiles.endy); } /* * Create a canvas upon which the tiles will be composited. */ canvas_info=CloneImageInfo((ImageInfo *)NULL); // Set canvas dimensions in pixels xastir_snprintf(tmpString, sizeof(tmpString), "%lix%li", ((tiles.endx + 1) - tiles.startx) * 256, ((tiles.endy + 1) - tiles.starty) * 256); (void)CloneString(&canvas_info->size, tmpString); /* * A file name based on a color creates an image filled * with that color. The matte color will be treated as * transparent when the completed OSM map gets copied to the X * display. */ xastir_snprintf(canvas_info->filename, sizeof(canvas_info->filename), "%s", MATTE_COLOR_STRING); canvas = ReadImage(canvas_info, &exception); if (exception.severity != UndefinedException) { CatchException(&exception); fprintf(stderr, "Could not allocate canvas to hold tiles.\n"); if (canvas_info != NULL) { DestroyImageInfo(canvas_info); } return; } // Make sure that the canvas is an image type that uses the // opacity channel for compositing. SetImageType(canvas, PaletteMatteType); // Fill the image with an opaque color. Ultimately pixels that // are this color will be skipped when the image is written to // the screen. canvas->background_color.red = MATTE_RED; canvas->background_color.green = MATTE_GREEN; canvas->background_color.blue = MATTE_BLUE; canvas->background_color.opacity = MATTE_OPACITY; #if defined(HAVE_GRAPHICSMAGICK) SetImage(canvas, MATTE_OPACITY); #else SetImageBackgroundColor(canvas); SetImageOpacity(canvas, MATTE_OPACITY); #endif xastir_snprintf(map_it, sizeof(map_it), "%s", langcode ("BBARSTA049")); // Reading tiles... statusline(map_it,0); XmUpdateDisplay(text); tile_info = CloneImageInfo((ImageInfo *)NULL); // Read the tile and composite them onto the canvas for (col = tiles.starty, offset_y = 0; col <= tiles.endy; col++, offset_y += 256) { for (row = tiles.startx, offset_x = 0; row <= tiles.endx; row++, offset_x += 256) { xastir_snprintf(tmpString, sizeof(tmpString), "%s/%d/%d/%d.%s", tileRootDir, osm_zl, row, col, tileExt[0] != '\0' ? tileExt : "png"); strncpy(tile_info->filename, tmpString, MaxTextExtent); tile = ReadImage(tile_info,&exception); if (exception.severity != UndefinedException) { //fprintf(stderr,"Exception severity:%d\n", exception.severity); if (exception.severity==FileOpenError) { //fprintf(stderr, "%s NOT available\n", tile_info->filename); #if !defined(HAVE_GRAPHICSMAGICK) ClearMagickException(&exception); #endif } else { xastir_snprintf(tmpString, sizeof(tmpString), "%s/%d/%d/%d.%s", tileRootDir, osm_zl, row, col, tileExt[0] != '\0' ? tileExt : "png"); if (debug_level & 512) { fprintf(stderr, "%s NOT removed.\n", tmpString); } else { fprintf(stderr, "Removing %s\n", tmpString); unlink(tmpString); } CatchException(&exception); } // clear exception so next iteration doesn't fail GetExceptionInfo(&exception); // replace the missing tile with a place holder //(void)strcpy(tile_info->filename, "xc:red"); //tile = ReadImage(tile_info, &exception); } if (tile) { (void)CompositeImage(canvas, OverCompositeOp, tile, offset_x, offset_y); DestroyImage(tile); } } } // Set the matte color for use in transparentency testing canvas->matte_color.red = MATTE_RED; canvas->matte_color.green = MATTE_GREEN; canvas->matte_color.blue = MATTE_BLUE; if (debug_level & 512) { #if defined(HAVE_GRAPHICSMAGICK) DescribeImage(canvas, stderr, 0); #else IdentifyImage(canvas, stderr, 0); #endif WriteImages(canvas_info, canvas, "/tmp/xastirOSMTiledMap.png", &exception); } draw_OSM_image(w, canvas, &exception, &NWcorner, &SEcorner, osm_zl); // Display the OpenStreetMap attribution // Just reuse the tile structure rather than creating another. xastir_snprintf(tmpString, sizeof(tmpString), "%s/CC_OpenStreetMap.png", get_data_base_dir("maps")); strncpy(tile_info->filename, tmpString, MaxTextExtent); tile = ReadImage(tile_info,&exception); if (exception.severity != UndefinedException) { CatchException(&exception); } else { draw_image(w, tile, &exception, 4, 4); DestroyImage(tile); } } else { // map draw was interrupted // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } /* * Release resources */ if (tile_info != NULL) { DestroyImageInfo(tile_info); } if (canvas_info != NULL) { DestroyImageInfo(canvas_info); } if (canvas != NULL) { DestroyImage(canvas); } DestroyExceptionInfo(&exception); return; } // draw_OSM_tiles() /********************************************************** * draw_OSM_map() - retrieve an image that is the size of the display **********************************************************/ void draw_OSM_map (Widget w, char *filenm, int destination_pixmap, char *url, char *style, int UNUSED(nocache) ) // For future implementation of a "refresh cached map" option { char file[MAX_FILENAME]; // Complete path/name of image file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of image file char fileimg[MAX_FILENAME]; // Ascii name of image file, read from GEO file char OSMtmp[MAX_FILENAME*2]; // Used for putting together the OSMmap query tiepoint tp[2]; // Calibration points for map char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; double left, right, top, bottom; double lat_center = 0; double long_center = 0; char map_it[MAX_FILENAME]; char tmpstr[1001]; int osm_zl = 18; // OSM zoom level, at 18, the whole // world fits in one 256x256 tile. unsigned map_image_width; // Image width unsigned map_image_height; // Image height // TODO: put the max_image_* limits in the .geo/.osm file because it could change on a by-server // basis and the server URL can be specified in the .geo/.osm file. unsigned max_image_width = 2000; // This value is for the default server unsigned max_image_height = 2000; // This value is for the default server // initialize this local_filename[0]='\0'; // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... XmUpdateDisplay(text); // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // calculate the OSM zoom level (osm_zl) that is nearest the xastir scale osm_zl = osm_zoom_level(scale_x); // Calculate the image size to request. The size will be saved as tiepoints // for the top-left and bottom-right of the image. tp[0].x_long = xastirLon2pixelLon(NW_corner_longitude, osm_zl); // OSM pixels tp[1].x_long = xastirLon2pixelLon(SE_corner_longitude, osm_zl); // OSM pixels tp[0].y_lat = xastirLat2pixelLat(NW_corner_latitude, osm_zl); // OSM pixels tp[1].y_lat = xastirLat2pixelLat(SE_corner_latitude, osm_zl); // OSM pixels map_image_height = tp[1].y_lat - tp[0].y_lat; map_image_width = tp[1].x_long - tp[0].x_long; // Limit dimensions to the max the server will allow. if (map_image_width > max_image_width) { int tmp = ((map_image_width - map_image_height) / 2) + 1; tp[0].x_long += tmp; tp[1].x_long -= tmp; map_image_width = tp[1].x_long - tp[0].x_long; } if (map_image_height > max_image_height) { int tmp = ((map_image_height - max_image_height) / 2) + 1; tp[0].y_lat += tmp; tp[1].y_lat -= tmp; map_image_height = tp[1].y_lat - tp[0].y_lat; } // Size and coordinates for the tiepoints in pixels tp[0].img_x = 0; tp[0].img_y = 0; tp[1].img_x = map_image_width - 1; tp[1].img_y = map_image_height - 1; // calculate the center coordinates for the image request left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates, degrees top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates, degrees right = (double)((SE_corner_longitude - 64800000l)/360000.0); //Lat/long Coordinates, degrees bottom = (double)(-((SE_corner_latitude - 32400000l)/360000.0));//Lat/long Coordinates, degrees long_center = (left + right)/2.0l; // degrees // The vertical center of the image must be calculated from the OSM image size to // compensate for latitude scaling (Mercator). This is particularly important for small image/screen // sizes and may not be apparent on large displays. lat_center = pixelLat2Lat((map_image_height / 2) + tp[0].y_lat, osm_zl); /* * Query format to the StaticMap * See: http://ojw.dev.openstreetmap.org/StaticMap/?mode=API& * * http://ojw.dev.openstreetmap.org/StaticMap/?lat=LL.LLLLLL&lon=-LLL.LLLLL&z=15& \ * w=WWW&h=HHH&layer=osmarender&mode=Export&att=none&show=1 */ if (url[0] != '\0') { xastir_snprintf(OSMtmp, sizeof(OSMtmp), "%s", url); } else { xastir_snprintf(OSMtmp, sizeof(OSMtmp), "http://ojw.dev.openstreetmap.org/StaticMap/"); } //xastir_snprintf(tmpstr, sizeof(tmpstr), "?mode=Export&att=text&show=1&"); xastir_snprintf(tmpstr, sizeof(tmpstr), "?mode=Export&show=1&"); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); if (style[0] != '\0') { xastir_snprintf(tmpstr, sizeof(tmpstr), "%s", style); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); } else { xastir_snprintf(tmpstr, sizeof(tmpstr), "layer=osmarender&"); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); } xastir_snprintf(tmpstr, sizeof(tmpstr), "&lat=%f\046lon=%f\046", lat_center, long_center); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "w=%i\046h=%i\046", map_image_width, map_image_height); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "z=%d", osm_zl); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); memcpy(fileimg, OSMtmp, sizeof(fileimg)); fileimg[sizeof(fileimg)-1] = '\0'; // Terminate string if (debug_level & 512) { fprintf(stderr,"left side is %f\n", left); fprintf(stderr,"right side is %f\n", right); fprintf(stderr,"top is %f\n", top); fprintf(stderr,"bottom is %f\n", bottom); fprintf(stderr,"lat center is %f\n", lat_center); fprintf(stderr,"long center is %f\n", long_center); fprintf(stderr,"screen width is %li\n", screen_width); fprintf(stderr,"screen height is %li\n", screen_height); fprintf(stderr,"OSM image width is %i\n", map_image_width); fprintf(stderr,"OSM image height is %i\n", map_image_height); fprintf(stderr,"scale_y = %li\n", scale_y); fprintf(stderr,"scale_x = %li\n", scale_x); fprintf(stderr,"OSM zoom level = %i\n", osm_zl); fprintf(stderr,"fileimg is %s\n", fileimg); fprintf(stderr,"ftp or http file: %s\n", fileimg); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } get_OSM_local_file(local_filename,fileimg); // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 512) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { if (debug_level & 512) { fprintf(stderr,"File could not be read\n"); } #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete unreadable map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } else if ( (image->columns != map_image_width) || (image->rows != map_image_height)) { fprintf(stderr, "Server returned an image size different than requested!\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 512) { fprintf(stderr,"Image: %s\n", file); fprintf(stderr,"Image size %d %d\n", map_image_width, map_image_height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"image matte is %i\n", image->matte); } // debug_level & 512 draw_OSM_image(w, image, &exception, &(tp[0]), &(tp[1]), osm_zl); DestroyImage(image); // Display the OpenStreetMap attribution xastir_snprintf(OSMtmp, sizeof(OSMtmp), "%s/CC_OpenStreetMap.png", get_data_base_dir("maps")); strncpy(image_info->filename, OSMtmp, MaxTextExtent); image = ReadImage(image_info,&exception); if (exception.severity != UndefinedException) { CatchException(&exception); } else { draw_image(w, image, &exception, 4, 4); } // Clean up if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); } // end draw_OSM_map() #endif //HAVE_MAGICK ///////////////////////////////////////////// End of OpenStreetMap code /////////////////////////////////////// Xastir-Release-2.2.2/src/map_OSM.h000066400000000000000000000036141501463444000166050ustar00rootroot00000000000000/* * * Copyright (C) 2000-2023 The Xastir Group * * This file was contributed by Jerry Dunmire, KA6HLD. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef OSM_H #define OSM_H #include // for KeySym #define MAX_OSMSTYLE 1000 // max characters in the a OSM style argument #define MAX_OSM_URL 1000 // max characters for a OSM URL #define MAX_OSMEXT 10 // max characters for a tilename extension void adj_to_OSM_level( long *new_scale_x, long *new_scale_y); void draw_OSM_map(Widget w, char *filenm, int destination_pixmap, char *url, char *style, int nocache); void draw_OSM_tiles(Widget w, char *filenm, int destination_pixmap, char *server_url, char *tileCacheDir, char *mapName, char *tileExt); unsigned int osm_zoom_level(long scale_x); void init_OSM_values(void); int OSM_optimize_key(KeySym key); void set_OSM_optimize_key(KeySym key); int OSM_report_scale_key(KeySym key); void set_OSM_report_scale_key(KeySym key); #endif //OSM_H Xastir-Release-2.2.2/src/map_WMS.c000066400000000000000000001030731501463444000166100ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #include "map_cache.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" /********************************************************** * draw_WMS_map() **********************************************************/ #ifdef HAVE_MAGICK void draw_WMS_map (Widget w, char *filenm, int destination_pixmap, char *URL, transparent_color_record *c_trans_color_head, int nocache) // If non-zero, don't use cached version { char file[MAX_FILENAME]; // Complete path/name of image file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of image file char fileimg[MAX_FILENAME]; // Ascii name of image file, read from GEO file char WMStmp[MAX_FILENAME*2]; // Used for putting together the WMS map query int width, height; tiepoint tp[2]; // Calibration points for map, read in from .geo file long map_c_T, map_c_L; // map delta NW edge coordinates, DNN: these should be signed long tp_c_dx, tp_c_dy; // tiepoint coordinate differences unsigned long c_x_min, c_y_min;// top left coordinates of map inside screen // unsigned long c_y_max; // bottom right coordinates of map inside screen double c_x; // Xastir coordinates 1/100 sec, 0 = 180W double c_y; // Xastir coordinates 1/100 sec, 0 = 90N long map_y_0; // map pixel pointer prior to TM adjustment long map_x, map_y; // map pixel pointers, DNN: this was a float, chg to long long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; // // long map_x_ctr; // half map width in pixel // long map_y_ctr; // half map height in pixel int map_seen = 0; int map_act; // int map_done; // long map_c_yc; // map center, vert coordinate // long map_c_xc; // map center, hor coordinate double map_c_dx, map_c_dy; // map coordinates increment (pixel width) double c_dx; // adjusted map pixel width long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions // long scr_x_mc; // map center in screen units // long scr_c_xr; // long scale_xa; // adjusted for topo maps // double scale_x_nm; // nm per Xastir coordinate unit // long scale_x0; // at widest map area char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; int l; XColor my_colors[256]; int trans_skip = 0; // skip transparent pixel double left, right, top, bottom, map_width, map_height; double lat_center = 0; double long_center = 0; char map_it[MAX_FILENAME]; char tmpstr[100]; int geo_image_width; // Image width from GEO file int geo_image_height; // Image height from GEO file time_t query_start_time, query_end_time; #ifdef USE_MAP_CACHE int map_cache_return; char * cache_file_id; #endif // USE_MAP_CACHE char temp_file_path[MAX_VALUE]; if (debug_level & 512) { if (nocache) { fprintf(stderr,"draw_WMS_map: NOCACHE selected\n"); } else { fprintf(stderr,"draw_WMS_map: CACHING if enabled\n"); } } // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // Tiepoint for upper left screen corner // tp[0].img_x = 0; // Pixel Coordinates tp[0].img_y = 0; // Pixel Coordinates tp[0].x_long = NW_corner_longitude; // Xastir Coordinates tp[0].y_lat = NW_corner_latitude; // Xastir Coordinates // Tiepoint for lower right screen corner // // Here we must use scale_x for both directions because we have // square pixels returned by the WMS server. // Really what we want to do here is to change our bounding box for // our request to fit square pixels, using scale_x for both // dimensions, and to change our tiepoints to match. WMS servers // currently feed us back square pixels but the spec says that the // servers should be capable of sending back rectangular pixels, so // the images we get back may change if we don't request square // pixels each time. // // TODO: Change our imagesize, bounding rectangle requested, and // tiepoints to fit square pixels and to use scale_x for both // dimensions. // // Actually, looking at the changes that were made, it looks like we // _are_ using square pixels and requesting a bounding box based on // scale_x for both dimensions, so we might be good to go as-is. // tp[1].img_x = screen_width - 1; // Pixel Coordinates tp[1].img_y = screen_height - 1; // Pixel Coordinates tp[1].x_long = SE_corner_longitude; // Xastir Coordinates // Modified to use same scale (scale_x) for both dimensions, square // pixels. Don't use SE_corner_latitude here as it uses scale_y! // tp[1].y_lat = NW_corner_latitude + ((screen_height) * scale_y); // Xastir Coordinates tp[1].y_lat = NW_corner_latitude + ((screen_height) * scale_x); // Xastir Coordinates // Again, use scale_x for both directions due to the square // pixels returned from the WMS server. // left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates right = (double)((SE_corner_longitude - 64800000l)/360000.0);//Lat/long Coordinates // Modified to use same scale (scale_x) for both dimensions, square // pixels. Don't use SE_corner_latitude here as it uses scale_y! // bottom = (double)(-(((NW_corner_latitude + ((screen_height) * scale_y) ) - 32400000l)/360000.0));//Lat/long Coordinates bottom = (double)(-(((NW_corner_latitude + ((screen_height) * scale_x) ) - 32400000l)/360000.0));//Lat/long Coordinates map_width = right - left; // Lat/long Coordinates map_height = top - bottom; // Lat/long Coordinates geo_image_width = screen_width; geo_image_height = screen_height; long_center = (left + right)/2.0l; lat_center = (top + bottom)/2.0l; // Example query for a WMS map server.... // xastir_snprintf(fileimg, sizeof(fileimg), // "\'http://mesonet.tamu.edu/cgi-bin/p-warn?SERVICE=WMS&VERSION=1.1.1&REQUEST=getmap&layers=radar&BBOX=-129.000,52.500,-111.000,42.500&HEIGHT=1000&WIDTH=1800&FORMAT=image/png\'"); // xastir_snprintf(WMStmp, sizeof(WMStmp), // "http://mesonet.tamu.edu/cgi-bin/p-warn?SERVICE=WMS&VERSION=1.1.1&REQUEST=getmap"); xastir_snprintf(WMStmp, sizeof(WMStmp), "%s", URL); strncat(WMStmp, "&REQUEST=getmap", sizeof(WMStmp) - 1 - strlen(WMStmp)); strncat(WMStmp, "&EXCEPTIONS=INIMAGE", sizeof(WMStmp) - 1 - strlen(WMStmp)); // This specifies a bounding box based on square pixels. xastir_snprintf(tmpstr, sizeof(tmpstr), "&BBOX=%8.5f,%7.5f,%8.5f,%7.5f", left, // Lower left bottom, // Lower left right, // Upper right top); // Upper right strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "&HEIGHT=%d", geo_image_height); strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "&WIDTH=%d", geo_image_width); strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); // These should be specified in the .geo file instead of hard-coded: // // strncat(WMStmp, "&VERSION=1.0.0", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&FORMAT=image/png", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&TRANSPARENT=TRUE", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&BGCOLOR=0xffffff", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&BGCOLOR=0x000000", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&CRS=CRS:84", sizeof(WMStmp) - 1 - strlen(WMStmp)); memcpy(fileimg, WMStmp, sizeof(fileimg)); fileimg[sizeof(fileimg)-1] = '\0'; // Terminate string if (debug_level & 512) { fprintf(stderr,"left side is %f\n", left); fprintf(stderr,"right side is %f\n", right); fprintf(stderr,"top is %f\n", top); fprintf(stderr,"bottom is %f\n", bottom); fprintf(stderr,"lat center is %f\n", lat_center); fprintf(stderr,"long center is %f\n", long_center); fprintf(stderr,"screen width is %li\n", screen_width); fprintf(stderr,"screen height is %li\n", screen_height); fprintf(stderr,"map width is %f\n", map_width); fprintf(stderr,"map height is %f\n", map_height); fprintf(stderr,"fileimg is %s\n", fileimg); fprintf(stderr,"ftp or http file: %s\n", fileimg); } if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (nocache || map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } // Simulate a cache miss map_cache_return = 1; } else { // Else look for the file in the cache map_cache_return = map_cache_get(fileimg,local_filename); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: %d\n", map_cache_return); } // Don't use cached version if "nocache" is non-zero // if (nocache || map_cache_return != 0 ) { // Caching has not been requested or cached file not found. // We must snag the remote file via libcurl or wget. if (nocache) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); } else { cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, sizeof(local_filename), "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, "png"); free(cache_file_id); } #else // USE_MAP_CACHE xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same name. // This avoids the problem of having an old map image here and // the code trying to display it when the download fails. unlink( local_filename ); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // For debugging the MagickError/MagickWarning segfaults. //system("cat /dev/null >/var/tmp/xastir_hacker_map.png"); #ifdef USE_MAP_CACHE // Cache this map only if nocache is zero if (!nocache) { map_cache_put(fileimg,local_filename); } } // end if is cached DHBROWN #endif // USE_MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 512) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { if (debug_level & 512) { fprintf(stderr,"File could not be read\n"); } #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 512) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } /* if (image->colorspace != RGBColorspace) { fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); if (image) DestroyImage(image); if (image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); return; } */ width = image->columns; height = image->rows; // Code to mute the image so it's not as bright. /* if (raster_map_intensity < 1.0) { char tempstr[30]; if (debug_level & 512) fprintf(stderr,"level=%s\n", tempstr); xastir_snprintf(tempstr, sizeof(tempstr), "%d, 100, 100", (int)(raster_map_intensity * 100.0)); ModulateImage(image, tempstr); } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, &exception) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, &exception); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as ImageMagick can read in all sorts // of image files temp_pack = image->colormap[l]; if (debug_level & 512) fprintf(stderr,"Colormap color is %i %i %i \n", (int)temp_pack.red, (int)temp_pack.green, (int)temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as Quantum's. Quantum // is defined in /usr/include/magick/image.h as either an unsigned short or an // unsigned char, depending on what "configure" decided when ImageMagick was installed. // We can determine which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (debug_level & 512) fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our map will soon be (after translating the * tiepoints to the corners if they're not already there): * * left edge of map = tp[0].x_long in Xastir format * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ map_c_L = tp[0].x_long - NW_corner_longitude; // map left coordinate map_c_T = tp[0].y_lat - NW_corner_latitude; // map top coordinate tp_c_dx = (long)(tp[1].x_long - tp[0].x_long);// Width between tiepoints tp_c_dy = (long)(tp[1].y_lat - tp[0].y_lat); // Height between tiepoints // Check for tiepoints being in wrong relation to one another if (tp_c_dx < 0) { tp_c_dx = -tp_c_dx; // New width between tiepoints } if (tp_c_dy < 0) { tp_c_dy = -tp_c_dy; // New height between tiepoints } // Calculate step size per pixel map_c_dx = ((double) tp_c_dx / abs(tp[1].img_x - tp[0].img_x)); map_c_dy = ((double) tp_c_dy / abs(tp[1].img_y - tp[0].img_y)); // Scaled screen step size for use with XFillRectangle below scr_dx = (int) (map_c_dx / scale_x) + 1; scr_dy = (int) (map_c_dy / scale_y) + 1; // calculate top left map corner from tiepoints if (tp[0].img_x != 0) { tp[0].x_long -= (tp[0].img_x * map_c_dx); // map left edge longitude map_c_L = tp[0].x_long - NW_corner_longitude; // delta ?? tp[0].img_x = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 x: %d\t%lu\n", tp[0].img_x, tp[0].x_long); } } if (tp[0].img_y != 0) { tp[0].y_lat -= (tp[0].img_y * map_c_dy); // map top edge latitude map_c_T = tp[0].y_lat - NW_corner_latitude; tp[0].img_y = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 y: %d\t%lu\n", tp[0].img_y, tp[0].y_lat); } } // calculate bottom right map corner from tiepoints // map size is geo_image_width / geo_image_height if (tp[1].img_x != (geo_image_width - 1) ) { tp[1].img_x = geo_image_width - 1; tp[1].x_long = tp[0].x_long + (tp[1].img_x * map_c_dx); // right if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 x: %d\t%lu\n", tp[1].img_x, tp[1].x_long); } } if (tp[1].img_y != (geo_image_height - 1) ) { tp[1].img_y = geo_image_height - 1; tp[1].y_lat = tp[0].y_lat + (tp[1].img_y * map_c_dy); // bottom if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 y: %d\t%lu\n", tp[1].img_y, tp[1].y_lat); } } if (debug_level & 512) { fprintf(stderr,"X tiepoint width: %ld\n", tp_c_dx); fprintf(stderr,"Y tiepoint width: %ld\n", tp_c_dy); fprintf(stderr,"Loading imagemap: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"Image size %d %d\n", width, height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"image matte is %i\n", image->matte); } // debug_level & 512 // draw the image from the file out to the map screen // Get the border values for the X and Y for loops used // for the XFillRectangle call later. // map_c_yc = (tp[0].y_lat + tp[1].y_lat) / 2; // vert center of map as reference // map_y_ctr = (long)(height / 2 +0.499); // scale_x0 = get_x_scale(0,map_c_yc,scale_y); // reference scaling at vert map center // map_c_xc = (tp[0].x_long + tp[1].x_long) / 2; // hor center of map as reference // map_x_ctr = (long)(width / 2 +0.499); // scr_x_mc = (map_c_xc - NW_corner_longitude) / scale_x; // screen coordinates of map center // calculate map pixel range in y direction that falls into screen area // c_y_max = 0ul; map_y_min = map_y_max = 0l; for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_y_0; // update last map pixel in y // c_y_max = (unsigned long)c_y;// bottom map inside screen coordinate } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_y_0; // update first map pixel in y } } c_y_min = (unsigned long)(tp[0].y_lat + map_y_min * map_c_dy); // top map inside screen coordinate map_x_min = map_x_max = 0l; for (map_x = 0, c_x = tp[0].x_long; map_x < (long)width; map_x++, c_x += map_c_dx) { scr_x = (c_x - NW_corner_longitude)/ scale_x; // current screen position if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_x; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_x; // update first map pixel in x } } c_x_min = (unsigned long)(tp[0].x_long + map_x_min * map_c_dx); // left map inside screen coordinate scr_yp = -1; // scr_c_xr = SE_corner_longitude; c_dx = map_c_dx; // map pixel width // scale_xa = scale_x0; // the compiler likes it ;-) // map_done = 0; map_act = 0; map_seen = 0; scr_y = screen_height - 1; // loop over map pixel rows for (map_y_0 = map_y_min, c_y = (double)c_y_min; (map_y_0 <= map_y_max); map_y_0++, c_y += map_c_dy) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = (c_y - NW_corner_latitude) / scale_y; if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y scr_xp = -1; // loop over map pixel columns map_act = 0; // scale_x_nm = calc_dscale_x(0,(long)c_y) / 1852.0; // nm per Xastir coordinate for (map_x = map_x_min, c_x = (double)c_x_min; map_x <= map_x_max; map_x++, c_x += c_dx) { scr_x = (c_x - NW_corner_longitude) / scale_x; if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x map_y = map_y_0; if (map_y >= 0 && map_y <= tp[1].img_y) // check map boundaries in y direction { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // now copy a pixel from the map image to the screen l = map_x + map_y * image->columns; trans_skip = 1; // possibly transparent if (image->storage_class == PseudoClass) { if ( c_trans_color_head && check_trans(my_colors[(int)index_pack[l]],c_trans_color_head)) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); trans_skip = 0; // draw it } } else { // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); if ( c_trans_color_head && check_trans(my_colors[0],c_trans_color_head)) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); trans_skip = 0; // draw it } } // Skip drawing if a transparent pixel if (!trans_skip) { (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } } // check map boundaries in y direction } } // loop over map pixel columns if (map_seen && !map_act) { // map_done = 1; } } } // loop over map pixel rows if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); } #endif //HAVE_MAGICK Xastir-Release-2.2.2/src/map_cache.c000066400000000000000000000655711501463444000172170ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ /* * The code in this file is used to cache maps downloaded * from tiger.census.gov, and to manage that cache. It was written * to use Berkeley DB version 4 or better. * * Dan Brown N8YSZ. * */ // Need this one before the #ifdef in order to get the definition of // USE_MAP_CACHE, if defined. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef USE_MAP_CACHE //#warning USE_MAP_CACHE Defined #include #include #include #include #include #include #include #include "snprintf.h" #include "xastir.h" #include "xa_config.h" #include "main.h" #include "maps.h" #include "map_cache.h" #include // Must be last include file #include "leak_detection.h" // This is used to temporarily disable fetching from the map cache. // Used for refreshing corrupted maps in the cache. int map_cache_fetch_disable = 0; // Used to disable map caching entirely if the header and dblib // versions don't match, in order to avoid segfaults when the map // caching is used. int map_cache_disabled = 0; // Here we do a run-time check to verify that the header file we // used to compile with is the same version as the shared library // we're currently linked with. To do otherwise often results in // segfaults. // void map_cache_init(void) { int warn_now = 0; if (strcmp( DB_VERSION_STRING, db_version(NULL,NULL,NULL) ) != 0) { fprintf(stderr, "\n\n***** WARNING *****\n"); fprintf(stderr, "Berkeley DB header files/shared library file do NOT match!\n"); fprintf(stderr, "Disabling use of the map cache.\n"); // Can't bring up a popup here 'cuz we don't have any GUI running // yet by this point. // popup_message_always(langcode("POPEM00034"),langcode("POPEM00046")); warn_now++; map_cache_disabled++; } if (debug_level & 5 || warn_now) { //fprintf(stderr, // "Berkeley DB Library Header File Version %d.%d.%d\n", // DB_VERSION_MAJOR, // DB_VERSION_MINOR, // DB_VERSION_PATCH); fprintf(stderr, " Header file: %s\n", DB_VERSION_STRING); fprintf(stderr, "Library file: %s\n", db_version(NULL,NULL,NULL) ); } if (warn_now) { fprintf(stderr, "***** WARNING *****\n"); } } // map_cache_put() // // Inputs: // // Outputs: // int map_cache_put( char * map_cache_url, char * map_cache_file ) { // Puts an entry into the url->filename database // Tracks space used in "CACHE_SPACE_USED" char mc_database_filename[MAX_FILENAME]; int mc_ret, mc_t_ret, mc_file_stat, mc_space_used ; DBT mc_key, mc_data ; DB *dbp; struct stat file_status; char mc_buf[128]; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } mc_space_used=0; xastir_snprintf(mc_database_filename, sizeof(mc_database_filename), "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); // check for reasonable filename // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // 1234567890123456789012345678901234567 mc_ret=strlen(map_cache_file); if ( mc_ret < 37 ) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_put: Unusable filename: %s. Skipping encaching\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } return (-1 * mc_ret); } // stat the file to see if we even need to bother if ((mc_file_stat=stat(map_cache_file, &file_status)) !=0) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_put: File Error: %s. Skipping encaching\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } return (mc_file_stat); } if ( debug_level & 512) { fprintf (stderr, "map_cache_put: file_status.st_size %d\n", (int) file_status.st_size); } // Create handle to db if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_put db_create:%s\n", db_strerror(mc_ret)); return(1); } // open the db #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); db_strerror(mc_ret); } #else if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); db_strerror(mc_ret); } #endif /** DB_VERSION Check **/ // Before we put something in we need to see if we got space // if mc_cache_size_limit // Setup for get memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data = "CACHE_SPACE_USED"; mc_key.size = sizeof("CACHE_SPACE_USED"); // check "CACHE_SPACE_USED" record in db // mc_ret is assigned here but not used. Commented it out for now. if (((/* mc_ret = */ dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) == 0) && ( mc_data.data != NULL ) ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } if (mc_data.data == NULL) { mc_space_used = 0; } else { mc_space_used = atoi( (char *)mc_data.data); } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: CACHE_SPACE_USED = %.2f mb\n", (mc_space_used/1024/1024.0)); } } else { if (mc_data.data == NULL) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: CACHE_SPACE_USED get returned null \n"); } } else { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: Unable to check CACHE_SPACE_USED: %s\n", db_strerror(mc_ret)); } } // for now let us assume this is the first map entry and we // just flag an error. Better procedure for later might be to // return(mc_ret) indicating a database error of some sort } // xastir_snprintf(map_cache_file, MAX_FILENAME, "%s",(char *)mc_data.data); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_space_used before = %d bytes file_status.st_size %d\n", mc_space_used, (int) file_status.st_size); } mc_space_used += (int) file_status.st_size; if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_space_used after = %d bytes \n", mc_space_used); } if ( mc_space_used > MAP_CACHE_SPACE_LIMIT) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: Warning cache space used: %.2f mb NOW OVER LIMIT: %.2f mb\n", (mc_space_used/1024/1024.0), (MAP_CACHE_SPACE_LIMIT/1024/1024.0)); } // Cache Cleanup // The warning is nice, but we should do something here // Needs LRU and or FIFO db structures } else { // else put cache_space_used // setup memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); // data mc_key.data = "CACHE_SPACE_USED"; mc_key.size = sizeof("CACHE_SPACE_USED"); xastir_snprintf(mc_buf, sizeof(mc_buf), "%d", mc_space_used); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_buf: %s len %d\n", mc_buf,(int) sizeof(mc_buf)); } mc_data.data = mc_buf ; mc_data.size = sizeof(mc_buf); // put if ((mc_ret = dbp->put(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key stored.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put"); } // db_strerror(mc_ret); return(mc_ret); } } // Setup for put of data memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); // Real data at last mc_key.data = map_cache_url; mc_key.size = strlen(map_cache_url); mc_data.data = map_cache_file; mc_data.size = strlen(map_cache_file)+1; /* +1 includes \0 */ // do the actual put if ((mc_ret = dbp->put(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key stored.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put") ; } // db_strerror(mc_ret); return(mc_ret); } // Map now cached statusline(langcode("CACHE001"), 1); // close the db // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; db_strerror(mc_ret); } } /* end map_cache_put */ return (0) ; } // map_cache_get() // // Queries URL->Filename db // Calls map_cache_del to cleanup expired maps // // Inputs: // // Outputs: 0 if cached file is retrieved successfully // 1 if db can't be created // negative number if unusable filename or bad filestat // positive number if map has expired // return value from dbp->get if record not found // int map_cache_get( char * map_cache_url, char * map_cache_file ) { DBT mc_key, mc_data ; DB *dbp; int mc_ret, mc_t_ret, mc_file_stat ; char mc_database_filename[MAX_FILENAME]; struct stat file_status; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } set_dangerous("map_cache_get: xastir_snprintf 1"); xastir_snprintf(mc_database_filename, sizeof(mc_database_filename), // change to max_filename? "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); clear_dangerous(); set_dangerous("map_cache_get: db_create"); if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_get db_create:%s\n", db_strerror(mc_ret)); return(1); } clear_dangerous(); #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) set_dangerous("map_cache_get:dbp->open 1"); if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { ( debug_level & 512 ) ? dbp->err(dbp, mc_ret, "%s", mc_database_filename):0; // db_strerror(mc_ret); } clear_dangerous(); #else set_dangerous("map_cache_get:dbp->open 2"); if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { if (debug_level & 512) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); // db_strerror(mc_ret); } } clear_dangerous(); #endif /** DB_VERSION Check **/ memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data=map_cache_url ; mc_key.size=strlen(map_cache_url); statusline("Checking Map Cache",1); if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Checking Map Cache\n"); } set_dangerous("map_cache_get:dbp->get"); if ((mc_ret = dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } set_dangerous("map_cache_get: xastir_snprintf 2"); xastir_snprintf(map_cache_file, MAX_FILENAME, "%s",(char *)mc_data.data); clear_dangerous(); // check for reasonable filename // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // 1234567890123456789012345678901234567 mc_ret=strlen(map_cache_file); if ( mc_ret < 37 ) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Unusable filename: %s. Deleting key %s from cache\n", (map_cache_file == NULL) ? "(null)" : map_cache_file, (map_cache_url == NULL) ? "(null)" : map_cache_url); } set_dangerous("map_cache_get: map_cache_del 1"); map_cache_del(map_cache_url); if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (-1 * mc_ret); } // check age of file - based on name - delete if too old if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Checking age\n"); } set_dangerous("map_cache_get: map_cache_expired"); if ( (mc_ret=map_cache_expired(map_cache_file, (MC_MAX_FILE_AGE)))) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: deleting expired key: %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } set_dangerous("map_cache_get: map_cache_del 2"); map_cache_del(map_cache_url); if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (mc_ret); } clear_dangerous(); // check if the file exists if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: checking for existence of map_cache_file: %s.\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } mc_file_stat=stat(map_cache_file, &file_status); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: map_cache_file %s stat returned:%d.\n", (map_cache_file == NULL) ? "(null)" : map_cache_file, mc_file_stat); } if ( mc_file_stat == -1 ) { // if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: attempting to delete map_cache_file %s \n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } set_dangerous("map_cache_get: dbp->del"); if ((mc_ret = dbp->del(dbp, NULL, &mc_key, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: File stat failed %s: key was deleted.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); } clear_dangerous(); set_dangerous("map_cache_get: dbp->close 1"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); // db_strerror(mc_ret); // Return the file stat if there was a file problem return (mc_file_stat); } else { set_dangerous("map_cache_get: dbp->close 2"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); // If we made it here all is good // Loading Cached Map statusline(langcode("CACHE002"), 1); return (0); } } else { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: Get failed. Key was: %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } if (debug_level & 512) { dbp->err(dbp, mc_ret, "DB->get"); // db_strerror(mc_ret); } // there was some problem getting things from the db // return the return from the get // Map not found in cache... statusline(langcode("CACHE003"), 1); set_dangerous("map_cache_get: dbp->close 3"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (mc_ret); } clear_dangerous(); /** end map_cache_get **/ } // map_cache_del() // // Delete entry from the cache and unlink associated file from disk // // Inputs: Map URL // // Outputs: 0 if successful deleting the item from the cache // 1 if error in creating/opening DB file // mc_ret if unlink failed or if error in DB->del // int map_cache_del( char * map_cache_url ) { DBT mc_key, mc_data, mc_size_key, mc_size_data ; DB *dbp; int mc_ret, mc_t_ret, mc_file_stat, mc_space_used; char mc_database_filename[MAX_FILENAME]; char mc_delete_file[MAX_FILENAME]; struct stat file_status; char mc_buf[128]; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } mc_space_used = 0 ; xastir_snprintf(mc_database_filename, MAX_FILENAME, "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_del db_create:%s\n", db_strerror(mc_ret)); return(1); } #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { ( debug_level & 512 ) ? dbp->err(dbp, mc_ret, "%s", mc_database_filename):0; // db_strerror(mc_ret); return(1); } #else if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { if (debug_level & 512) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); // db_strerror(mc_ret); } return(1); } #endif /** DB_VERSION Check **/ memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data=map_cache_url ; mc_key.size=strlen(map_cache_url); // Try to get the key from the cache if ((mc_ret = dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) != 0) { // Couldn't get the key from the cache if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); // Only try the close if we have a valid handle if (dbp != NULL) { set_dangerous("map_cache_del: dbp->close 1"); dbp->close(dbp, 0); clear_dangerous(); } return (mc_ret); } if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } // stat the file xastir_snprintf(mc_delete_file, MAX_FILENAME, "%s", (char *) mc_data.data); set_dangerous("map_cache_del: stat"); mc_file_stat = stat(mc_delete_file, &file_status); clear_dangerous(); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: file %s stat returned:%d.\n", (mc_data.data == NULL) ? "(null)" : (char *) mc_data.data, mc_file_stat); } if (mc_file_stat != 0 ) { // file stat was not good - do something here // RETURN() HERE? } // Setup for get CACHE_SPACE_USED memset(&mc_size_key, 0, sizeof(mc_size_key)); memset(&mc_size_data, 0, sizeof(mc_size_data)); mc_size_key.data = "CACHE_SPACE_USED"; mc_size_key.size = sizeof("CACHE_SPACE_USED"); // check "CACHE_SPACE_USED" record in db if (((mc_ret = dbp->get(dbp, NULL, &mc_size_key, &mc_size_data, 0)) == 0) && ( mc_size_data.data != NULL ) && ( strlen(mc_size_data.data) != 0 ) ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key retrieved: data was %s.\n", (mc_size_key.data == NULL) ? "(null)" : (char *)mc_size_key.data, (mc_size_data.data == NULL) ? "(null)" : (char *)mc_size_data.data); } set_dangerous("map_cache_del: atoi"); if (mc_size_data.data == NULL) { mc_space_used = 0; } else { mc_space_used = atoi( (char *)mc_size_data.data); } clear_dangerous(); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: CACHE_SPACE_USED = %.2f mb\n", (mc_space_used/1024/1024.0)); } } else { // Failed the "dpb->get" operation if (mc_size_data.data == NULL) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: CACHE_SPACE_USED get returned null \n"); } } else { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: Unable to check CACHE_SPACE_USED: %s\n", db_strerror(mc_ret)); } } // RETURN() HERE? } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: mc_space_used before = %d bytes file_status.st_size %d\n", mc_space_used, (int) file_status.st_size); } mc_ret = unlink( mc_delete_file ); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: file %s unlink returned:%d.\n", mc_delete_file, mc_ret); } if (mc_ret != 0 ) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: unlink failed mc_space_used = %d bytes \n", mc_space_used); } return(mc_ret); } // Update cache_space_used // setup mc_space_used -= (int) file_status.st_size; if (mc_space_used < 0) { mc_space_used = 0; } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: unlink succeeded mc_space_used = %d bytes \n", mc_space_used); } memset(&mc_size_key, 0, sizeof(mc_size_key)); memset(&mc_size_data, 0, sizeof(mc_size_data)); // data mc_size_key.data = "CACHE_SPACE_USED"; mc_size_key.size = sizeof("CACHE_SPACE_USED"); xastir_snprintf(mc_buf, sizeof(mc_buf), "%d", mc_space_used); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: mc_buf: %s len %d\n", mc_buf, (int)sizeof(mc_buf)); } mc_size_data.data = mc_buf ; mc_size_data.size = sizeof(mc_buf); // put if ((mc_ret = dbp->put(dbp, NULL, &mc_size_key, &mc_size_data, 0)) != 0) { // Failed the "dbp->put" operation if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put"); } // db_strerror(mc_ret); // RETURN() HERE? } if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: %s: key stored.\n", (mc_size_key.data == NULL) ? "(null)" : (char *)mc_size_key.data); } // remove entry from cache url->filename database if ((mc_ret = dbp->del(dbp, NULL, &mc_key, 0)) != 0) { // Failed the "dbp->del" operation if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); // RETURN() HERE? } if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key was deleted.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } // close the db. // Only try the close if we have a valid handle if (dbp != NULL) { set_dangerous("map_cache_del: dbp->close 2"); if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { clear_dangerous(); mc_ret = mc_t_ret; // db_strerror(mc_ret); // RETURN() HERE? } } return (0); // All is well /** end map_cache_del **/ } char * map_cache_fileid(void) { // returns a unique identifier // used for generating filenames for cached files time_t t; char * mc_time_buf; mc_time_buf = malloc (16); sprintf( mc_time_buf, "%d",(int) time(&t)); return (mc_time_buf); } // check for files old enough to expire // this is lame but it should work for now. // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // // writing this proved a good example of why pointer arithmetic is tricky // and a good example of why I should avoid it - n8ysz 20041110 // int map_cache_expired( char * mc_filename, time_t mc_max_age ) { time_t mc_t,mc_file_age; char *mc_filename_tmp, *mc_time_buf_tmp, *mc_time_buf; if (map_cache_disabled) { return(0); } mc_time_buf=malloc(MAX_FILENAME); mc_time_buf_tmp=mc_time_buf; // grab filename mc_filename_tmp=strrchr(mc_filename,'/'); // clean up map_ mc_filename_tmp=strchr(mc_filename_tmp,'_'); ++mc_filename_tmp; // save up to .gif while ((*mc_time_buf_tmp++ = *mc_filename_tmp++) != '.' ) ; *(--mc_time_buf_tmp) ='\0'; // if ( debug_level & 512 ) { // fprintf(stderr, "map_cache_expired: mc_filename is: %s mc_time_buf is: %s.\n", mc_filename, mc_time_buf); // } mc_file_age=(time(&mc_t) - ((time_t) atoi(mc_time_buf)) ); if ( mc_file_age < mc_max_age ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_expired: mc_filename %s is NOT expired. mc_time_buf is: %s.\n", (mc_filename == NULL) ? "(null)" : mc_filename, (mc_time_buf == NULL) ? "(null)" : mc_time_buf); } free(mc_time_buf); return (0); } else { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_expired: mc_filename %s IS expired. mc_time_buf is: %s.\n", (mc_filename == NULL) ? "(null)" : mc_filename, (mc_time_buf == NULL) ? "(null)" : mc_time_buf); } free(mc_time_buf); return ((int)mc_file_age); } // sprintf( mc_time_buf, "%d",(int) return (0); } // Functions that need writing int mc_check_space_used (void) { if (map_cache_disabled) { return(0); } return(0); } int mc_update_space_used (void) { if (map_cache_disabled) { return(0); } return(0); } #endif // USE_MAP_CACHE Xastir-Release-2.2.2/src/map_cache.h000066400000000000000000000043311501463444000172070ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_MAP_CACHE_H #define XASTIR_MAP_CACHE_H // Global variable declarations extern int map_cache_fetch_disable; // External function declarations extern void map_cache_init(void); // Saves file and puts entries into cache db extern int map_cache_put( char * map_cache_url, char * map_cache_file ); // Retrieves entry from cache db - checks existence of file extern int map_cache_get( char * map_cache_url, char * map_cache_file ); // Deletes cached map file and the entry from cache extern int map_cache_del( char * map_cache_url ); // Checks to see if map is expired based on date embedded in filename extern int map_cache_expired( char * mc_filename, time_t mc_max_age ); // Generates filename based on current time extern char * map_cache_fileid(void); // Static variable definitions // These should probably be runtime options // Cache expiration times // about 6mo #define MC_MAX_FILE_AGE 6*30*24*60*60 // 1 hr //#define MC_MAX_FILE_AGE 60*60 // 5 seconds -- don't do this except for testing //#define MC_MAX_FILE_AGE 5 // Cache Space Limit in bytes // 1 megabytes == about ten 1024x768 map gifs n8ysz // MAP_CACHE_SPACE_LIMIT=1024*1024 // 16 megabytes // MAP_CACHE_SPACE_LIMIT=16*1024*1024 // 128 megabytes #define MAP_CACHE_SPACE_LIMIT 128*1024*1024 #endif /* XASTIR_MAP_CACHE_H */ Xastir-Release-2.2.2/src/map_dos.c000066400000000000000000001431341501463444000167310ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #define DOS_HDR_LINES 8 #define GRID_MORE 5000 extern int npoints; /* tsk tsk tsk -- globals */ extern int mag; /* MAP pointers */ //static map_vectors *map_vectors_ptr; //static text_label *map_text_label_ptr; //static symbol_label *map_symbol_label_ptr; /* MAP counters */ //static long vectors_num; //static long text_label_num; //static long object_label_num; /********************************************************** * map_plot() * * Plots vectors on the map. If "color" is non-zero, * then it draws filled polygons in the color of * "object_behavior"? Weird. **********************************************************/ void map_plot (Widget w, long max_x, long max_y, long x_long_cord, long y_lat_cord, unsigned char color, long object_behavior, int destination_pixmap, int draw_filled) { static int redraw_check; static XPoint points[MAX_MAP_POINTS]; static unsigned char last_color = (unsigned char)0; static unsigned char last_behavior = (unsigned char)0, first_behavior = (unsigned char)0; long x, y; int draw_ok; unsigned char line_behavior, fill_color; char warning[200]; /* don't ever go over MAX_MAP_POINTS have a bad map not a crashed program */ if (npoints > MAX_MAP_POINTS) { xastir_snprintf(warning, sizeof(warning), "Warning line point count overflow: map_plot\b\n"); XtAppWarning (app_context, warning); npoints = MAX_MAP_POINTS; } /* if map_color_levels are on see if we should draw the line? */ draw_ok = 0; if (map_color_levels) // Decide which colors to display at this zoom level switch (color) { case (0x01): case (0x14): case (0x18): if (mag < 100) { draw_ok = 1; } break; case (0x15): case (0x19): if (mag < 600) { draw_ok = 1; } break; case (0x16): if (mag < 800) { draw_ok = 1; } break; default: draw_ok = 1; break; } // end of switch else // Display all colors { draw_ok = 1; } if (draw_ok) { x = ((x_long_cord - NW_corner_longitude) / scale_x); y = ((y_lat_cord - NW_corner_latitude) / scale_y); if (x < -MAX_OUTBOUND) { x = -MAX_OUTBOUND; } if (y < -MAX_OUTBOUND) { y = -MAX_OUTBOUND; } if (x > max_x) { x = max_x; } if (y > max_y) { y = max_y; } if (debug_level & 16) fprintf(stderr," MAP Plot - max_x: %ld, max_y: %ld, x: %ld, y: %ld, color: %d, behavior: %lx, points: %d\n", max_x, max_y, x, y, (int)color, (unsigned long)object_behavior, npoints); if ( (last_color != color) || (color == (unsigned char)0xff) ) { if (npoints && (last_color != (unsigned char)0xff) ) { line_behavior = last_behavior; if (last_behavior & 0x80) { if (color) { fill_color = (last_behavior & ~0x80) + (unsigned char)0x60; if (fill_color > (unsigned char)0x69) { fill_color = (unsigned char)0x60; } } else { fill_color = (unsigned char)object_behavior; } // Here's where we draw filled areas using fill_color. (void)XSetForeground (XtDisplay (w), gc, colors[(int)fill_color]); switch (destination_pixmap) { case DRAW_TO_PIXMAP: // We must be drawing maps 'cuz this is the pixmap we use for it. if (map_color_fill && draw_filled) { if (npoints >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap, gc, points, npoints, Nonconvex, CoordModeOrigin); } else { // fprintf(stderr, // "map_plot:Too few points:%d, Skipping XFillPolygon()", // npoints); } } break; case DRAW_TO_PIXMAP_ALERTS: fprintf(stderr,"You're calling the wrong routine to draw weather alerts!\n"); break; case DRAW_TO_PIXMAP_FINAL: // We must be drawing symbols/tracks 'cuz this is the pixmap we use for it. if (npoints >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap_final, gc, points, npoints, Nonconvex, CoordModeOrigin); } else { // fprintf(stderr, // "map_plot:Too few points:%d, Skipping XFillPolygon()", // npoints); } break; } // end of switch line_behavior = first_behavior; } if (line_behavior & 0x01) { (void)XSetLineAttributes (XtDisplay (w), gc, 2, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes (XtDisplay (w), gc, 1, LineSolid, CapButt,JoinMiter); } if (color == (unsigned char)0x56) { (void)XSetLineAttributes (XtDisplay (w), gc, 10, LineSolid, CapButt,JoinMiter); } // Set the color for drawing lines/borders (void)XSetForeground (XtDisplay (w), gc, colors[(int)last_color]); switch (destination_pixmap) { case DRAW_TO_PIXMAP_FINAL: (void)XDrawLines (XtDisplay (w), pixmap_final, gc, points, l16(npoints), CoordModeOrigin); break; case DRAW_TO_PIXMAP: (void)XDrawLines (XtDisplay (w), pixmap, gc, points, l16(npoints), CoordModeOrigin); break; case DRAW_TO_PIXMAP_ALERTS: fprintf(stderr,"You're calling the wrong routine to draw weather alerts!\n"); break; } // end of switch npoints = 0; /* check to see if we have been away from the screen too long */ if (redraw_check > 1000) { redraw_check = 0; XmUpdateDisplay (XtParent (da)); } redraw_check++; } last_color = color; if (color == (unsigned char)0xff) { npoints = 0; first_behavior = (unsigned char)object_behavior; } points[npoints].x = l16(x); points[npoints].y = l16(y); if ( (points[npoints].x > (-MAX_OUTBOUND)) && (points[npoints].x < (short)max_x) && (points[npoints].y > (-MAX_OUTBOUND)) && (points[npoints].y < (short)max_y) && (color != (unsigned char)0) ) { npoints++; } last_behavior = (unsigned char)object_behavior; return; } points[npoints].x = l16(x); points[npoints].y = l16(y); last_behavior = (unsigned char)object_behavior; if (points[npoints].x != points[npoints - 1].x || points[npoints].y != points[npoints - 1].y) { if (last_behavior & 0x80) { npoints++; } else if (points[npoints].x > (-MAX_OUTBOUND) && points[npoints].x < (short)max_x && points[npoints].y > (-MAX_OUTBOUND) && points[npoints].y < (short)max_y) { npoints++; } } } else { npoints = 0; } } /* map_plot */ void draw_dos_map(Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { FILE *f; char file[MAX_FILENAME]; char short_filenm[MAX_FILENAME]; char map_it[MAX_FILENAME]; /* map header info */ char map_type[5]; char map_version[5]; char file_name[33]; // char *ext; char map_title[33]; char map_creator[9]; unsigned long creation_date; unsigned long left_boundary; unsigned long right_boundary; unsigned long top_boundary; unsigned long bottom_boundary; char map_reserved1[9]; long total_vector_points; long total_labels; char map_reserved2[141]; char Buffer[2049]; char *ptr; int dos_labels; int dos_flag; long temp; int points_per_degree; // int map_range; /* vector info */ unsigned char vector_start; unsigned char object_behavior; unsigned long x_long_cord; unsigned long y_lat_cord; /* label data */ char label_type[3]; unsigned long label_x_cord; unsigned long label_y_cord; int temp_mag; int label_mag; char label_symbol_del; char label_symbol_char; char label_text_color; char label_text[50]; unsigned long year; unsigned long days; long count; int label_length; int i; // int map_maxed_vectors; // int map_maxed_text_labels; // int map_maxed_symbol_labels; // map_vectors *vectors_ptr; // text_label *text_ptr; // symbol_label *symbol_ptr; int line_width; int x, y; int color; long max_x, max_y; int in_window = 0; char symbol_table; char symbol_id; char symbol_color; int embedded_object; int draw_filled; unsigned char last_behavior, special_fill = (unsigned char)FALSE; draw_filled=mdf->draw_filled; x = 0; y = 0; color = -1; line_width = 1; mag = (1 * scale_y) / 2; // determines if details are drawn /* MAP counters */ // vectors_ptr = map_vectors_ptr; // text_ptr = map_text_label_ptr; // symbol_ptr = map_symbol_label_ptr; // map_maxed_vectors = 0; // map_maxed_text_labels = 0; // map_maxed_symbol_labels = 0; npoints = 0; xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } f = fopen (file, "r"); if (f == NULL) { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (fread (map_type, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_type[4] = '\0'; dos_labels = FALSE; points_per_degree = 300; // DOS-type map header portion of the code. if (strtod (map_type, &ptr) > 0.01 && (*ptr == '\0' || *ptr == ' ' || *ptr == ',')) { int j; if (debug_level & 512) { fprintf(stderr,"\nDOS Map\n"); } top_boundary = left_boundary = bottom_boundary = right_boundary = 0; rewind (f); map_title[0] = map_creator[0] = Buffer[0] = '\0'; // set map_type for DOS ASCII maps xastir_snprintf(map_type,sizeof(map_type),"DOS "); map_type[4] = '\0'; xastir_snprintf(file_name,sizeof(file_name),"%s",filenm); total_vector_points = 200000; total_labels = 2000; for (j = 0; j < DOS_HDR_LINES; strlen(Buffer) ? 1 : j++) { if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } // if (!strlen(Buffer)) // j++; while ((ptr = strpbrk (Buffer, "\r\n")) != NULL && j < DOS_HDR_LINES) { *ptr = '\0'; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; switch (j) { case 0: //fprintf(stderr,"top_boundary: %s\n", Buffer); top_boundary = (unsigned long) (-atof (Buffer) * 360000 + 32400000); break; case 1: //fprintf(stderr,"left_boundary: %s\n", Buffer); left_boundary = (unsigned long) (-atof (Buffer) * 360000 + 64800000); break; case 2: //fprintf(stderr,"points_per_degree: %s\n", Buffer); points_per_degree = atoi (Buffer); break; case 3: //fprintf(stderr,"bottom_boundary: %s\n", Buffer); bottom_boundary = (unsigned long) (-atof (Buffer) * 360000 + 32400000); bottom_boundary = bottom_boundary + bottom_boundary - top_boundary; break; case 4: //fprintf(stderr,"right_boundary: %s\n", Buffer); right_boundary = (unsigned long) (-atof (Buffer) * 360000 + 64800000); right_boundary = right_boundary + right_boundary - left_boundary; break; case 5: //fprintf(stderr,"map_range: %s\n", Buffer); // map_range = (int) atof (Buffer); break; case 7: //fprintf(stderr,"Map Version: %s\n", Buffer); memcpy(map_version, Buffer, sizeof(map_version)); map_version[sizeof(map_version)-1] = '\0'; // Terminate string //fprintf(stderr,"MAP VERSION: %s\n", map_version); break; } // end of switch xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); // if (strlen (Buffer)) // j++; } } // End of DOS-type map header portion } else { // Windows-type map header portion if (debug_level & 512) { fprintf(stderr,"\nWindows map\n"); } if (fread (map_version, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_version[4] = '\0'; if (fread (file_name, 32, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } file_name[32] = '\0'; if (fread (map_title, 32, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_title[32] = '\0'; if (debug_level & 16) { fprintf(stderr,"Map Title %s\n", map_title); } if (fread (map_creator, 8, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_creator[8] = '\0'; if (debug_level & 16) { fprintf(stderr,"Map Creator %s\n", map_creator); } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } creation_date = ntohl (temp); if (debug_level & 16) { fprintf(stderr,"Creation Date %lX\n", creation_date); } year = creation_date / 31536000l; days = (creation_date - (year * 31536000l)) / 86400l; if (debug_level & 16) { fprintf(stderr,"year is %ld + days %ld\n", 1904l + year, (long)days); } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } left_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } right_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } top_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } bottom_boundary = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { left_boundary *= 10; right_boundary *= 10; top_boundary *= 10; bottom_boundary *= 10; } if (fread (map_reserved1, 8, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } total_vector_points = (long)ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } total_labels = (long)ntohl (temp); if (fread (map_reserved2, 140, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } } // End of Windows-type map header portion // Done processing map header info. The rest of this // function performs the actual drawing of both DOS-type // and Windows-type maps to the screen. if (debug_level & 16) { fprintf(stderr,"Map Type: %s, Version: %s, Filename: %s\n", map_type, map_version, file_name); fprintf(stderr,"Left Boundary: %ld, Right Boundary: %ld\n", (long)left_boundary,(long)right_boundary); fprintf(stderr,"Top Boundary: %ld, Bottom Boundary: %ld\n", (long)top_boundary,(long)bottom_boundary); fprintf(stderr,"Total vector points: %ld, total labels: %ld\n",total_vector_points, total_labels); } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_boundary, // Bottom top_boundary, // Top left_boundary, // Left right_boundary, // Right 1000); // Default Map Level (void)fclose (f); // Update the statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check to see if we should draw the map in_window = map_onscreen(left_boundary, right_boundary, top_boundary, bottom_boundary, 1); if (!in_window) { (void)fclose (f); return; } // Update the statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading/Indexing ... object_behavior = '\0'; if (debug_level & 16) { fprintf(stderr,"in Boundary %s\n", map_it); } (void)XSetLineAttributes (XtDisplay (w), gc, line_width, LineSolid, CapButt,JoinMiter); /* read vectors */ max_x = screen_width + MAX_OUTBOUND; max_y = screen_height + MAX_OUTBOUND; x_long_cord = 0; y_lat_cord = 0; color = 0; dos_flag = 0; for (count = 0l; count < total_vector_points && !feof (f) && !dos_labels; count++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // DOS type map if (strncmp ("DOS ", map_type, 4) == 0) { if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } while ((ptr = strpbrk (Buffer, "\r\n")) != NULL && !dos_labels) { long LatHld = 0, LongHld; char *trailer; *ptr = '\0'; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; process: if (strncasecmp ("Line", map_version, 4) == 0) { int k; color = (int)strtol (Buffer, &trailer, 0); if (trailer && (*trailer == ',' || *trailer == ' ')) { trailer++; if (color == -1) { dos_labels = (int)TRUE; xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); break; } for (k = strlen (trailer) - 1; k >= 0; k--) { trailer[k] = (char)( (int)trailer[k] - 27 ); } while (*trailer) { LongHld = (long)( (int)(*(unsigned char *)trailer) * 16); trailer++; LatHld = (long)( (int)(*(unsigned char *)trailer) * 8); trailer++; LongHld += (long)((*trailer >> 3) & 0xf); LatHld += (long)( (*trailer) & 0x7); trailer++; LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', 0, destination_pixmap, draw_filled); } } else if (strncasecmp ("ASCII", map_version, 4) == 0) { if (color == 0) { color = (int)strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; dos_flag = (int)strtol (trailer, &trailer, 0); if (dos_flag == -1) { dos_labels = (int)TRUE; } } } else { LongHld = strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; LatHld = strtol (trailer, &trailer, 0); } else if (LongHld == 0 && *trailer != '\0') { xastir_snprintf(map_version,sizeof(map_version),"Comp"); map_version[4] = '\0'; goto process; } if (LongHld == 0 && LatHld == 0) { color = 0; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } else if (LongHld == 0 && LatHld == -1) { dos_labels = (int)TRUE; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', 0, destination_pixmap, draw_filled); } else { LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } } } else if (strncasecmp ("Comp", map_version, 4) == 0) { char Tag[81]; int k; Tag[80] = '\0'; if (color == 0) { color = (int)strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; dos_flag = (int)strtol (trailer, &trailer, 0); xastir_snprintf(Tag,sizeof(Tag),"%s",trailer); Tag[79] = '\0'; if (dos_flag == -1) { dos_labels = (int)TRUE; } } } else { LongHld = strtol (Buffer, &trailer, 0); for (; *trailer == ',' || *trailer == ' '; trailer++) ; LatHld = strtol (trailer, &trailer, 0); if (LatHld == 0 && *trailer != '\0') { LatHld = 1; } if (LongHld == 0 && LatHld == 0) { color = 0; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } else if (LongHld == 0 && LatHld == -1) { dos_labels = (int)TRUE; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } if (color && !dos_labels) { trailer = Buffer; for (k = strlen (trailer) - 1; k >= 0; k--) { trailer[k] = (char)((int)trailer[k] - 27); } while (*trailer) { LongHld = (long)( (int)(*(unsigned char *)trailer) * 16); trailer++; LatHld = (long)( (int)(*(unsigned char *)trailer) * 8); trailer++; LongHld += (long)((*(unsigned char *)trailer >> 3) & 0xf); LatHld += (*trailer) & 7l; trailer++; LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } } } } else { LongHld = strtol (Buffer, &trailer, 0); if (trailer) { if (*trailer == ',' || *trailer == ' ') { if (LongHld == 0) { memcpy(map_version, "ASCII", sizeof(map_version)); map_version[sizeof(map_version)-1] = '\0'; // Terminate string } map_version[4] = '\0'; trailer++; dos_flag = (int)strtol (trailer, &trailer, 0); if (dos_flag == -1) { dos_labels = (int)TRUE; } if (dos_flag == 0 && *trailer != '\0') { xastir_snprintf(map_version,sizeof(map_version),"Line"); map_version[4] = '\0'; goto process; } color = (int)LongHld; } } else { xastir_snprintf(map_version,sizeof(map_version),"Comp"); } map_version[4] = '\0'; } xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); } } else { // Windows type map... last_behavior = object_behavior; if (fread (&vector_start, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&object_behavior, 1, 1, f) == 0) // Fill Color? { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (strcmp (map_type, "COMP") == 0) { short temp_short; long LatOffset, LongOffset; LatOffset = (long)(top_boundary - top_boundary % 6000); LongOffset = (long)(left_boundary - left_boundary % 6000); if (fread (&temp_short, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } x_long_cord = (ntohs (temp_short) * 10 + LongOffset); if (fread (&temp_short, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } y_lat_cord = (ntohs (temp_short) * 10 + LatOffset); } else { if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } x_long_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { x_long_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } y_lat_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { y_lat_cord *= 10; } } if (alert_color && last_behavior & 0x80 && (int)vector_start == 0xff) { map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', (long)alert_color, destination_pixmap, draw_filled); //special_fill = TRUE; } map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, vector_start, (long)object_behavior, destination_pixmap, draw_filled); } } if (alert_color) { map_plot (w, max_x, max_y, 0, 0, '\0', special_fill ? (long)0xfd : (long)alert_color, destination_pixmap, draw_filled); } else { map_plot (w, max_x, max_y, 0, 0, (unsigned char)0xff, 0, destination_pixmap, draw_filled); } (void)XSetForeground (XtDisplay (w), gc, colors[20]); line_width = 2; (void)XSetLineAttributes (XtDisplay (w), gc, line_width, LineSolid, CapButt,JoinMiter); // Here is the map label section of the code for both DOS & Windows-type maps if (map_labels) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* read labels */ for (count = 0l; count < total_labels && !feof (f); count++) { //DOS-Type Map Labels embedded_object = 0; if (strcmp (map_type, "DOS ") == 0) // Handle DOS-type map labels/embedded objects { char *trailer; if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } for (; (ptr = strpbrk (Buffer, "\r\n")) != NULL; xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr)) { *ptr = '\0'; label_type[0] = (char)0x08; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; trailer = strchr (Buffer, ','); if (trailer && strncmp (Buffer, "0", 1) != 0) { *trailer = '\0'; trailer++; memcpy(label_text, Buffer, sizeof(label_text)); label_text[sizeof(label_text)-1] = '\0'; // Terminate string // Check for '#' or '$' as the first character of the label. // If found, we have an embedded symbol and colored text to display. symbol_table = ' '; symbol_id = ' '; symbol_color = '0'; if ( (label_text[0] == '$') || (label_text[0] == '#') ) { // We found an embedded map object embedded_object = 1; // Set the flag if (label_text[0] == '$') // Old format: $xC { symbol_table = '/'; symbol_id = label_text[1]; symbol_color = label_text[2]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+3); } else // Could be in new or old format with a leading '#' character { symbol_table = label_text[1]; if (symbol_table == '/' || symbol_table == '\\') // New format: #/xC { symbol_id = label_text[2]; symbol_color = label_text[3]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+4); } else // Old format: #xC { symbol_table = '\\'; symbol_id = label_text[1]; symbol_color = label_text[2]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+3); } } if (debug_level & 512) { fprintf(stderr,"Found embedded object: %c %c %c %s\n",symbol_table,symbol_id,symbol_color,label_text); } } label_length = (int)strlen (label_text); label_y_cord = (unsigned long) (-strtod (trailer, &trailer) * 360000) + 32400000; trailer++; label_x_cord = (unsigned long) (-strtod (trailer, &trailer) * 360000) + 64800000; trailer++; label_mag = (int)strtol (trailer, &trailer, 0) * 20; if ((label_type[0] & 0x80) == '\0') /* left of coords */ { x = ((label_x_cord - NW_corner_longitude) / scale_x) - (label_length * 6); } else /* right of coords */ { x = ((label_x_cord - NW_corner_longitude) / scale_x); } y = ((label_y_cord - NW_corner_latitude) / scale_y); if (x > (0) && (x < (int)screen_width)) { if (y > (0) && (y < (int)screen_height)) { /*fprintf(stderr,"Label mag %d mag %d\n",label_mag,(scale_x*2)-1); */ //if (label_mag > (int)((scale_x * 2) - 1) || label_mag == 0) if (label_mag > (int)((scale_x) - 1) || label_mag == 0) { if (embedded_object) { // NOTE: 0x21 is the first color for the area object or "DOS" colors draw_label_text (w, x+10, y+5, label_length,colors[0x21 + symbol_color],label_text); symbol(w,0,symbol_table,symbol_id,' ',pixmap,1,x-10,y-10,' '); } else { draw_label_text (w, x, y, label_length,colors[(int)(label_type[0] & 0x7f)],label_text); } } } } } } } else // Handle Windows-type map labels/embedded objects { int rotation = 0; char rotation_factor[5]; // Windows-Type Map Labels char label_type_1[2], label_type_2[2]; // Snag first two bytes of label if (fread (label_type_1, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (label_type_2, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_type_2[0] == '\0') // Found a label { // Found text label if (fread (&temp, 4, 1, f) == 0) /* x */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_x_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_x_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) /* y */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_y_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_y_cord *= 10; } if (fread (&temp_mag, 2, 1, f) == 0) /* mag */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_mag = (int)ntohs (temp_mag); if (strcmp (map_version, "2.00") != 0) { label_mag *= 10; } if (strcmp (map_type, "COMP") == 0) { for (i = 0; i < 32; i++) { if (fread (&label_text[i], 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text[i] == '\0') { break; } } label_text[32] = '\0'; // Make sure we have a terminator } else { if (fread (label_text, 32, 1, f) == 0) /* text */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_text[32] = '\0'; // Make sure we have a terminator } // Special strings like: "#123" are rotation factors for labels // in degrees. This is not documented in the windows-type map // format documents that I could find. if (label_text[0] == '#') { int i,j; if (debug_level & 512) { fprintf(stderr,"%s\n",label_text); } // Save the rotation factor in "rotation" for ( i=1; i<4; i++ ) { rotation_factor[i-1] = label_text[i]; } rotation_factor[3] = '\0'; rotation = atoi(rotation_factor); // Take rotation factor out of label string for ( i=4, j=0; i < (int)(strlen(label_text)+1); i++,j++) { label_text[j] = label_text[i]; } //fprintf(stderr,"Windows label: %s, rotation factor: %d\n",label_text, rotation); } label_length = (int)strlen (label_text); for (i = (label_length - 1); i > 0; i--) { if (label_text[i] == ' ') { label_text[i] = '\0'; } else { break; } } label_length = (int)strlen (label_text); /*fprintf(stderr,"labelin:%s\n",label_text); */ if ((label_type_1[0] & 0x80) == '\0') { /* left of coords */ x = ((label_x_cord - NW_corner_longitude) / scale_x) - (label_length * 6); x = 0; // ?????? } else { /* right of coords */ x = ((label_x_cord - NW_corner_longitude) / scale_x); } y = ((label_y_cord - NW_corner_latitude) / scale_y); if (x > (0) && (x < (int)screen_width)) { if (y > (0) && (y < (int)screen_height)) { /*fprintf(stderr,"Label mag %d mag %d\n",label_mag,(scale_x*2)-1); */ //if (label_mag > (int)((scale_x * 2) - 1) || label_mag == 0) if (label_mag > (int)((scale_x) - 1) || label_mag == 0) { // Note: We're not drawing the labels in the right colors if (rotation == 0) // Non-rotated label { // draw_label_text (w, // x, // y, // label_length, // colors[(int)(label_type_1[0] & 0x7f)], // label_text); draw_rotated_label_text (w, -90.0, x, y, label_length, colors[(int)(label_type_1[0] & 0x7f)], label_text, FONT_DEFAULT); } else // Rotated label { draw_rotated_label_text (w, rotation, x, y, label_length, colors[(int)(label_type_1[0] & 0x7f)], label_text, FONT_DEFAULT); } } } } } else if (label_type_2[0] == '\1' && label_type_1[0] == '\0') // Found an embedded object { //fprintf(stderr,"Found windows embedded symbol\n"); /* label is an embedded symbol */ if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_x_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_x_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_y_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_y_cord *= 10; } if (fread (&temp_mag, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_mag = (int)ntohs (temp_mag); if (strcmp (map_version, "2.00") != 0) { label_mag *= 10; } if (fread (&label_symbol_del, 1, 1, f) == 0) // Snag symbol table char { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&label_symbol_char, 1, 1, f) == 0) // Snag symbol char { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&label_text_color, 1, 1, f) == 0) // Snag text color (should be 1-9, others should default to black) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text_color < '1' && label_text_color > '9') { label_text_color = '0'; // Default to black } x = ((label_x_cord - NW_corner_longitude) / scale_x); y = ((label_y_cord - NW_corner_latitude) / scale_y); // Read the label text portion if (strcmp (map_type, "COMP") == 0) { for (i = 0; i < 32; i++) { if (fread (&label_text[i], 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text[i] == '\0') { break; } } } else { if (fread (label_text, 29, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } } // NOTE: 0x21 is the first color for the area object or "DOS" colors draw_label_text (w, x+10, y+5, strlen(label_text),colors[0x21 + label_text_color],label_text); symbol(w,0,label_symbol_del,label_symbol_char,' ',pixmap,1,x-10,y-10,' '); if (debug_level & 512) fprintf(stderr,"Windows map, embedded object: %c %c %c %s\n", label_symbol_del,label_symbol_char,label_text_color,label_text); } else { if (debug_level & 512) fprintf(stderr,"Weird label in Windows map, neither a plain label nor an object: %d %d\n", label_type_1[0],label_type_2[0]); } } } } // if (map_labels) (void)fclose (f); } Xastir-Release-2.2.2/src/map_geo.c000066400000000000000000002577271501463444000167340ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //#define FUZZYRASTER #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "map_cache.h" #include "alert.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #include "map_OSM.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } // Check for XPM and/or ImageMagick. We use "NO_GRAPHICS" // to disable some routines below if the support for them // is not compiled in. #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK)) #define NO_GRAPHICS 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK) #if defined(HAVE_MAGICK) || !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM)) #define NO_XPM 1 #endif // HAVE_MAGICK || !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM) #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" int check_interrupt( #ifdef HAVE_MAGICK Image *image, ImageInfo *image_info, ExceptionInfo *exception, #else // HAVE_MAGICK XImage *xi, #endif // HAVE_MAGICK Widget *da, Pixmap *pixmap, GC *gc, unsigned long screen_width, unsigned long screen_height) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { #ifdef HAVE_MAGICK if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } #else // HAVE_MAGICK if (xi) { XDestroyImage (xi); } #endif // HAVE_MAGICK // Update to screen (void)XCopyArea(XtDisplay(*da), *pixmap, XtWindow(*da), *gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); #ifdef HAVE_MAGICK DestroyExceptionInfo(exception); #endif // HAVE_MAGICK return(~0); } else { return(0); } } void draw_geo_image_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf); /* typedef struct _transparent_color_record{ unsigned long trans_color; struct _transparent_color_record *next; } transparent_color_record; */ // Pointer to head of transparent color linked list. transparent_color_record *trans_color_head = NULL; // Empty out the linked list containing transparent colors void empty_trans_color_list(void) { transparent_color_record *p; while (trans_color_head != NULL) { p = trans_color_head; trans_color_head = p->next; free(p); } } // Add a new transparent color to the linked list void new_trans_color(unsigned long trans_color) { transparent_color_record *p; //fprintf(stderr,"New transparent color: %lx\n", trans_color); p = (transparent_color_record *)malloc( sizeof(transparent_color_record) ); // Fill in value p->trans_color = trans_color; // Link it to transparent color list p->next = trans_color_head; trans_color_head = p; } /********************(********************************************** * check_trans() * * See if this pixel's color should be transparent * * We only call this from blocks where ImageMagick is used, so we're * ok to use IM calls. ******************************************(************************/ int check_trans (XColor c, transparent_color_record *c_trans_color_head) { transparent_color_record *p = c_trans_color_head; // fprintf (stderr, "pix = %li,%lx, chk = %li,%lx.\n",c.pixel,c.pixel,c_trans_color,c_trans_color); // A linked list from the geo file of colors to zap. // if ( c.pixel == (unsigned long) 0x000000 ) { // return 1; // black background //} while (p) { if ( c.pixel == p->trans_color ) { return 1; } p = p->next; } return 0; // everything else is OK to draw } // Regarding MAP CACHING for toporama maps: Here we are only // snagging a .geo file for toporama from findu.com: We send the // parameters off to findu.com, it computes the .geo file, we // download it, then we call draw_geo_image_map() with it. We would // have to cache the .geo files from findu, we'd have to modify them // to point to our local cached map file (maybe), and we'd of course // have to cache that map image as well. The image filename on // findu changes each time we call with the same parameters, so we'd // have to give the image file our own name based on the parameters // and write that same name into the cached .geo file. A bit of // work, but it _could_ be done. Actually, we should be able to map // between the original URL we use to request the .GEO file and the // final image we received. That way the name would stay the same // each time we made the request. There may be other things we need // from the generated .GEO file though. // // For this particular case we need to snag a remote .geo file and // then start the process all over again. The URL we'll need to use // looks something like this: // // http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1 // // Where the lat/lon are the center of our view, and the // width/height depend on our window size. The "set" parameter // decides whether we're fetching 50k or 250k maps. // void draw_toporama_map (Widget w, char * UNUSED(dir), char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf, int toporama_flag) // 50 or 250 { #ifdef HAVE_MAGICK char fileimg[MAX_FILENAME+1]; // Ascii name of image file, read from GEO file char map_it[MAX_FILENAME]; char local_filename[MAX_FILENAME]; char file[MAX_FILENAME+1]; // Complete path/name of image file char short_filenm[MAX_FILENAME+1]; FILE *f; // Filehandle of image file double lat_center = 0; double long_center = 0; double left, right, top, bottom; int my_screen_width, my_screen_height; float my_zoom = 1.0; char temp_file_path[MAX_VALUE]; // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } //fprintf(stderr, "Found TOPORAMA in a .geo file, %dk scale\n", toporama_flag); // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the index // file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // Compute the parameters we'll need for the URL, fetch the .geo // file at that address, then pass that .geo file off to // draw_geo_image_map(). This will cause us to fetch the image // file corresponding to the .geo file and display it. We may // also need to tweak the zoom parameter for our current zoom // level so that things match up properly. // Compute the center of our view in decimal lat/long. left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates right = (double)((SE_corner_longitude - 64800000l)/360000.0);//Lat/long Coordinates bottom = (double)(-((SE_corner_latitude - 32400000l)/360000.0));//Lat/long Coordinates long_center = (left + right)/2.0l; lat_center = (top + bottom)/2.0l; // We now have the center in decimal lat/long. We also have the // screen width and height in pixels, which we can use in the // URL as well (depending on the zoom parameter and how to make // the finished display look nice). // Compute the size of the image we want to snag. It should be // easy to get darn near anything to work, although the size and // scale of the image will drastically affect how nicely the // finished map display will look. // Compute the zoom parameter for the URL. // A test URL that works, just to get things going. This URL // requests 1:50k scale maps ("set=50"). //xastir_snprintf(fileimg, sizeof(fileimg), // "\"http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1\""); // Compute our custom URL based on our map view and the // requested map scale. // my_screen_width = (int)screen_width; my_screen_height = (int)screen_height; if (toporama_flag == 50) // 1:50k { my_zoom = 32.0 / scale_y; if (scale_y <= 16) { my_zoom = 2.0; } } else // toporama_flag == 250 (1:250k) { my_zoom = 128.0 / scale_y; if (scale_y <= 64) { my_zoom = 2.0; } } // Set a max zoom limit so we don't tax the server too much. if (my_zoom < 0.02) { my_zoom = 0.02; } xastir_snprintf(fileimg, sizeof(fileimg), "http://mm.aprs.net/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f", // "http://www2.findu.com/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f", toporama_flag, // Scale, 50 or 250 lat_center, long_center, my_screen_width, my_screen_height, my_zoom); //fprintf(stderr,"%s\n", fileimg); // Create a local filename that we'll save to. xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.geo", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path))); // Erase any previously existing local file by the same // name. This avoids the problem of having an old map image // here and the code trying to display it when the download // fails. unlink( local_filename ); // Call wget or libcurl to fetch the .geo file. Best would be // to create a generic "fetch" routine which would fetch a // remote file, then go back and rework all of the various map // routines to use it. if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. // Tell ImageMagick where to find it xastir_snprintf(file,sizeof(file),"%s",local_filename); // Check whether we got a reasonable ~/.xastir/tmp/map.geo file from // the fetch. If so, pass it off to the routine which can draw it. // We also need to write a valid IMAGESIZE line into the .geo // file. We know these parameters because they should match // screen_width/screen_height. // xastir_snprintf(map_it, sizeof(map_it), "IMAGESIZE\t%d\t%d\n", my_screen_width, my_screen_height); // Another thing we might need is a TRANSPARENT line, for the grey // color we see crossing over the U.S. border and obscuring maps on // this side of the border. f = fopen (local_filename, "a"); if (f != NULL) { fprintf(f, "%s", map_it); (void)fclose (f); } else { fprintf(stderr,"Couldn't open file: %s to add IMAGESIZE tag\n", local_filename); return; } // Call draw_geo_image_map() with our newly-fetched .geo file, // passing it most of the parameters that we were originally // passed in order to effect the map draw. draw_geo_image_map (w, get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "map.geo", alert, alert_color, destination_pixmap, mdf); #endif // HAVE_MAGICK } /********************************************************** * draw_geo_image_map() * * If we have found a ".geo" file, we read it here and plot * the graphic image into the current viewport. * We check first to see whether the map should be plotted * and skip it if it's not in our viewport. These images * are expected to be aligned in the lat/lon directions * (not rotated) and rectangular. **********************************************************/ void draw_geo_image_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { #ifdef NO_GRAPHICS fprintf(stderr,"XPM and/or ImageMagick support have not been compiled in.\n"); #else // NO_GRAPHICS char file[MAX_FILENAME+1]; // Complete path/name of image file char short_filenm[MAX_FILENAME+1]; FILE *f; // Filehandle of image file char line[MAX_FILENAME]; // One line from GEO file char fileimg[MAX_FILENAME+1]; // Ascii name of image file, read from GEO file char tileCache[MAX_FILENAME+1]; // directory for the OSM tile cache, read from GEO file. char OSMstyle[MAX_OSMSTYLE]; char OSMtileExt[MAX_OSMEXT]; // Start with an empty fileimg[] string so that we can // tell if a URL has been specified in the file. Same for OSMstyle. fileimg[0] = '\0'; OSMstyle[0] = '\0'; tileCache[0] = '\0'; OSMtileExt[0] = '\0'; int width,height; #ifndef NO_XPM XpmAttributes atb; // Map attributes after map's read into an XImage #endif // NO_XPM tiepoint tp[2]; // Calibration points for map, read in from .geo file int n_tp; // Temp counter for number of tiepoints read float temp_long, temp_lat; long map_c_T, map_c_L; // map delta NW edge coordinates, DNN: these should be signed long tp_c_dx, tp_c_dy; // tiepoint coordinate differences // DK7IN-- // int test; // temporary debugging unsigned long c_x_min, c_y_min;// top left coordinates of map inside screen // unsigned long c_y_max; // bottom right coordinates of map inside screen double c_x; // Xastir coordinates 1/100 sec, 0 = 180W double c_y; // Xastir coordinates 1/100 sec, 0 = 90N double c_y_a; // coordinates correction for Transverse Mercator long map_y_0; // map pixel pointer prior to TM adjustment long map_x, map_y; // map pixel pointers, DNN: this was a float, chg to long long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; // long map_x_ctr; // half map width in pixel // long map_y_ctr; // half map height in pixel // long x; int map_seen, map_act, map_done; double corrfact; long map_c_yc; // map center, vert coordinate long map_c_xc; // map center, hor coordinate double map_c_dx, map_c_dy; // map coordinates increment (pixel width) double c_dx; // adjusted map pixel width long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions // long scr_x_mc; // map center in screen units long scr_c_xr; double dist; // distance from equator in nm double ew_ofs; // distance from map center in nm long scale_xa; // adjusted for topo maps double scale_x_nm; // nm per Xastir coordinate unit long scale_x0; // at widest map area #ifdef HAVE_MAGICK char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; int l; XColor my_colors[256]; time_t query_start_time, query_end_time; char gamma[16]; struct { float r_gamma; float g_gamma; float b_gamma; int gamma_flag; int contrast; int negate; int equalize; int normalize; char level[32]; char modulate[32]; } imagemagick_options = { 1.0, 1.0, 1.0, 0, 0, -1, 0, 0, "", "" }; double left, right, top, bottom; // double map_width, map_height; //N0VH // double lat_center = 0; // double long_center = 0; // Terraserver variables double top_n=0, left_e=0, bottom_n=0, right_e=0, map_top_n=0, map_left_e=0; int z, url_n=0, url_e=0, t_zoom=16, t_scale=12800; char zstr0[8]; char zstr1[8]; #else // HAVE_MAGICK XImage *xi; // Temp XImage used for reading in current image #endif // HAVE_MAGICK int terraserver_flag = 0; // U.S. satellite images/topo/reflectivity/urban // areas via terraserver int OSMserver_flag = 0; // OpenStreetMaps server, 1 = static maps, 2 = tiled unsigned tmp_zl = 0; int toporama_flag = 0; // Canadian topo's from mm.aprs.net (originally from Toporama) int WMSserver_flag = 0; // WMS server char map_it[MAX_FILENAME]; int geo_image_width = 0; // Image width from GEO file int geo_image_height = 0; // Image height from GEO file char geo_datum[8+1]; // WGS-84 etc. char geo_projection[256+1]; // TM, UTM, GK, LATLON etc. int map_proj=0; int map_refresh_interval_temp = 0; #ifdef HAVE_MAGICK int nocache = 0; // Don't cache the file if non-zero #endif // HAVE_MAGICK #ifdef FUZZYRASTER int rasterfuzz = 3; // ratio to skip #endif //FUZZYRASTER unsigned long temp_trans_color; // what color to zap int trans_skip = 0; // skip transparent pixel int crop_x1=0, crop_x2=0, crop_y1=0, crop_y2=0; // pixel crop box int do_crop = 0; // do we crop pixels //#define TIMING_DEBUG #ifdef TIMING_DEBUG time_mark(1); #endif // TIMING_DEBUG #ifdef HAVE_MAGICK #ifdef USE_MAP_CACHE int map_cache_return; char *cache_file_id; #endif // USE_MAP_CACHE #endif // HAVE_MAGICK #ifdef HAVE_MAGICK char temp_file_path[MAX_VALUE]; #endif // HAVE_MAGICK KeySym OSM_key = 0; xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } // Read the .geo file to find out map filename and tiepoint info // Empty the transparent color list before we start reading in a // new .geo file. empty_trans_color_list(); n_tp = 0; geo_datum[0] = '\0'; geo_projection[0] = '\0'; f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) { (void)get_line (f, line, MAX_FILENAME); if (strncasecmp (line, "FILENAME", 8) == 0) { if (1 != sscanf (line + 9, "%s", fileimg)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (fileimg[0] != '/' ) // not absolute path { // make it relative to the .geo file char temp[MAX_FILENAME]; // grab .geo file name strcpy(temp, file); temp[sizeof(temp)-1] = '\0'; // Terminate line (void)get_map_dir(temp); // leaves just the path and trailing / if (strlen(temp) < (MAX_FILENAME - 1 - strlen(fileimg))) strncat(temp, fileimg, sizeof(temp) - 1 - strlen(temp)); xastir_snprintf(fileimg,sizeof(fileimg),"%s",temp); } } if (strncasecmp (line, "URL", 3) == 0) if (1 != sscanf (line + 4, "%s", fileimg)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (n_tp < 2) // Only take the first two tiepoints { if (strncasecmp (line, "TIEPOINT", 8) == 0) { if (4 != sscanf (line + 9, "%d %d %f %f", &tp[n_tp].img_x, &tp[n_tp].img_y, &temp_long, &temp_lat)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } // Convert tiepoints from lat/lon to Xastir coordinates tp[n_tp].x_long = 64800000l + (360000.0 * temp_long); tp[n_tp].y_lat = 32400000l + (360000.0 * (-temp_lat)); n_tp++; } } if (strncasecmp (line, "IMAGESIZE", 9) == 0) if (2 != sscanf (line + 10, "%d %d",&geo_image_width,&geo_image_height)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "DATUM", 5) == 0) if (1 != sscanf (line + 6, "%8s",geo_datum)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "PROJECTION", 10) == 0) // Ignores leading and trailing space (nice!) if (1 != sscanf (line + 11, "%256s",geo_projection)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "TERRASERVER-URBAN", 17) == 0) { terraserver_flag = 4; } if (strncasecmp (line, "TERRASERVER-REFLECTIVITY", 24) == 0) { terraserver_flag = 3; } if (strncasecmp (line, "TERRASERVER-TOPO", 16) == 0) { // Set to max brightness as it looks weird when the // intensity variable comes into play. #ifdef HAVE_MAGICK // This one causes problems now. Not sure why. // xastir_snprintf(imagemagick_options.modulate,32,"100 100 100"); #endif // HAVE_MAGICK terraserver_flag = 2; } if (strncasecmp (line, "TERRASERVER-SATELLITE", 21) == 0) { terraserver_flag = 1; } if (strncasecmp (line, "OSMSTATICMAP", 12) == 0) { OSMserver_flag = 1; if (strlen(line) > 13) { if (1 != sscanf (line + 13, "%s", OSMstyle)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n"); } } } if (strncasecmp (line, "OSM_TILED_MAP", 13) == 0) { OSMserver_flag = 2; if (strlen(line) > 14) { if (1 != sscanf (line + 14, "%s", OSMstyle)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n"); } } } if (OSMserver_flag > 0) // the following keywords are only valid for OSM maps { if (strncasecmp (line, "OSM_OPTIMIZE_KEY", 16) == 0) { if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS)) { if (strlen(line) > 17) { if (1 != sscanf (line + 17, "%lu", &OSM_key)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n"); } else { set_OSM_optimize_key(OSM_key); } } } } if (strncasecmp (line, "OSM_REPORT_SCALE_KEY", 20) == 0) { if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS)) { if (strlen(line) > 21) { if (1 != sscanf (line + 21, "%lu", &OSM_key)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n"); } else { set_OSM_report_scale_key(OSM_key); } } } } if (strncasecmp (line, "TILE_DIR", 8) == 0) { if (strlen(line) > 9) { if (1 != sscanf (line + 9, "%s", tileCache)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_DIR\n"); } } } if (strncasecmp (line, "TILE_EXT", 8) == 0) { if (strlen(line) > 9) { if (1 != sscanf (line + 9, "%s", OSMtileExt)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_EXT\n"); } } } if (strncasecmp(line, "ZOOM_LEVEL_MIN", 14) == 0) { if (strlen(line) > 15) { if (1 != sscanf(line + 15, "%u", &tmp_zl)) { fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MIN\n"); } else { if (!(osm_zoom_level(scale_x) >= tmp_zl)) { // skip this map because the zoom level // is not supported. if (debug_level & 512) { fprintf(stderr, "Skipping OSM map. zl = %u < %u\n", osm_zoom_level(scale_x), tmp_zl); } return; } } } } if (strncasecmp(line, "ZOOM_LEVEL_MAX", 14) == 0) { if (strlen(line) > 15) { if (1 != sscanf(line + 15, "%u", &tmp_zl)) { fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MAX\n"); } else { if (!(tmp_zl >= osm_zoom_level(scale_x))) { // skip this map because the zoom level // is not supported. if (debug_level & 512) { fprintf(stderr, "Skipping OSM map. zl = %u > %u\n", osm_zoom_level(scale_x), tmp_zl); } return; } } } } } if (strncasecmp (line, "WMSSERVER", 9) == 0) { WMSserver_flag = 1; } // Check for Canadian topo map request if (strncasecmp (line, "TOPORAMA-50k", 12) == 0) { toporama_flag = 50; } if (strncasecmp (line, "TOPORAMA-250k", 13) == 0) { toporama_flag = 250; } // Check whether we're indexing or drawing the map. // Exclude setting the map refresh interval from // indexing. if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { if (strncasecmp (line, "REFRESH", 7) == 0) { if (1 != sscanf (line + 8, "%d", &map_refresh_interval_temp)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if ( map_refresh_interval_temp > 0 && ( map_refresh_interval == 0 || map_refresh_interval_temp < map_refresh_interval) ) { map_refresh_interval = (time_t) map_refresh_interval_temp; map_refresh_time = sec_now() + map_refresh_interval; if (debug_level & 512) { fprintf(stderr, "Map Refresh set to %d.\n", (int) map_refresh_interval); } } #ifdef HAVE_MAGICK nocache = map_refresh_interval_temp; #endif // HAVE_MAGICK } } if (strncasecmp(line, "TRANSPARENT", 11) == 0) { // need to make this read a list of colors to zap // out. Use 32-bit unsigned values, so we can // handle 32-bit color displays. if (1 != sscanf (line + 12, "%lx", &temp_trans_color)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } { unsigned short r,g,b; // We'll assume the temp_trans_color has been // specified as a 24-bit quantity r = (temp_trans_color&0xff0000) >> 16; g = (temp_trans_color&0x00ff00)>>8; b = temp_trans_color&0x0000ff; // Now this is an incredible kludge, but seems to be right // Apparently, if QuantumDepth is 16 bits, r, g, and b // values are duplicated in the high and low byte, which // is just bizarre #ifdef HAVE_MAGICK if (QuantumDepth == 16) { r=r|(r<<8); g=g|(g<<8); b=b|(b<<8); } #endif // HAVE_MAGICK //fprintf(stderr,"Original Transparent %lx\n",temp_trans_color); //fprintf(stderr,"Transparent r,g,b=%x,%x,%x\n",r,g,b); if (visual_type == NOT_TRUE_NOR_DIRECT) { XColor junk; #ifdef HAVE_MAGICK if (QuantumDepth == 16) { junk.red=r; junk.green=g; junk.blue=b; } else #endif // HAVE_MAGICK { junk.red= r<<8; junk.green = g<<8; junk.blue = b<<8; } XAllocColor(XtDisplay(w),cmap,&junk); temp_trans_color = junk.pixel; } else { pack_pixel_bits(r,g,b,&temp_trans_color); } //fprintf(stderr,"Packed Transparent %lx\n",temp_trans_color); } //fprintf(stderr,"New Transparent: %lx\n",temp_trans_color); // Link color to transparent color list new_trans_color(temp_trans_color); } if (strncasecmp(line, "CROP", 4) == 0) { if (4 != sscanf (line + 5, "%d %d %d %d", &crop_x1, &crop_y1, &crop_x2, &crop_y2 )) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (crop_x1 < 0 ) { crop_x1 = 0; } if (crop_y1 < 0 ) { crop_y1 = 0; } if (crop_x2 < 0 ) { crop_x2 = 0; } if (crop_y2 < 0 ) { crop_y2 = 0; } if (crop_x2 < crop_x1 ) { // swap do_crop = crop_x1; crop_x1=crop_x2; crop_x2=do_crop; } if (crop_y2 < crop_y1 ) { // swap do_crop = crop_y1; crop_y1=crop_y2; crop_y2=do_crop; } do_crop = 1; } #ifdef HAVE_MAGICK if (strncasecmp(line, "GAMMA", 5) == 0) imagemagick_options.gamma_flag = sscanf(line + 6, "%f,%f,%f", &imagemagick_options.r_gamma, &imagemagick_options.g_gamma, &imagemagick_options.b_gamma); if (strncasecmp(line, "CONTRAST", 8) == 0) { if (1 != sscanf(line + 9, "%d", &imagemagick_options.contrast)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } } if (strncasecmp(line, "NEGATE", 6) == 0) { if (1 != sscanf(line + 7, "%d", &imagemagick_options.negate)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } } if (strncasecmp(line, "EQUALIZE", 8) == 0) { imagemagick_options.equalize = 1; } if (strncasecmp(line, "NORMALIZE", 9) == 0) { imagemagick_options.normalize = 1; } if (strncasecmp(line, "LEVEL", 5) == 0) { xastir_snprintf(imagemagick_options.level, sizeof(imagemagick_options.level), "%s", line+6); } if (strncasecmp(line, "MODULATE", 8) == 0) { xastir_snprintf(imagemagick_options.modulate, sizeof(imagemagick_options.modulate), "%s", line+9); } #endif // HAVE_MAGICK } (void)fclose (f); } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } // // Check whether OpenStreetMap has been selected. If so, run off to // another routine to service this request. // if (OSMserver_flag == 1) { #ifdef HAVE_MAGICK // We need to send the "nocache" parameter to this function // for those instances when the received map is bad. // Later the GUI can implement a method for refreshing the // latest map and replacing the bad map in the cache. // // fileimg is the server URL, if specified. draw_OSM_map(w, filenm, destination_pixmap, fileimg, OSMstyle, nocache); #endif // HAVE_MAGICK return; } else if (OSMserver_flag == 2) { #ifdef HAVE_MAGICK // fileimg is the server URL, if specified. draw_OSM_tiles(w, filenm, destination_pixmap, fileimg, tileCache, OSMstyle, OSMtileExt); #endif // HAVE_MAGICK return; } // Check whether a WMS server has been selected. If so, run off // to another routine to service this request. // if (WMSserver_flag) { #ifdef HAVE_MAGICK // Pass the URL in "fileimg" draw_WMS_map(w, filenm, destination_pixmap, fileimg, trans_color_head, nocache); // Don't use cached version if non-zero #endif // HAVE_MAGICK return; } if (toporama_flag) { #ifdef HAVE_MAGICK // Pass all of the parameters to it. We'll need to use them // to call draw_geo_image_map() again shortly, after we // fetch the remote .geo file. // draw_toporama_map(w, dir, filenm, alert, alert_color, destination_pixmap, mdf, toporama_flag); #endif // HAVE_MAGICK return; } // DK7IN: I'm experimenting with the adjustment of topo maps with // Transverse Mercator projection. Those maps have equal scaling // in distance while we use equal scaling in degrees. // For now I use the map center as central meridian (I think that // is ok for mapblast), that will change with UTM and Gauss-Krueger // I have introduced new entries in the geo file for that... // I first adjust the x scaling depending on the latitude // Then I move points in y direction depending on the offset from // the central meridian. I hope I get that right with those // approximations. I have the correct formulas, but that will // be very computing intensive and result in slow map loading... // if (geo_datum[0] != '\0') // fprintf(stderr,"Map Datum: %s\n",geo_datum); // not used now... if (geo_projection[0] == '\0') // default xastir_snprintf(geo_projection, sizeof(geo_projection), "LatLon"); //fprintf(stderr,"Map Projection: %s\n",geo_projection); // (void)to_upper(geo_projection); if (strcasecmp(geo_projection,"TM") == 0) { map_proj = 1; // Transverse Mercator } else { map_proj = 0; // Lat/Lon, default } #ifdef HAVE_MAGICK if (terraserver_flag) { //http://terraservice.net/download.ashx?t=1&s=10&x=2742&y=26372&z=10&w=820&h=480 if (scale_y <= 4) { t_zoom = 10; // 1m/pixel t_scale = 200; } else if (scale_y <= 8) { t_zoom = 11; // 2m/pixel t_scale = 400; } else if (scale_y <= 16) { t_zoom = 12; // 4m/pixel t_scale = 800; } else if (scale_y <= 32) { t_zoom = 13; // 8m/pixel t_scale = 1600; } else if (scale_y <= 64) { t_zoom = 14; // 16m/pixel t_scale = 3200; } else if (scale_y <= 128) { t_zoom = 15; // 32m/pixel t_scale = 6400; } else { t_zoom = 16; // 64m/pixel t_scale = 12800; } top = -((NW_corner_latitude - 32400000l) / 360000.0); left = (NW_corner_longitude - 64800000l) / 360000.0; ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid, top, left, &top_n, &left_e, zstr0, sizeof(zstr0) ); if (1 != sscanf(zstr0, "%d", &z)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } bottom = -((SE_corner_latitude - 32400000l) / 360000.0); right = (SE_corner_longitude - 64800000l) / 360000.0; ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid, bottom, right, &bottom_n, &right_e, zstr1, sizeof(zstr1) ); // // NOTE: // POSSIBLE FUTURE ENHANCEMENT: // If zstr0 != zstr1, we have a viewscreen that crosses a UTM zone // boundary. Terraserver/Toposerver will only feed us a map for one // side of it or the other. It'd be VERY nice if some day we could // check for this condition and do two map loads instead of the one. // We'd need to stop drawing right at the boundary for each map // also, so that they'd tile together nicely. // map_top_n = (int)((top_n / t_scale) + 1) * t_scale; map_left_e = (int)((left_e / t_scale) + 0) * t_scale; utm_ups_to_ll(gDatum[D_NAD_83_CONUS].ellipsoid, map_top_n, map_left_e, zstr0, &top, &left); // Below here things can get messed up. We can end up with very // large and/or negative values for geo_image_width and/or // geo_image_height. Usually happens around UTM zone boundaries. // // Terraserver uses UTM coordinates for specifying the maps instead // of lat/long. Note that we're also not supposed to cross UTM // zones in our requests. // // t = 1 - 4, theme. 1=DOQ (aerial photo) // 2=DRG (topo) // 3=shaded relief // 4=Color photos/Urban areas // s = 10 - 16, scale. 10=1 meter/pixel. 11=2 meters/pixel. // x = UTM easting, center of image // y = UTM northing, center of image // z = 1 - 60, UTM zone, center of image // w = 50 - 2000, width in pixels // h = 50 - 2000, height in pixels // logo = 0/1, USGS logo in image if 1 // // This number gets messed up if we cross zones. UTM lines // are slanted, so we _can_ cross zones vertically! geo_image_height = abs( (((int)map_top_n - (int)bottom_n) * 200 / t_scale) ); // This number gets messed up if we cross zones geo_image_width = abs( (((int)right_e - (int)map_left_e) * 200 / t_scale) ); //fprintf(stderr,"\ngeo_image_height:%d\tmap_top_n:%0.1f\tbottom_n:%0.1f\tt_scale:%d\n", //geo_image_height, //map_top_n, //bottom_n, //t_scale); // map_top_n is the one that goes whacko, throwing off the height. // Check whether this is because we're crossing a UTM zone. We // _can_ cross zones vertically because the UTM lines are slanted. //fprintf(stderr,"geo_image_width:%d\tright_e:%0.1f\tmap_left_e:%0.1f\tt_scale:%d\n", //geo_image_width, //right_e, //map_left_e, //t_scale); // right_e is the one that goes whacko, throwing off the width. // Check whether this is because we're crossing a UTM zone. if (geo_image_height < 50) { geo_image_height = 50; } if (geo_image_width < 50) { geo_image_width = 50; } if (geo_image_height > 2000) { geo_image_height = geo_image_width; } if (geo_image_width > 2000) { geo_image_width = geo_image_height; } if (geo_image_height > 2000) { geo_image_height = geo_image_width; } if (geo_image_width > 2000) { geo_image_width = geo_image_height; } // map_width = right - left; // map_height = top - bottom; tp[0].img_x = 0; tp[0].img_y = 0; tp[0].x_long = 64800000l + (360000.0 * left); tp[0].y_lat = 32400000l + (360000.0 * (-top)); tp[1].img_x = geo_image_width - 1; tp[1].img_y = geo_image_height - 1; tp[1].x_long = 64800000l + (360000.0 * right); tp[1].y_lat = 32400000l + (360000.0 * (-bottom)); url_n = (int)(top_n / t_scale); // The request URL does not use the url_e = (int)(left_e / t_scale); // N/E of the map corner xastir_snprintf(fileimg, sizeof(fileimg), "http://terraservice.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d", // "http://terraserver-usa.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d", terraserver_flag, // 1, 2, 3, or 4 t_zoom, url_e, // easting, center of map url_n, // northing, center of map z, geo_image_width, geo_image_height); //http://terraservice.net/download.ashx?t=1&s=11&x=1384&y=13274&z=10&w=1215&h=560 //fprintf(stderr,"%s\n",fileimg); if (debug_level & 16) { fprintf(stderr,"URL: %s\n", fileimg); } } #endif // HAVE_MAGICK // // DK7IN: we should check what we got from the geo file // we use geo_image_width, but it might not be initialised... // and it's wrong if the '\n' is missing at the end... /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our map will soon be (after translating the * tiepoints to the corners if they're not already there): * * left edge of map = tp[0].x_long in Xastir format * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ map_c_L = tp[0].x_long - NW_corner_longitude; // map left coordinate map_c_T = tp[0].y_lat - NW_corner_latitude; // map top coordinate tp_c_dx = (long)(tp[1].x_long - tp[0].x_long);// Width between tiepoints tp_c_dy = (long)(tp[1].y_lat - tp[0].y_lat); // Height between tiepoints // Check for tiepoints being in wrong relation to one another if (tp_c_dx < 0) { tp_c_dx = -tp_c_dx; // New width between tiepoints } if (tp_c_dy < 0) { tp_c_dy = -tp_c_dy; // New height between tiepoints } if (debug_level & 512) { fprintf(stderr,"X tiepoint width: %ld\n", tp_c_dx); fprintf(stderr,"Y tiepoint width: %ld\n", tp_c_dy); } // Calculate step size per pixel map_c_dx = ((double) tp_c_dx / abs(tp[1].img_x - tp[0].img_x)); map_c_dy = ((double) tp_c_dy / abs(tp[1].img_y - tp[0].img_y)); // Scaled screen step size for use with XFillRectangle below scr_dx = (int) (map_c_dx / scale_x) + 1; scr_dy = (int) (map_c_dy / scale_y) + 1; if (debug_level & 512) { fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } // calculate top left map corner from tiepoints if (tp[0].img_x != 0) { tp[0].x_long -= (tp[0].img_x * map_c_dx); // map left edge longitude map_c_L = tp[0].x_long - NW_corner_longitude; // delta ?? tp[0].img_x = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 x: %d\t%lu\n", tp[0].img_x, tp[0].x_long); } } if (tp[0].img_y != 0) { tp[0].y_lat -= (tp[0].img_y * map_c_dy); // map top edge latitude map_c_T = tp[0].y_lat - NW_corner_latitude; tp[0].img_y = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 y: %d\t%lu\n", tp[0].img_y, tp[0].y_lat); } } // By this point, geo_image_width & geo_image_height have to // have been initialized to something. if ( (geo_image_width == 0) || (geo_image_height == 0) ) { if ( (strncasecmp ("http", fileimg, 4) == 0) || (strncasecmp ("ftp", fileimg, 3) == 0)) { // what to do for remote files... hmm... -cbell } else { #ifdef HAVE_MAGICK GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", fileimg); if (debug_level & 16) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { fprintf(stderr,"1 "); fprintf(stderr,"File %s could not be read\n",image_info->filename); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = PingImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 16) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } geo_image_width = image->magick_columns; geo_image_height = image->magick_rows; // close and clean up imagemagick if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); #endif // HAVE_MAGICK } } // fprintf(stderr, "Geo: %s: size %ux%u.\n",file, geo_image_width, geo_image_height); // if that did not generate a valid size, bail out... if ( (geo_image_width == 0) || (geo_image_height == 0) ) { fprintf(stderr,"*** Skipping '%s', IMAGESIZE tag missing or incorrect. ***\n",file); fprintf(stderr,"Perhaps no XPM/ImageMagick/GraphicsMagick library support is installed?\n"); return; } // calculate bottom right map corner from tiepoints // map size is geo_image_width / geo_image_height if (tp[1].img_x != (geo_image_width - 1) ) { tp[1].img_x = geo_image_width - 1; tp[1].x_long = tp[0].x_long + (tp[1].img_x * map_c_dx); // right if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 x: %d\t%lu\n", tp[1].img_x, tp[1].x_long); } } if (tp[1].img_y != (geo_image_height - 1) ) { tp[1].img_y = geo_image_height - 1; tp[1].y_lat = tp[0].y_lat + (tp[1].img_y * map_c_dy); // bottom if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 y: %d\t%lu\n", tp[1].img_y, tp[1].y_lat); } } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. if (terraserver_flag) { // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level } else { index_update_xastir(filenm, // Filename only tp[1].y_lat, // Bottom tp[0].y_lat, // Top tp[0].x_long, // Left tp[1].x_long, // Right 0); // Default Map Level } // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check whether map is inside our current view // bottom top left right if (!map_visible (tp[1].y_lat, tp[0].y_lat, tp[0].x_long, tp[1].x_long)) { if (debug_level & 16) { fprintf(stderr,"Map not in current view, skipping: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr," Map: lat0:%ld\t lon0:%ld\t lat1:%ld\t lon1:%ld\n", tp[0].y_lat, tp[0].x_long, tp[1].y_lat, tp[1].x_long); fprintf(stderr,"Screen: NWlat:%ld\tNWlon:%ld\tSElat:%ld\tSElon:%ld\n", NW_corner_latitude, NW_corner_longitude, SE_corner_latitude, SE_corner_longitude); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } return; // Skip this map #ifdef FUZZYRASTER } else if (((float)(map_c_dx/scale_x) > rasterfuzz) || ((float)(scale_x/map_c_dx) > rasterfuzz) || ((float)(map_c_dy/scale_y) > rasterfuzz) || ((float)(scale_y/map_c_dy) > rasterfuzz)) { fprintf(stderr,"Skipping fuzzy map %s with sx=%f,sy=%f.\n", file, (float)(map_c_dx/scale_x),(float)(map_c_dy/scale_y)); return; #endif //FUZZYRASTER } else if (debug_level & 16) { fprintf(stderr,"Loading imagemap: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading/Indexing ... #ifndef NO_XPM atb.valuemask = 0; #endif // NO_XPM HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Best here would be to add the process ID or user ID to the filename // (to keep the filename distinct for different users), and to check // the timestamp on the map file. If it's older than xx minutes, go // get another one. Make sure to delete the temp files when closing // Xastir. It'd probably be good to check for old files and delete // them when starting Xastir as well. // Check to see if we have to use "wget" to go get an internet map if ( (strncasecmp ("http", fileimg, 4) == 0) || (strncasecmp ("ftp", fileimg, 3) == 0) || (terraserver_flag) ) { #ifdef HAVE_MAGICK char *ext; if (debug_level & 16) { fprintf(stderr,"ftp or http file: %s\n", fileimg); } if (terraserver_flag) { ext = "jpg"; } else { ext = get_map_ext(fileimg); // Use extension to determine image type } if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (nocache || map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } // Simulate a cache miss map_cache_return = 1; } else { // Look for the file in the cache map_cache_return = map_cache_get(fileimg,local_filename); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: %d\n", map_cache_return); } // If nocache is non-zero, we're supposed to refresh the map // at intervals. Don't use a cached version of the map in // that case. // if (nocache || map_cache_return != 0 ) { // Caching not requested or cached file not found. We // must snag the remote file via libcurl or wget. if (nocache) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext); } else { cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, sizeof(local_filename), "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, ext); free(cache_file_id); } #else // USE_MAP_CACHE xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same // name. This avoids the problem of having an old map image // here and the code trying to display it when the download // fails. unlink( local_filename ); if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } #ifdef USE_MAP_CACHE // Cache the map only if map_refresh_interval_temp is zero if (!map_refresh_interval_temp) { map_cache_put(fileimg,local_filename); } } // end if is cached #endif // MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); #endif // HAVE_MAGICK } else { //fprintf(stderr,"Not ftp or http file\n"); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. xastir_snprintf(file, sizeof(file), "%s", fileimg); } //fprintf(stderr,"File = %s\n",file); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // The status line is not updated yet, probably 'cuz we're too busy // getting the map in this thread and aren't redrawing? #ifdef HAVE_MAGICK GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 16) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { fprintf(stderr,"2 "); fprintf(stderr,"File %s could not be read\n",image_info->filename); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 16) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } /* if (image->colorspace != RGBColorspace) { fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); if (image) DestroyImage(image); if (image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); return; } */ width = image->columns; height = image->rows; if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } // gamma setup if (imagemagick_options.gamma_flag == 0 || imagemagick_options.gamma_flag == 1) { if (imagemagick_options.gamma_flag == 0) // if not set in file, set to 1.0 { imagemagick_options.r_gamma = 1.0; } imagemagick_options.gamma_flag = 1; // set flag to do gamma imagemagick_options.r_gamma += imagemagick_gamma_adjust; if (imagemagick_options.r_gamma > 0.95 && imagemagick_options.r_gamma < 1.05) { imagemagick_options.gamma_flag = 0; // don't bother if near 1.0 } else if (imagemagick_options.r_gamma < 0.1) { imagemagick_options.r_gamma = 0.1; // 0.0 is black and negative is really wacky } xastir_snprintf(gamma, sizeof(gamma), "%.1f", imagemagick_options.r_gamma); } else if (imagemagick_options.gamma_flag == 3) { // No checking if you specify 3 channel gamma correction, so you can try negative // numbers, etc. if you wish. imagemagick_options.gamma_flag = 1; // set flag to do gamma imagemagick_options.r_gamma += imagemagick_gamma_adjust; imagemagick_options.g_gamma += imagemagick_gamma_adjust; imagemagick_options.b_gamma += imagemagick_gamma_adjust; xastir_snprintf(gamma, sizeof(gamma), "%.1f,%.1f,%.1f", imagemagick_options.r_gamma, imagemagick_options.g_gamma, imagemagick_options.b_gamma); } else { imagemagick_options.gamma_flag = 0; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.gamma_flag) { if (debug_level & 16) { fprintf(stderr,"gamma=%s\n", gamma); } GammaImage(image, gamma); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.contrast != 0) { if (debug_level & 16) { fprintf(stderr,"contrast=%d\n", imagemagick_options.contrast); } ContrastImage(image, imagemagick_options.contrast); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.negate != -1) { if (debug_level & 16) { fprintf(stderr,"negate=%d\n", imagemagick_options.negate); } NegateImage(image, imagemagick_options.negate); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.equalize) { if (debug_level & 16) { fprintf(stderr,"equalize"); } EqualizeImage(image); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.normalize) { if (debug_level & 16) { fprintf(stderr,"normalize"); } NormalizeImage(image); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.level[0] != '\0') { if (debug_level & 16) { fprintf(stderr,"level=%s\n", imagemagick_options.level); } LevelImage(image, imagemagick_options.level); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.modulate[0] != '\0') { if (debug_level & 16) { fprintf(stderr,"modulate=%s\n", imagemagick_options.modulate); } ModulateImage(image, imagemagick_options.modulate); } /* // Else check the menu option for raster intensity else if (raster_map_intensity < 1.0) { char tempstr[30]; int temp_i; temp_i = (int)(raster_map_intensity * 100.0); xastir_snprintf(tempstr, sizeof(tempstr), "%d, 100, 100", temp_i); //fprintf(stderr,"Modulate: %s\n", tempstr); ModulateImage(image, tempstr); } */ if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } // crop image: if we just use CropImage(), then the tiepoints will be off // make border pixels transparent. // cbell - this is a first attempt, it will be integrated into the // lower loops to speed them up... if ( do_crop) { int x, y; //PixelPacket target; PixelPacket *q; // target=GetOnePixel(image,0,0); for (y=0; y < (long) image->rows; y++) { #if defined(HAVE_GRAPHICSMAGICK) q=GetImagePixels(image,0,y,image->columns,1); #else q=GetAuthenticPixels(image,0,y,image->columns,1,&exception); #endif if (q == (PixelPacket *) NULL) { fprintf(stderr, "GetImagePixels Failed....\n"); } for (x=0; x < (int) image->columns; x++) { if ( (x < crop_x1) || (x > crop_x2) || (y < crop_y1) || (y > crop_y2)) { q->opacity=(Quantum) 1; } q++; } #if defined(HAVE_GRAPHICSMAGICK) if (!SyncImagePixels(image)) { fprintf(stderr, "SyncImagePixels Failed....\n"); } #else if (!SyncAuthenticPixels(image,&exception)) { fprintf(stderr, "SyncImagePixels Failed....\n"); } #endif } } // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, &exception) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows,&exception); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (debug_level & 16) #ifdef HAVE_GRAPHICSMAGICK fprintf(stderr,"Colors = %d\n", (int)image->colors); #else // HAVE_GRAPHICSMAGICK fprintf(stderr,"Colors = %ld\n", image->colors); #endif // HAVE_GRAPHICSMAGICK // Set up our own version of the color map. if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { int leave_unchanged = 0; // Need to check how to do this for ANY image, as ImageMagick can read in all sorts // of image files temp_pack = image->colormap[l]; if (debug_level & 16) fprintf(stderr,"Colormap color is %1.2f %1.2f %1.2f \n", (float)temp_pack.red, (float)temp_pack.green, (float)temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as Quantum's. Quantum // is defined in /usr/include/magick/image.h as either an unsigned short or an // unsigned char, depending on what "configure" decided when ImageMagick was installed. // We can determine which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/magick_config.h { if (debug_level & 16) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red; my_colors[l].green = temp_pack.green; my_colors[l].blue = temp_pack.blue; } else // QuantumDepth = 8 { if (debug_level & 16) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = temp_pack.red * 256; my_colors[l].green = temp_pack.green * 256; my_colors[l].blue = temp_pack.blue * 256; } // Take care not to screw up the transparency value by // the raster_map_intensity multiplication factor. if ( trans_color_head ) { //fprintf(stderr,"Checking for transparency\n"); // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (check_trans(my_colors[l],trans_color_head) ) { // Found a transparent color. Leave it alone. leave_unchanged++; //fprintf(stderr,"Found transparency\n"); // We never get here! } } // Use the map_intensity value if it's not a transparent // color we're dealing with. if (!leave_unchanged) { my_colors[l].red = my_colors[l].red * raster_map_intensity; my_colors[l].green = my_colors[l].green * raster_map_intensity; my_colors[l].blue = my_colors[l].blue * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (debug_level & 16) fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG if (debug_level & 16) { fprintf(stderr,"Image size %d %d\n", width, height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"is Gray Image = %i\n", IsGrayImage( image, &exception )); fprintf(stderr,"is Monochrome Image = %i\n", IsMonochromeImage( image, &exception )); //fprintf(stderr,"is Opaque Image = %i\n", IsOpaqueImage( image, &exception )); //fprintf(stderr,"is PseudoClass = %i\n", image->storage_class == PseudoClass); fprintf(stderr,"image matte is %i\n", image->matte); fprintf(stderr,"Colorspace = %i\n", image->colorspace); if (image->colorspace == UndefinedColorspace) { fprintf(stderr,"Class Type = Undefined\n"); } else if (image->colorspace == RGBColorspace) { fprintf(stderr,"Class Type = RGBColorspace\n"); } else if (image->colorspace == GRAYColorspace) { fprintf(stderr,"Class Type = GRAYColorspace\n"); } else if (image->colorspace == sRGBColorspace) { fprintf(stderr,"Class Type = sRGBColorspace\n"); } } #else // HAVE_MAGICK // We don't have ImageMagick libs compiled in, so use the // XPM library instead, but only if we HAVE XPM. #ifndef NO_XPM HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check whether file has .xpm or .xpm.Z or .xpm.gz at the end. // If not, don't use the XpmReadFileToImage call below. if ( !strstr(filenm,"xpm") && !strstr(filenm,"XPM") && !strstr(filenm,"Xpm") ) { fprintf(stderr, "Error: File format not supported by XPM library: %s\n", filenm); return; } /* XpmReadFileToImage is the call we wish to avoid if at all * possible. On large images this can take quite a while. We * check above to see whether the image is inside our viewport, * and if not we skip loading the image. */ if (! XpmReadFileToImage (XtDisplay (w), file, &xi, NULL, &atb) == XpmSuccess) { fprintf(stderr,"ERROR loading %s\n", file); if (xi) { XDestroyImage (xi); } return; } if (debug_level & 16) { fprintf(stderr,"Image size %d %d\n", (int)atb.width, (int)atb.height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx, (int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (xi) { XDestroyImage (xi); } // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } width = atb.width; height = atb.height; #else // NO_XPM fprintf(stderr,"Xastir was configured with neither XPM library nor (Image/Graphics)Magick, cannot display map %s\n",filenm); #endif // NO_XPM #endif // HAVE_MAGICK // draw the image from the file out to the map screen // Get the border values for the X and Y for loops used // for the XFillRectangle call later. map_c_yc = (tp[0].y_lat + tp[1].y_lat) / 2; // vert center of map as reference // map_y_ctr = (long)(height / 2 +0.499); scale_x0 = get_x_scale(0,map_c_yc,scale_y); // reference scaling at vert map center map_c_xc = (tp[0].x_long + tp[1].x_long) / 2; // hor center of map as reference map_x_ctr = (long)(width / 2 +0.499); // scr_x_mc = (map_c_xc - NW_corner_longitude) / scale_x; // screen coordinates of map center // calculate map pixel range in y direction that falls into screen area // c_y_max = 0ul; map_y_min = map_y_max = 0l; for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_y_0; // update last map pixel in y // c_y_max = (unsigned long)c_y;// bottom map inside screen coordinate } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_y_0; // update first map pixel in y } } // fprintf(stderr,"map top: %ld bottom: %ld\n",tp[0].y_lat,tp[1].y_lat); c_y_min = (unsigned long)(tp[0].y_lat + map_y_min * map_c_dy); // top map inside screen coordinate // // find the y coordinate nearest to the equator // c_y = 90*60*60*100; // Equator // if ((c_y_min>c_y && c_y_max>c_y) || (c_y_min abs(c_y_max-c_y)) // c_y = c_y_max; // north // else // c_y = c_y_min; // south // } // scale_x0 = get_x_scale(0,(long)c_y,scale_y); // calc widest map area in x // if (map_proj != 1) { // calculate map pixel range in x direction that falls into screen area map_x_min = map_x_max = 0l; for (map_x = 0, c_x = tp[0].x_long; map_x < (long)width; map_x++, c_x += map_c_dx) { scr_x = (c_x - NW_corner_longitude)/ scale_x; // current screen position if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_x; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_x; // update first map pixel in x } } c_x_min = (unsigned long)(tp[0].x_long + map_x_min * map_c_dx); // left map inside screen coordinate // } // for (scr_y = scr_y_min; scr_y <= scr_y_max;scr_y++) { // screen lines // } // test = 1; // DK7IN: debuging scr_yp = -1; scr_c_xr = SE_corner_longitude; c_dx = map_c_dx; // map pixel width scale_xa = scale_x0; // the compiler likes it ;-) // for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { // scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position map_done = 0; map_act = 0; map_seen = 0; scr_y = screen_height - 1; #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG if (check_interrupt( #ifdef HAVE_MAGICK image, image_info, &exception, #else // HAVE_MAGICK xi, #endif // HAVE_MAGICK &da, &pixmap, &gc, screen_width, screen_height)) { return; } // loop over map pixel rows for (map_y_0 = map_y_min, c_y = (double)c_y_min; (map_y_0 <= map_y_max) || (map_proj == 1 && !map_done && scr_y < screen_height); map_y_0++, c_y += map_c_dy) { if (check_interrupt( #ifdef HAVE_MAGICK image, image_info, &exception, #else // HAVE_MAGICK xi, #endif // HAVE_MAGICK &da, &pixmap, &gc, screen_width, screen_height)) { return; } scr_y = (c_y - NW_corner_latitude) / scale_y; if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y if (map_proj == 1) // Transverse Mercator correction in x { scale_xa = get_x_scale(0,(long)c_y,scale_y); // recalc scale_x for current y c_dx = map_c_dx * scale_xa / scale_x0; // adjusted map pixel width map_x_min = map_x_ctr - (map_c_xc - NW_corner_longitude) / c_dx; if (map_x_min < 0) { map_x_min = 0; } c_x_min = map_c_xc - (map_x_ctr - map_x_min) * c_dx; map_x_max = map_x_ctr - (map_c_xc - scr_c_xr) / c_dx; if (map_x_max > (long)width) { map_x_max = width; } scr_dx = (int) (c_dx / scale_x) + 1; // at least 1 pixel wide } // if (c_y == (double)c_y_min) { // first call // fprintf(stderr,"map: min %ld ctr %ld max %ld, c_dx %ld, c_x_min %ld, c_y_min %ld\n",map_x_min,map_x_ctr,map_x_max,(long)c_dx,c_x_min,c_y_min); // } scr_xp = -1; // loop over map pixel columns map_act = 0; scale_x_nm = calc_dscale_x(0,(long)c_y) / 1852.0; // nm per Xastir coordinate for (map_x = map_x_min, c_x = (double)c_x_min; map_x <= map_x_max; map_x++, c_x += c_dx) { scr_x = (c_x - NW_corner_longitude) / scale_x; if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x if (map_proj == 1) // Transverse Mercator correction in y { // DK7IN-- dist = (90*60 - (c_y / 6000.0)); // equator distance in nm // ?? 180W discontinuity! not done yet ew_ofs = (c_x - (double)map_c_xc) * scale_x_nm; // EW offset from center in nm //corrfact = (map_y_0 - map_y_ctr)/(2*map_y_ctr); // 0..50% //corrfact = fabs(ew_ofs/dist)*3.0; //corrfact = 1.0-1.0*(0.5*map_y_0 / map_y_ctr); corrfact = 1.0; c_y_a = (fabs(dist) - sqrt((double)(dist*dist - ew_ofs*ew_ofs)))*6000.0; // in Xastir units if (dist < 0) // S { map_y = map_y_0 + (long)(corrfact*c_y_a / map_c_dy); // coord per pixel } else // N { map_y = map_y_0 - (long)(corrfact*c_y_a / map_c_dy); } // if (test < 10) { // fprintf(stderr,"dist: %ldkm, ew_ofs: %ldkm, dy: %ldkm\n",(long)(1.852*dist),(long)(1.852*ew_ofs),(long)(1.852*c_y_a/6000.0)); // fprintf(stderr," corrfact: %f, mapy0: %ld, mapy: %ld\n",corrfact,map_y_0,map_y); // test++; // } } else { map_y = map_y_0; } if (map_y >= 0 && map_y <= tp[1].img_y) // check map boundaries in y direction { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // DK7IN-- //----- copy pixel from map to screen --------------------- // if (c_y == (double)c_y_min && (scr_x < 5 || (c_x == (double)c_x_min))) { // first call // fprintf(stderr,"map: x %ld y %ld scr: x %ld y %ld dx %d, dy %d\n",map_x,map_y,scr_x,scr_y,scr_dx,scr_dy); // fprintf(stderr,"color: %ld\n",XGetPixel (xi, map_x, map_y)); // // 65529 // } // now copy a pixel from the map image to the screen #ifdef HAVE_MAGICK l = map_x + map_y * image->columns; trans_skip = 1; // possibly transparent if (image->storage_class == PseudoClass) { if ( trans_color_head && check_trans(my_colors[(int)index_pack[l]],trans_color_head) ) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); trans_skip = 0; // draw it } } else { // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); if ( trans_color_head && check_trans(my_colors[0],trans_color_head) ) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); trans_skip = 0; // draw it } } #else // HAVE_MAGICK (void)XSetForeground (XtDisplay (w), gc, XGetPixel (xi, map_x, map_y)); #endif // HAVE_MAGICK // Skip drawing if a transparent pixel #ifdef HAVE_MAGICK if ( pixel_pack[l].opacity == 0 && !trans_skip ) // skip transparent #else // HAVE_MAGICK if (!trans_skip) // skip transparent #endif // HAVE_MAGICK (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } // check map boundaries in y direction } } // loop over map pixel columns if (map_seen && !map_act) { map_done = 1; } } } // loop over map pixel rows #ifdef HAVE_MAGICK if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); #else // HAVE_MAGICK if (xi) { XDestroyImage (xi); } #endif // HAVE_MAGICK #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG #endif // NO_GRAPHICS } Xastir-Release-2.2.2/src/map_gnis.c000066400000000000000000001332741501463444000171100ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } //NOTE: This function has a problem if a non-gnis file is labeled //with a ".gnis" extension. It causes a segfault in Xastir. More //error checking needs to be done in order to prevent this. // draw_gnis_map() // // Allows drawing a background map of labels for the viewport. // Example format (old): // "WA","Abbey View Memorial Park","cemetery","Snohomish","53","061","474647N","1221650W","47.77972","-122.28056","","","","","420","","Edmonds East" // // Example format (new): // 376016|ID|12th Ave Drain|stream|Canyon|16|027|433107N|1163348W|43.51861|-116.56333||||||||Nampa // // These types of files are available from http://geonames.usgs.gov/ // under "Download State Gazetteer Data - Available Via Anonymous FTP". // A typical filename would be: "WA_Features_20090401.zip". Do not get the other // types of files which are columnar. The files that we parse are // pipe-delimited. // void draw_gnis_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags * UNUSED(mdf) ) { char file[MAX_FILENAME]; // Complete path/name of GNIS file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of GNIS file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char name[200]; char type[100]; char county[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; long min_lat, min_lon, max_lat, max_lon; int ok; long x,y; char symbol_table, symbol_id, symbol_over; unsigned long bottom_extent = 0l; unsigned long top_extent = 0l; unsigned long left_extent = 0l; unsigned long right_extent = 0l; char status_text[MAX_FILENAME]; int count = 0; //fprintf(stderr,"draw_gnis_map starting: %s/%s\n",dir,filenm); xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } // Screen view min_lat = SE_corner_latitude; max_lat = NW_corner_latitude; min_lon = NW_corner_longitude; max_lon = SE_corner_longitude; // The map extents in the map index are checked in draw_map to // see whether we should draw the map at all. // Update the statusline for this map name // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); } statusline(status_text,0); // Loading/Indexing ... HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* Latest pipe-delimited format from USGS (as of 08/12/2004): ---------------------------------------------------------- Feature ID Number (FID) State Alpha Code Feature Name Feature Type County Name State Number Code (FIPS Code) County Number Code (FIPS Code) Primary Latitude (DMS) Primary Longitude (DMS) Primary Latitude (decimal degrees) Primary Longitude (decimal degrees) Source Latitude (DMS) Source Longitude (DMS) Source Latitude (decimal degrees) Source Longitude (decimal degrees) Elevation Estimated Population Federal Status Cell Name */ // Attempt to open the file f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) // Loop through entire file { int lat_in_view = 0; count++; if ((count % 16) == 0) { // Check whether map drawing should be interrupted. // Check every 16 lines. // HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose (f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } } if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { // It is common for these lines to have incredible // numbers of spaces at the end, so trim them here. (void)remove_trailing_spaces(line); if (strlen(line) > 0) { // Default population, in case the field isn't // present in the file. xastir_snprintf(population,sizeof(population),"0"); // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // 2008 Format follows //FEATURE_ID|FEATURE_NAME|FEATURE_CLASS|STATE_ALPHA|STATE_NUMERIC|COUNTY_NAME|COUNTY_NUMERIC|PRIMARY_LAT_DMS|PRIM_LONG_DMS|PRIM_LAT_DEC|PRIM_LONG_DEC|SOURCE_LAT_DMS|SOURCE_LONG_DMS|SOURCE_LAT_DEC|SOURCE_LONG_DEC|ELEVATION|MAP_NAME|DATE_CREATED|DATE_EDITED //205110|Appalachian National Scenic Trail|Trail|PA|42|Perry|099|401920N|0770439W|40.3221113|-77.0775473|||||201|Wertzville|09/12/1979|05/19/2008 //NOTE: We handle running off the end of "line" //via the "continue" statement. Skip the line //if we don't find enough parameters while //parsing. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",j); // Find end of Feature Type field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",i); // Find end of State field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); // Find end of State Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Find end of County Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",j); // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); if (!isdigit((int)latitude[0])) // skip record if not { continue; // numeric! (e.g. "UNKNOWN") } //WE7U clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); if (!isdigit((int)longitude[0])) // skip record if not { continue; // numeric (e.g. UNKNOWN) } //WE7U clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Source Latitude field (DMS) (old // format) or elevation (new format) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (DMS) (old // format) or j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Elevation field i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Estimated Population field j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } if ( j != NULL ) { j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i); } FINISH: // There are two more fields (old format), // "Federal Status" and "Cell Name". We ignore // those for now. if (strlen(latitude) < 7) { continue; // We really don't have any latitude here. } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"draw_gnis_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); // Quick test of latitude to see if it's within // our view. If not and we're not doing // indexing, skip this line and go on to the // next. if (coord_lat <= min_lat && coord_lat >= max_lat) { // Latitude is ok lat_in_view++; } else // Latitude not in current view { // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Process the line 'cuz we're indexing } else // Not indexing so skip to the next { // line in the file continue; } } if (strlen(longitude) < 8) { continue; // We really don't have any longitude here. } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"draw_gnis_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Save the min/max extents of the file. We // should really initially set the extents // to the min/max for the Xastir coordinate // system, but in practice zeroes should // work just as well. // if ((coord_lat > (long)bottom_extent) || (bottom_extent == 0l)) { bottom_extent = coord_lat; } if ((coord_lat < (long)top_extent) || (top_extent == 0l)) { top_extent = coord_lat; } if ((coord_lon < (long)left_extent) || (left_extent == 0l)) { left_extent = coord_lon; } if ((coord_lon > (long)right_extent) || (right_extent == 0l)) { right_extent = coord_lon; } } // Now check whether this lat/lon is within our viewport. If it // is, draw a text label at that location. else if (coord_lon >= min_lon && coord_lon <= max_lon && lat_in_view) { clean_string(state); clean_string(name); clean_string(type); clean_string(county); clean_string(population); if (debug_level & 16) { fprintf(stderr,"%s\t%s\t%s\t%s\t%s\t%s\t\t", state, name, type, county, latitude, longitude); fprintf(stderr,"%s %s %s %s\t%s %s %s %s\t\t", lat_dd, lat_mm, lat_ss, lat_dir, long_dd, long_mm, long_ss, long_dir); fprintf(stderr,"%s\t%s\n", lat_str, long_str); } // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = coord_lon - NW_corner_longitude; y = coord_lat - NW_corner_latitude; x /= scale_x; y /= scale_y; ok = 1; /* set default symbol */ symbol_table = '/'; symbol_id = '.'; /* small x */ symbol_over = ' '; if (strcasecmp(type,"airport") == 0) { symbol_id = '^'; if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"arch") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"area") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"arroyo") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"basin") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bay") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"beach") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bench") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bend") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"building") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"canal") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cape") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cave") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cemetery") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"census") == 0) { /* if (scale_y > 50)*/ /* Census divisions */ ok = 0; } else if (strcasecmp(type,"channel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"church") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"civil") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cliff") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crater") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crossing") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"dam") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"falls") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"flat") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"forest") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gap") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"geyser") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"glacier") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gut") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"harbor") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"hospital") == 0) { symbol_id = 'h'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"island") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"isthmus") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lake") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lava") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"levee") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"locale") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"military") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"mine") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"oilfield") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"other") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"park") == 0) { symbol_table = '\\'; symbol_id = ';'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"pillar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"plain") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"po") == 0) { symbol_id = ']'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ppl") == 0) { symbol_id = '/'; if (scale_y > 20000) // Don't draw cities at zoom higher than 20,000 { ok = 0; } else if (scale_y > 4000) // Don't draw cities of less than 20,000 { if (atoi(population) < 50000) { ok = 0; } } else if (scale_y > 1500) // Don't draw cities of less than 10,000 { if (atoi(population) < 20000) { ok = 0; } } else if (scale_y > 750) // Don't draw cities of less than 5,000 { if (atoi(population) < 10000) { ok = 0; } } else if (scale_y > 200) // Don't draw cities { // of less than 1,000 if (atoi(population) < 1000) { ok = 0; //fprintf(stderr, // "Name: %s\tPopulation: %s\n",name, // population); } } } else if (strcasecmp(type,"range") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"rapids") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reserve") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reservoir") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"school") == 0) { symbol_id = 'K'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"sea") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"slope") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"spring") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"stream") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"summit") == 0) { if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"swamp") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"trail") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tower") == 0) { symbol_id = 'r'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tunnel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"valley") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"well") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"woods") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ruin") == 0) { if (scale_y > 50) { ok = 0; } } else { fprintf(stderr,"Something unusual found, Type:%s\tState:%s\tCounty:%s\tName:%s\n", type,state,county,name); } if (ok == 1) // If ok to draw it { symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)name, 0xf, 0x10, strlen(name)); } } else { //fprintf(stderr,"Not in viewport. Coordinates: %ld %ld\n",coord_lat,coord_lon); //fprintf(stderr,"Min/Max Lat: %ld %ld\n",min_lat,max_lat); //fprintf(stderr,"Min/Max Lon: %ld %ld\n",min_lon,max_lon); } } } } // End of while (void)fclose (f); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_extent, // Bottom top_extent, // Top left_extent, // Left right_extent, // Right 99999); // Default Map Level } } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (debug_level & 16) { fprintf(stderr,"Exiting draw_gnis_map\n"); } } // Search for a placename among GNIS files // // We need to search a file in the map directory that has the filename // STATE.gis, where STATE is from the "state" variable passed to us. // Search for the placename/county/state/type that the user requested. // Once found, center the map on that location or bring up a response // dialog that asks whether one wants to go there, and that dialog // provides info about the place found, with a possible selection // out of a list of matches. // Might also need to place a label at that position on the map in // case that GNIS file isn't currently selected. // int gnis_locate_place( Widget UNUSED(w), char *name_in, char *state_in, char *county_in, char *quad_in, char *type_in, char *filename_in, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50] ) { char file[MAX_FILENAME]; // Complete path/name of GNIS file FILE *f; // Filehandle of GNIS file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char state_in2[50]; char name[200]; char name_in2[50]; char type[100]; char type_in2[50]; char county[100]; char county_in2[50]; char quad[100]; char quad_in2[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; int ok; struct stat file_status; int my_count = 0; xastir_snprintf(file,sizeof(file),"%s",filename_in); if (debug_level & 16) { fprintf(stderr,"File: %s\n",file); } xastir_snprintf(name_in2,sizeof(name_in2),"%s",name_in); xastir_snprintf(state_in2,sizeof(state_in2),"%s",state_in); xastir_snprintf(county_in2,sizeof(county_in2),"%s",county_in); xastir_snprintf(quad_in2,sizeof(quad_in2),"%s",quad_in); xastir_snprintf(type_in2,sizeof(type_in2),"%s",type_in); // Convert State/Province to upper-case always (they're // always upper-case in the GNIS files from USGS. to_upper(state_in2); if (debug_level & 16) fprintf(stderr,"Name:%s\tState:%s\tCounty:%s\tQuad:%s\tType:%s\n", name_in,state_in2,county_in,quad_in,type_in); // If "Match Case" togglebutton is not set, convert the // rest of the keys to upper-case. if (!follow_case) { to_upper(name_in2); to_upper(county_in2); to_upper(quad_in2); to_upper(type_in2); } // Check status of the file if (stat(file, &file_status) < 0) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Check for regular file if (!S_ISREG(file_status.st_mode)) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Attempt to open the file f = fopen (file, "r"); if (f == NULL) { // "Can't open file" popup_message_always( langcode("POPEM00028"), filename_in ); return(0); } while (!feof (f)) // Loop through entire file { if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { if (strlen(line) > 0) { //NOTE: How do we handle running off the end of "line" while using "index"? // Short lines here can cause segfaults. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",j); clean_string(name); // Find end of Feature Type field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",i); clean_string(type); // Find end of State field i = index(++j,'|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); clean_string(state); // Find end of State Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of County Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",j); clean_string(county); // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (DMS) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude (DMS) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Estimated Population field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",j); clean_string(population); // Find end of Quad field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(quad,sizeof(quad),"%s",i); clean_string(quad); // If "Match Case" togglebutton is not set, convert // the data to upper-case before we do our compare. if (!follow_case) { to_upper(name); to_upper(state); to_upper(county); to_upper(quad); to_upper(type); } // Still need to code for the "Match Exact" togglebutton. // Now compare the input variables with those we've // parsed. If a match, bring up a list of items which // match. // ok = 1; if (get_match) // Looking for exact match { if (name_in2[0] != '\0') if (strcmp(name,name_in2) != 0) { ok = 0; } if (state_in2[0] != '\0') if (strcmp(state,state_in2) != 0) { ok = 0; } if (county_in2[0] != '\0') if (strcmp(county,county_in2) != 0) { ok = 0; } if (quad_in2[0] != '\0') if (strcmp(quad,quad_in2) != 0) { ok = 0; } if (type_in2[0] != '\0') if (strcmp(type,type_in2) != 0) { ok = 0; } } else // Look for substring in file, not exact match { if (name_in2[0] != '\0') if (strstr(name,name_in2) == NULL) { ok = 0; } if (state_in2[0] != '\0') if (strstr(state,state_in2) == NULL) { ok = 0; } if (county_in2[0] != '\0') if (strstr(county,county_in2) == NULL) { ok = 0; } if (quad_in2[0] != '\0') if (strstr(quad,quad_in2) == NULL) { ok = 0; } if (type_in2[0] != '\0') if (strstr(type,type_in2) == NULL) { ok = 0; } } if (ok) { if (debug_level & 16) { fprintf(stderr,"Match: %s,%s,%s,%s\n",name,state,county,type); } // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), name ); if (strlen(latitude) < 7) { continue; // We really don't have any latitude here. } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; if (strlen(longitude) < 8) { continue; // We really don't have any longitude here. } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); //set_map_position(w, coord_lat, coord_lon); // Fill in the array values with what we just // found, increment the counter. xastir_snprintf(match_array_name[my_count],200,"%s",name); match_array_lat[my_count] = coord_lat; match_array_long[my_count] = coord_lon; my_count++; // Check for a max array. Return if it is full. if (my_count > 50) { return(50); } } } } } return(my_count); } Xastir-Release-2.2.2/src/map_pop.c000066400000000000000000001330401501463444000167350ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } //NOTE: This function has a problem if a non-pop file is labeled //with a ".pop" extension. It causes a segfault in Xastir. More //error checking needs to be done in order to prevent this. // draw_pop_map() // // Allows drawing a background map of labels for the viewport. // Example format (old): // "WA","Abbey View Memorial Park","cemetery","Snohomish","53","061","474647N","1221650W","47.77972","-122.28056","","","","","420","","Edmonds East" // // Example format (new): // 376016|ID|12th Ave Drain|stream|Canyon|16|027|433107N|1163348W|43.51861|-116.56333||||||||Nampa // // These types of files are available from ftp://aprs.tamu.edu/ // A typical filename would be: "WA_deci.gz". Do not get the other // types of files which are columnar. The files that we parse are // pipe-delimited. // These files were originally from geonames.usgs.gov but the format changed // on that site from population to elevation and the display of populated sites // was severely broken by the new format. The population information should be // gathered from census.gov or other locations concerned with population mapping. // void draw_pop_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags * UNUSED(mdf) ) { char file[MAX_FILENAME]; // Complete path/name of pop file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of pop file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char name[200]; char type[100]; char county[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; long min_lat, min_lon, max_lat, max_lon; int ok; long x,y; char symbol_table, symbol_id, symbol_over; unsigned long bottom_extent = 0l; unsigned long top_extent = 0l; unsigned long left_extent = 0l; unsigned long right_extent = 0l; char status_text[MAX_FILENAME]; int count = 0; //fprintf(stderr,"draw_pop_map starting: %s/%s\n",dir,filenm); xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } // Screen view min_lat = SE_corner_latitude; max_lat = NW_corner_latitude; min_lon = NW_corner_longitude; max_lon = SE_corner_longitude; // The map extents in the map index are checked in draw_map to // see whether we should draw the map at all. // Update the statusline for this map name // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); } statusline(status_text,0); // Loading/Indexing ... HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* Latest pipe-delimited format from USGS (as of 08/12/2004): ---------------------------------------------------------- Feature ID Number (FID) State Alpha Code Feature Name Feature Type County Name State Number Code (FIPS Code) County Number Code (FIPS Code) Primary Latitude (DMS) Primary Longitude (DMS) Primary Latitude (decimal degrees) Primary Longitude (decimal degrees) Source Latitude (DMS) Source Longitude (DMS) Source Latitude (decimal degrees) Source Longitude (decimal degrees) Elevation Estimated Population Federal Status Cell Name */ // Attempt to open the file f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) // Loop through entire file { int lat_in_view = 0; count++; if ((count % 16) == 0) { // Check whether map drawing should be interrupted. // Check every 16 lines. // HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose (f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } } if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { // It is common for these lines to have incredible // numbers of spaces at the end, so trim them here. (void)remove_trailing_spaces(line); if (strlen(line) > 0) { // Default population, in case the field isn't // present in the file. xastir_snprintf(population,sizeof(population),"0"); // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria //NOTE: We handle running off the end of "line" //via the "continue" statement. Skip the line //if we don't find enough parameters while //parsing. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } // Find end of State field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j+1); //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",i+1); // Find end of Feature Type field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",j+1); // Find end of County Name field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",i+1); // Find end of State Number Code field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; // Find end of County Number Code field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Primary Latitude field (DDMMSSN) i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j+1); if (!isdigit((int)latitude[0])) // skip record if not { continue; // numeric! (e.g. "UNKNOWN") } //WE7U clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i+1); if (!isdigit((int)longitude[0])) // skip record if not { continue; // numeric (e.g. UNKNOWN) } //WE7U clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Source Latitude field (DMS) (old // format) or elevation (new format) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (DMS) (old // format) or j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Elevation field i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Estimated Population field j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } if ( j != NULL ) { j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i+1); } FINISH: // There are two more fields (old format), // "Federal Status" and "Cell Name". We ignore // those for now. if (strlen(latitude) < 7) { continue; // We really don't have any latitude here! } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"draw_pop_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); // Quick test of latitude to see if it's within // our view. If not and we're not doing // indexing, skip this line and go on to the // next. if (coord_lat <= min_lat && coord_lat >= max_lat) { // Latitude is ok lat_in_view++; } else // Latitude not in current view { // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Process the line 'cuz we're indexing } else // Not indexing so skip to the next { // line in the file continue; } } if (strlen(longitude) < 8) { continue; // We really don't have any latitude here! } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"draw_pop_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Save the min/max extents of the file. We // should really initially set the extents // to the min/max for the Xastir coordinate // system, but in practice zeroes should // work just as well. // if ((coord_lat > (long)bottom_extent) || (bottom_extent == 0l)) { bottom_extent = coord_lat; } if ((coord_lat < (long)top_extent) || (top_extent == 0l)) { top_extent = coord_lat; } if ((coord_lon < (long)left_extent) || (left_extent == 0l)) { left_extent = coord_lon; } if ((coord_lon > (long)right_extent) || (right_extent == 0l)) { right_extent = coord_lon; } } // Now check whether this lat/lon is within our viewport. If it // is, draw a text label at that location. else if (coord_lon >= min_lon && coord_lon <= max_lon && lat_in_view) { clean_string(state); clean_string(name); clean_string(type); clean_string(county); clean_string(population); if (debug_level & 16) { fprintf(stderr,"%s\t%s\t%s\t%s\t%s\t%s\t\t", state, name, type, county, latitude, longitude); fprintf(stderr,"%s %s %s %s\t%s %s %s %s\t\t", lat_dd, lat_mm, lat_ss, lat_dir, long_dd, long_mm, long_ss, long_dir); fprintf(stderr,"%s\t%s\n", lat_str, long_str); } // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = coord_lon - NW_corner_longitude; y = coord_lat - NW_corner_latitude; x /= scale_x; y /= scale_y; ok = 1; /* set default symbol */ symbol_table = '/'; symbol_id = '.'; /* small x */ symbol_over = ' '; if (strcasecmp(type,"airport") == 0) { symbol_id = '^'; if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"arch") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"area") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"arroyo") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"basin") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bay") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"beach") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bench") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bend") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"building") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"canal") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cape") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cave") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cemetery") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"census") == 0) { /* if (scale_y > 50)*/ /* Census divisions */ ok = 0; } else if (strcasecmp(type,"channel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"church") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"civil") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cliff") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crater") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crossing") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"dam") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"falls") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"flat") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"forest") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gap") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"geyser") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"glacier") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gut") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"harbor") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"hospital") == 0) { symbol_id = 'h'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"island") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"isthmus") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lake") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lava") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"levee") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"locale") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"military") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"mine") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"oilfield") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"other") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"park") == 0) { symbol_table = '\\'; symbol_id = ';'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"pillar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"plain") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"po") == 0) { symbol_id = ']'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ppl") == 0) { symbol_id = '/'; if (scale_y > 20000) // Don't draw cities at zoom higher than 20,000 { ok = 0; } else if (scale_y > 4000) // Don't draw cities of less than 20,000 { if (atoi(population) < 50000) { ok = 0; } } else if (scale_y > 1500) // Don't draw cities of less than 10,000 { if (atoi(population) < 20000) { ok = 0; } } else if (scale_y > 750) // Don't draw cities of less than 5,000 { if (atoi(population) < 10000) { ok = 0; } } else if (scale_y > 200) // Don't draw cities { // of less than 1,000 if (atoi(population) < 1000) { ok = 0; //fprintf(stderr, // "Name: %s\tPopulation: %s\n",name, // population); } } } else if (strcasecmp(type,"range") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"rapids") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reserve") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reservoir") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"school") == 0) { symbol_id = 'K'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"sea") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"slope") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"spring") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"stream") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"summit") == 0) { if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"swamp") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"trail") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tower") == 0) { symbol_id = 'r'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tunnel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"valley") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"well") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"woods") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ruin") == 0) { if (scale_y > 50) { ok = 0; } } else { fprintf(stderr,"Something unusual found, Type:%s\tState:%s\tCounty:%s\tName:%s\n", type,state,county,name); } if (ok == 1) // If ok to draw it { symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)name, 0xf, 0x10, strlen(name)); } } else { //fprintf(stderr,"Not in viewport. Coordinates: %ld %ld\n",coord_lat,coord_lon); //fprintf(stderr,"Min/Max Lat: %ld %ld\n",min_lat,max_lat); //fprintf(stderr,"Min/Max Lon: %ld %ld\n",min_lon,max_lon); } } } } // End of while (void)fclose (f); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_extent, // Bottom top_extent, // Top left_extent, // Left right_extent, // Right 99999); // Default Map Level } } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (debug_level & 16) { fprintf(stderr,"Exiting draw_pop_map\n"); } } // Search for a placename among pop files // // We need to search a file in the map directory that has the filename // STATE.gis, where STATE is from the "state" variable passed to us. // Search for the placename/county/state/type that the user requested. // Once found, center the map on that location or bring up a response // dialog that asks whether one wants to go there, and that dialog // provides info about the place found, with a possible selection // out of a list of matches. // Might also need to place a label at that position on the map in // case that pop file isn't currently selected. // int pop_locate_place( Widget UNUSED(w), char *name_in, char *state_in, char *county_in, char *quad_in, char *type_in, char *filename_in, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50] ) { char file[MAX_FILENAME]; // Complete path/name of pop file FILE *f; // Filehandle of pop file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char state_in2[50]; char name[200]; char name_in2[50]; char type[100]; char type_in2[50]; char county[100]; char county_in2[50]; char quad[100]; char quad_in2[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; int ok; struct stat file_status; int my_count = 0; xastir_snprintf(file,sizeof(file),"%s",filename_in); if (debug_level & 16) { fprintf(stderr,"File: %s\n",file); } xastir_snprintf(name_in2,sizeof(name_in2),"%s",name_in); xastir_snprintf(state_in2,sizeof(state_in2),"%s",state_in); xastir_snprintf(county_in2,sizeof(county_in2),"%s",county_in); xastir_snprintf(quad_in2,sizeof(quad_in2),"%s",quad_in); xastir_snprintf(type_in2,sizeof(type_in2),"%s",type_in); // Convert State/Province to upper-case always (they're // always upper-case in the pop files from USGS. to_upper(state_in2); if (debug_level & 16) fprintf(stderr,"Name:%s\tState:%s\tCounty:%s\tQuad:%s\tType:%s\n", name_in,state_in2,county_in,quad_in,type_in); // If "Match Case" togglebutton is not set, convert the // rest of the keys to upper-case. if (!follow_case) { to_upper(name_in2); to_upper(county_in2); to_upper(quad_in2); to_upper(type_in2); } // Check status of the file if (stat(file, &file_status) < 0) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Check for regular file if (!S_ISREG(file_status.st_mode)) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Attempt to open the file f = fopen (file, "r"); if (f == NULL) { // "Can't open file" popup_message_always( langcode("POPEM00028"), filename_in ); return(0); } while (!feof (f)) // Loop through entire file { if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { if (strlen(line) > 0) { //NOTE: How do we handle running off the end of "line" while using "index"? // Short lines here can cause segfaults. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } // Find end of State field i = index(++j,'|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); clean_string(state); //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",i); clean_string(name); // Find end of Feature Type field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",j); clean_string(type); // Find end of County Name field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",i); clean_string(county); // Find end of State Number Code field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (DMS) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude (DMS) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Elevation field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Estimated Population field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i); clean_string(population); // Snag Cell Name field (Quad name, last field) xastir_snprintf(quad,sizeof(quad),"%s",j+1); clean_string(quad); // If "Match Case" togglebutton is not set, convert // the data to upper-case before we do our compare. if (!follow_case) { to_upper(name); to_upper(state); to_upper(county); to_upper(quad); to_upper(type); } // Still need to code for the "Match Exact" togglebutton. // Now compare the input variables with those we've // parsed. If a match, bring up a list of items which // match. // ok = 1; if (get_match) // Looking for exact match { if (name_in2[0] != '\0') if (strcmp(name,name_in2) != 0) { ok = 0; } if (state_in2[0] != '\0') if (strcmp(state,state_in2) != 0) { ok = 0; } if (county_in2[0] != '\0') if (strcmp(county,county_in2) != 0) { ok = 0; } if (quad_in2[0] != '\0') if (strcmp(quad,quad_in2) != 0) { ok = 0; } if (type_in2[0] != '\0') if (strcmp(type,type_in2) != 0) { ok = 0; } } else // Look for substring in file, not exact match { if (name_in2[0] != '\0') if (strstr(name,name_in2) == NULL) { ok = 0; } if (state_in2[0] != '\0') if (strstr(state,state_in2) == NULL) { ok = 0; } if (county_in2[0] != '\0') if (strstr(county,county_in2) == NULL) { ok = 0; } if (quad_in2[0] != '\0') if (strstr(quad,quad_in2) == NULL) { ok = 0; } if (type_in2[0] != '\0') if (strstr(type,type_in2) == NULL) { ok = 0; } } if (ok) { if (debug_level & 16) { fprintf(stderr,"Match: %s,%s,%s,%s\n",name,state,county,type); } // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), name ); if (strlen(latitude) < 7) { continue; // We really don't have any latitude here! } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; if (strlen(longitude) < 8) { continue; // We really don't have any longitude here! } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); //set_map_position(w, coord_lat, coord_lon); // Fill in the array values with what we just // found, increment the counter. xastir_snprintf(match_array_name[my_count],200,"%s",name); match_array_lat[my_count] = coord_lat; match_array_long[my_count] = coord_lon; my_count++; // Check for a max array. Return if it is full. if (my_count > 50) { return(50); } } } } } return(my_count); } Xastir-Release-2.2.2/src/map_shp.c000066400000000000000000003417511501463444000167430ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * * Please see separate copyright notice attached to the * shape_ring_direction() function in this file. * * DBFAWK TODO: * - reload .dbfawk's when they've changed (or maps are reindexed) * - scale line widths based on zoom level (see city_flag, for example) * - allow multiple font sizes (font_size=small|medium|large|huge) * - allow multiple font faces? * - allow setting of map layer for individual shapes * - transparency * - allow setting fill_style (solid, stippled, etc.) * - do more config/ *.dbfawk files! * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #define CHECKREALLOC(m) if (!m) { fprintf(stderr, "***** Realloc Failed *****\n"); exit(0); } #ifdef HAVE_LIBSHP #include "awk.h" #include "dbfawk.h" #ifdef HAVE_SHAPEFIL_H #include #else // HAVE_SHAPEFIL_H #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else // HAVE_LIBSHP_SHAPEFIL_H #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H extern int npoints; /* tsk tsk tsk -- globals */ #include #include "shp_hash.h" // Must be last include file #include "leak_detection.h" static int *RTree_hitarray=NULL; int RTree_hitarray_size=0; int RTree_hitarray_index=0; //This trivial routine is used by the RTreeSearch as a callback when it finds // a match. int RTreeSearchCallback(int id, void* UNUSED(arg) ) { if (!RTree_hitarray) { RTree_hitarray = (int *)malloc(1000*sizeof(int)); RTree_hitarray_size=1000; } if (RTree_hitarray_size <= RTree_hitarray_index) { int *ptr; ptr = realloc(RTree_hitarray, (RTree_hitarray_size+1000)*sizeof(int)); CHECKREALLOC(ptr); // fatal error if we can't get 'em :-( RTree_hitarray=ptr; RTree_hitarray_size += 1000; //fprintf(stderr,"Hitarray now at %d\n",RTree_hitarray_size); } RTree_hitarray[RTree_hitarray_index++]=id-1; return 1; // signal to keep searching for more matches } /******************************************************************* * create_shapefile_map() * * Do we have a need for storing date/ time/ speed/ course/ * altitude/ heard-direct for each point? Altitude could be stored * in the Z space. If we store a station's trail as an SHPT_POINT * file, then we can associate a bunch of info with each point: * date/time, altitude, course, speed, status/comments, path, port, * heard-direct, weather data, etc. We could also dynamically * change the number of fields based on what we have a need to * store, using field-names to determine what's stored in each file. * * shapefile_name is the path/name of the map file we wish to create * (without the extension). * * type = SHPT_POINT, SHPT_ARC, SHPT_POLYGON, * SHPT_MULTIPOINT, etc. * * quantity equals the number of vertices we have. * * padfx/padfy/padfz are the vertices themselves, in double format. *******************************************************************/ void create_shapefile_map(char *dir, char *shapefile_name, int type, int quantity, double *padfx, double *padfy, double *padfz, int add_timestamp, char * shape_label) { SHPHandle my_shp_handle; SHPObject *my_object; DBFHandle my_dbf_handle; char timedatestring[101]; int index; int max_objects = 1; char credit_string[] = "Created by Xastir, http://www.xastir.org"; char temp_shapefile_name[MAX_FILENAME]; char temp_prj_name[MAX_FILENAME]; if (debug_level & 16) { fprintf(stderr,"create_shapefile_map\n"); fprintf(stderr,"%s %s %d %d %d\n", dir, shapefile_name, type, quantity, add_timestamp); } if (quantity == 0) { // No reason to make a map if we don't have any points. return; } // Get the time/datestamp get_timestamp(timedatestring); if (add_timestamp) // Prepend a timestamp to the filename { int ii; xastir_snprintf(temp_shapefile_name, sizeof(temp_shapefile_name), "%s%s_%s", dir, timedatestring, shapefile_name); // Change spaces and colons to underlines for (ii = 0; ii < (int)strlen(temp_shapefile_name); ii++) { if (temp_shapefile_name[ii] == ' ' || temp_shapefile_name[ii] == ':') { temp_shapefile_name[ii] = '_'; } } } else // Use the filename directly, no timestamp { xastir_snprintf(temp_shapefile_name, sizeof(temp_shapefile_name), "%s%s", dir, shapefile_name); } if (debug_level & 16) { fprintf(stderr, "Creating file %s\n", temp_shapefile_name); } // Create empty .shp/.shx/.dbf files // my_shp_handle = SHPCreate(temp_shapefile_name, type); my_dbf_handle = DBFCreate(temp_shapefile_name); // Check whether we were able to open these handles if ((my_shp_handle == NULL) || (my_dbf_handle == NULL)) { // Probably write-protected directory fprintf(stderr, "Could not create shapefile %s\n", temp_shapefile_name); return; } // Write out a WKT in a .prj file to go with this shapefile. strcpy(temp_prj_name, temp_shapefile_name); temp_prj_name[sizeof(temp_prj_name)-1] = '\0'; // Terminate string strcat(temp_prj_name, ".prj"); temp_prj_name[sizeof(temp_prj_name)-1] = '\0'; // Terminate string xastirWriteWKT(temp_prj_name); // Create the different fields we'll use to store the // attributes: // // Add a credits field and set the length. Field 0. DBFAddField(my_dbf_handle, "Credits", FTString, strlen(credit_string) + 1, 0); // // Add a date/time field and set the length. Field 1. DBFAddField(my_dbf_handle, "DateTime", FTString, strlen(timedatestring) + 1, 0); // Add a label field DBFAddField(my_dbf_handle, "Label", FTString, strlen(shape_label) + 1, 0); // Note that if were passed additional parameters that went // along with the lat/long/altitude points, we could write those // into the DBF file in the loop below. We would have to change // from a polygon to a point filetype though. // Populate the files with objects and attributes. Perform this // loop once for each object. // for (index = 0; index < max_objects; index++) { // Create a temporary object from the vertices my_object = SHPCreateSimpleObject( type, quantity, padfx, padfy, padfz); // Write out the vertices SHPWriteObject( my_shp_handle, -1, my_object); // Destroy the temporary object SHPDestroyObject(my_object); // Note that with the current setup the below really only get // written into the file once. Check it with dbfinfo/dbfdump. // Write the credits attributes DBFWriteStringAttribute( my_dbf_handle, index, 0, credit_string); // Write the time/date string DBFWriteStringAttribute( my_dbf_handle, index, 1, timedatestring); // Write the label string DBFWriteStringAttribute( my_dbf_handle, index, 2, shape_label); } // Close the .shp/.shx/.dbf files SHPClose(my_shp_handle); DBFClose(my_dbf_handle); } // Function which creates a Shapefile map from an APRS trail. // // Navigate through the linked list of TrackRow structs to pick out // the lat/long and write them into arrays of floats. We then pass // those arrays to create_shapefile_map(). // void create_map_from_trail(char *call_sign) { DataRow *p_station; // Find the station in our database. Count the number of points // for that station first, then allocate some arrays to hold // that quantity of points. Stuff the lat/long into the arrays // and then call create_shapefile_map(). // if (search_station_name(&p_station, call_sign, 1)) { int count; int ii; TrackRow *ptr; char temp[MAX_FILENAME]; char temp2[MAX_FILENAME]; double *x; double *y; double *z; char temp_base_dir[MAX_VALUE]; count = 0; ptr = p_station->oldest_trackpoint; while (ptr != NULL) { count++; ptr = ptr->next; } //fprintf(stderr, "Quantity of points: %d\n", count); if (count == 0) { // No reason to make a map if we don't have any points // in the track list. return; } // We know how many points are in the linked list. Allocate // arrays to hold the values. x = (double *) malloc( count * sizeof(double) ); y = (double *) malloc( count * sizeof(double) ); z = (double *) malloc( count * sizeof(double) ); CHECKMALLOC(x); CHECKMALLOC(y); CHECKMALLOC(z); // Fill in the values. We need to convert from Xastir // coordinate system to lat/long doubles as we go. ptr = p_station->oldest_trackpoint; ii = 0; while ((ptr != NULL) && (ii < count) ) { // Convert from Xastir coordinates to lat/long // Convert to string convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DEC_DEG); // Convert to double and stuff into array of doubles if (1 != sscanf(temp, "%lf", &x[ii])) { fprintf(stderr,"create_map_from_trail:sscanf parsing error\n"); } // If longitude string contains "W", make the final // result negative. if (index(temp, 'W')) { x[ii] = x[ii] * -1.0; } // Convert to string convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DEC_DEG); // Convert to double and stuff into array of doubles if (1 != sscanf(temp, "%lf", &y[ii])) { fprintf(stderr,"create_map_from_trail:sscanf parsing error\n"); } // If latitude string contains "S", make the final // result negative. if (index(temp, 'S')) { y[ii] = y[ii] * -1.0; } z[ii] = ptr->altitude; // Altitude (meters), undefined=-99999 ptr = ptr->next; ii++; } // Create a Shapefile from the APRS trail. Write it into // "~/.xastir/tracklogs" and add a date/timestamp to the end. // xastir_snprintf(temp, sizeof(temp), "%s/", get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir))); // Create filename xastir_snprintf(temp2, sizeof(temp2), "%s%s", call_sign, "_APRS_Trail_Red"); create_shapefile_map( temp, temp2, SHPT_ARC, count, x, y, z, 1, // Add a timestamp to the front of the filename call_sign); // Free the storage that we malloc'ed free(x); free(y); free(z); } else // Couldn't find the station of interest { } } // Code borrowed from Shapelib which determines whether a ring is CW // or CCW. Thanks to Frank Warmerdam for permitting us to use this // under the GPL license! Per e-mail of 04/29/2003 between Frank // and Curt, WE7U. Frank gave permission for us to use _any_ // portion of Shapelib inside the GPL'ed Xastir program. // // Test Ring for Clockwise/Counter-Clockwise (fill or hole ring) // // Return 1 for Clockwise (fill ring) // Return -1 for Counter-Clockwise (hole ring) // Return 0 for error/indeterminate (shouldn't get this!) // int shape_ring_direction ( SHPObject *psObject, int Ring ) { int nVertStart; int nVertCount; int iVert; float dfSum; int result; nVertStart = psObject->panPartStart[Ring]; if( Ring == psObject->nParts-1 ) { nVertCount = psObject->nVertices - psObject->panPartStart[Ring]; } else nVertCount = psObject->panPartStart[Ring+1] - psObject->panPartStart[Ring]; dfSum = 0.0; for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ ) { dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1] - psObject->padfY[iVert] * psObject->padfX[iVert+1]; } dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart] - psObject->padfY[iVert] * psObject->padfX[nVertStart]; if (dfSum < 0.0) { result = 1; } else if (dfSum > 0.0) { result = -1; } else { result = 0; } return(result); } /********************************************************** * draw_shapefile_map() * * This function handles both weather-alert shapefiles (from the * NOAA site) and shapefiles used as maps (from a number of * sources). * * If destination_pixmap equals INDEX_CHECK_TIMESTAMPS or * INDEX_NO_TIMESTAMPS, then we are indexing the file (finding the * extents) instead of drawing it. * * The current implementation can draw Polygon, PolyLine, and Point * Shapefiles, but only from a few sources (NOAA, Mapshots.com, and * ESRI/GeographyNetwork.com). We don't handle some of the more * esoteric formats. We now handle the "hole" drawing in polygon * shapefiles, where one direction around the ring means a fill, and * the other direction means a hole in the polygon. * * Note that we must currently hard-code the file-recognition * portion and the file-drawing portion, because every new source of * Shapefiles has a different format, and the fields and field * definitions can all change between them. * * If alert is NULL, draw every shape that fits the screen. If * non-NULL, draw only the shape that matches the zone number. * * Here's what I get for the County_Warning_Area Shapefile: * * * Info for shapefiles/county_warning_areas/w_24ja01.shp * 4 Columns, 121 Records in file * WFO string (3,0) * CWA string (3,0) * LON float (18,5) * LAT float (18,5) * Info for shapefiles/county_warning_areas/w_24ja01.shp * Polygon(5), 121 Records in file * File Bounds: ( 0, 0) * ( 179.7880249, 71.39809418) * * From the NOAA web pages: Zone Alert Maps: (polygon) (such as z_16mr01.shp) ---------------- field name type width,dec description STATE character 2 [ss] State abbrev (US Postal Standard) ZONE character 3 [zzz] Zone number, from WSOM C-11 CWA character 3 County Warning Area, from WSOM C-47 NAME character 254 Zone name, from WSOM C-11 STATE_ZONE character 5 [sszzz] state+("00"+zone.trim).right(3)) TIME_ZONE character 2 [tt] Time Zone, 2 chars if split FE_AREA character 2 [aa] Cardinal area of state (occasional) LON numeric 10,5 Longitude of centroid [decimal degrees] LAT numeric 9,5 Latitude of centroid [decimal degrees] NOTE: APRS weather alerts have these sorts of codes in them: AL_C001 AUTAUGACOUNTY MS_C075 LAUDERDALE&NEWTONCOUNTIES KY_C009 EDMONSON MS_CLARKE MS_C113 MN_Z076 PIKECOUNTY ATTALACOUNTY ST.LUCIECOUNTY CW_AGLD The strings in the shapefiles are mixed-case, and it appears that the NAME field would have the county name, in case state_zone-number format was not used. We can use the STATE_ZONE filed for a match unless it is a non-standard form, in which case we'll need to look through the NAME field, and perhaps chop off the "SS_" state portion first. County Warning Areas: (polygon) --------------------- field name type width,dec description WFO character 3 WFO Identifier (name of CWA) CWA character 3 CWA Identifier (same as WFO) LON numeric 10,5 Longitude of centroid [decimal degrees] LAT numeric 9,5 Latitude of centroid [decimal degrees] Coastal and Offshore Marine Areas: (polygon) ---------------------------------- field name type width,dec description ID character 6 Marine Zone Identifier WFO character 3 Assigned WFO (Office Identifier) NAME character 250 Name of Marine Zone LON numeric 10,5 Longitude of Centroid [decimal degrees] LAT numeric 9,5 Latitude of Centroid [decimal degrees] WFO_AREA character 200 "Official Area of Responsibility", from WSOM D51/D52 Road Maps: (polyline) ---------- field name type width,dec description STFIPS numeric 2,0 State FIPS Code CTFIPS numeric 3,0 County FIPS Code MILES numeric 6,2 length [mi] KILOMETERS numeric 6,2 length [km] TOLL numeric 1,0 SURFACE numeric 1,0 Surface type LANES numeric 2,0 Number of lanes FEAT_CLASS numeric 2,0 CLASS character 30 SIGN1 character 6 Primary Sign Route SIGN2 character 6 Secondary Sign Route SIGN3 character 6 Alternate Sign Route DESCRIPT character 35 Name of road (sparse) SPEEDLIM numeric 16,0 SECONDS numeric 16,2 Lakes (lk17de98.shp): --------------------- field name type width,dec description NAME string (40,0) FEATURE string (40,0) LON float (10,5) LAT float (9,5) USGS Quads Overlay (24kgrid.shp) from http://data.geocomm.com/quadindex/ ---------------------------------- field name type width,dec Example NAME string (30,0) Lummi Bay OE W STATE string (2,0) WA LAT string (6,0) 48.750 LON string (8,0) -122.750 MRC string (8,0) 48122-G7 // Need to figure out which type of alert it is, select the corresponding shapefile, // then store the shapefile AND the alert_tag in the alert hash .filename list? // and draw the map. Add an item to alert hash to keep track? // The last parameter denotes loading into pixmap_alerts instead of pixmap or pixmap_final // Here's the old APRS-type map call: //map_search (w, alert_scan, alert, &alert_count,(int)(alert_status[i + 2] == DATA_VIA_TNC || alert_status[i + 2] == DATA_VIA_LOCAL), DRAW_TO_PIXMAP_ALERTS); // Check the zone name(s) to see which Shapefile(s) to use. switch (zone[4]) { case ('C'): // County File (c_16my01.shp) break; *** case ('A'): // County Warning File (w_24ja01.shp) break; case ('Z'): // Zone File (z_16mr01.shp, z_16my01.shp, mz24ja01.shp, oz09de99.shp) break; case ('F'): // Fire weather (fz_ddmmyy.shp) break; *** case ('A'): // Canadian Area (a_mmddyy.shp) break; case ('R'): // Canadian Region (r_mmddyy.shp) break; } **********************************************************/ static dbfawk_sig_info *Dbf_sigs = NULL; static awk_symtab *Symtbl = NULL; /* default dbfawk rule when no better signature match is found */ static awk_rule dbfawk_default_rules[] = { { 0, BEGIN, NULL, NULL, 0, 0, "dbfinfo=\"\"; key=\"\"; lanes=1; color=8; fill_color=13; fill_stipple=0; name=\"\"; filled=0; fill_style=0; pattern=0; display_level=2147483647; label_level=0", 0, 0 }, }; #define dbfawk_default_nrules (sizeof(dbfawk_default_rules)/sizeof(dbfawk_default_rules[0])) static dbfawk_sig_info *dbfawk_default_sig = NULL; void draw_shapefile_map (Widget w, char *dir, char *filenm, alert_entry * alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { DBFHandle hDBF; SHPObject *object; static XPoint points[MAX_MAP_POINTS]; char file[MAX_FILENAME]; /* Complete path/name of image file */ char short_filenm[MAX_FILENAME]; int i, fieldcount, recordcount, structure, ring; SHPHandle hSHP; int nShapeType, nEntities; double adfBndsMin[4], adfBndsMax[4]; char *sType; unsigned long my_lat, my_long; long x,y; int ok, index; int polygon_hole_flag; int *polygon_hole_storage; GC gc_temp = NULL; XGCValues gc_temp_values; Region region[3]; int temp_region1; int temp_region2; int temp_region3; int gps_flag = 0; char gps_label[100]; int gps_color = 0x0c; int quad_overlay_flag = 0; int weather_alert_flag = 0; char *filename; // filename itself w/o directory int found_shape = -1; int ok_to_draw = 0; int high_water_mark_i = 0; int high_water_mark_index = 0; char quad_label[100]; char status_text[MAX_FILENAME]; /* these have to be static since I recycle Symtbl between calls */ static char dbfsig[1024],dbffields[1024],name[64],key[64],sym[4]; static int color,lanes,filled,pattern,display_level,label_level; static int fill_style,fill_color; static int fill_stipple; //static int layer; dbfawk_sig_info *sig_info = NULL; dbfawk_field_info *fld_info = NULL; int draw_filled_orig; int draw_filled; static int label_color = 8; /* set by dbfawk. Otherwise it's black. */ static int font_size = FONT_DEFAULT; // set by dbfawk, else this default typedef struct _label_string { char label[50]; int found; struct _label_string *next; } label_string; // Define hash table for label pointers label_string *label_hash[256]; // And the index into it uint8_t hash_index = 0; label_string *ptr2 = NULL; struct Rect viewportRect; double rXmin, rYmin, rXmax,rYmax; shpinfo *si; int nhits; // pull this out of the map_draw_flags draw_filled = mdf->draw_filled; // Initialize the hash table label pointers for (i = 0; i < 256; i++) { label_hash[i] = NULL; } // We're going to change draw_filled a bunch if we've got Auto turned // on, but we have to check --- save this! draw_filled_orig=draw_filled; // Re-initialize these static variables every time through here. // Otherwise, if a dbfawk file forgets to set one, we'd use what the // last map used. Sometimes that's ugly. color=8; lanes=1; filled=0; fill_style=0; fill_color=13; fill_stipple=0; pattern=0; display_level=INT_MAX; label_level=0; label_color=8; font_size=FONT_DEFAULT; if (Dbf_sigs == NULL) { Dbf_sigs = dbfawk_load_sigs(get_data_base_dir("config"),".dbfawk"); } if (debug_level & 16) fprintf(stderr,"DBFAWK signatures %sfound in %s.\n", (Dbf_sigs)?" ":"NOT ",get_data_base_dir("config")); if (dbfawk_default_sig == NULL) { /* set up default dbfawk when no sig matches */ // This one is ok to leave allocated, as it gets malloc'ed // once during each runtime and then gets left alone. We // don't need to free it. dbfawk_default_sig = calloc(1,sizeof(dbfawk_sig_info)); CHECKMALLOC(dbfawk_default_sig); // Calls awk_new_program which allocates memory. Again, we // don't need to free this one, as it gets allocated only // once per runtime. dbfawk_default_sig->prog = awk_load_program_array(dbfawk_default_rules,dbfawk_default_nrules); } //fprintf(stderr,"*** Alert color: %d ***\n",alert_color); // We don't draw the shapes if alert_color == -1 if (alert_color != 0xff) { ok_to_draw++; } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } //fprintf(stderr,"draw_shapefile_map:start:%s\n",file); filename = filenm; i = strlen(filenm); while ( (i >= 0) && (filenm[i] != '/') ) { filename = &filenm[i--]; } //fprintf(stderr,"draw_shapefile_map:filename:%s\ttitle:%s\n",filename,alert->title); if (alert) { weather_alert_flag++; } // Check for ~/.xastir/tracklogs directory. We set up the // labels and colors differently for these types of files. // if (strstr(filenm,".xastir/tracklogs")) { // We're in the ~/.xastir/tracklogs directory if (strstr(filenm,"GPS")) // We're in the maps/GPS directory { gps_flag++; } // Open the .dbf file for reading. This has the textual // data (attributes) associated with each shape. hDBF = DBFOpen( file, "rb" ); if ( hDBF == NULL ) { if (debug_level & 16) { fprintf(stderr,"draw_shapefile_map: DBFOpen(%s,\"rb\") failed.\n", file ); } return; } if (debug_level & 16) { fprintf(stderr,"\n---------------------------------------------\nInfo for %s\n",filenm); } *dbfsig = '\0'; fieldcount = dbfawk_sig(hDBF,dbfsig,sizeof(dbfsig)); if (fieldcount == 0) { DBFClose( hDBF ); // Clean up open file descriptors return; // Should have at least one field } recordcount = DBFGetRecordCount(hDBF); if (recordcount == 0) { DBFClose( hDBF ); // Clean up open file descriptors return; // Should have at least one record } if (debug_level & 16) { fprintf(stderr,"%d Columns, %d Records in file\n", fieldcount, recordcount); fprintf(stderr,"DBF signature: %s\n",dbfsig); } if (Dbf_sigs) /* see if we have a .dbfawk file that matches */ { sig_info = dbfawk_find_sig(Dbf_sigs,dbfsig,file); if (sig_info) { gps_flag = 0; // trump gps_flag-- use dbfawk } if (!sig_info) { fprintf(stderr,"No DBFAWK signature for %s! Using default.\n",filenm); sig_info = dbfawk_default_sig; } if (sig_info) /* we've got a .dbfawk, so set up symtbl */ { if (!Symtbl) { Symtbl = awk_new_symtab(); awk_declare_sym(Symtbl,"dbffields",STRING,dbffields,sizeof(dbffields)); awk_declare_sym(Symtbl,"color",INT,&color,sizeof(color)); awk_declare_sym(Symtbl,"lanes",INT,&lanes,sizeof(lanes)); //awk_declare_sym(Symtbl,"layer",INT,&layer,sizeof(layer)); awk_declare_sym(Symtbl,"name",STRING,name,sizeof(name)); awk_declare_sym(Symtbl,"key",STRING,key,sizeof(key)); awk_declare_sym(Symtbl,"symbol",STRING,sym,sizeof(sym)); awk_declare_sym(Symtbl,"filled",INT,&filled,sizeof(filled)); awk_declare_sym(Symtbl,"fill_style",INT,&fill_style,sizeof(fill_style)); awk_declare_sym(Symtbl,"fill_color",INT,&fill_color,sizeof(fill_color)); awk_declare_sym(Symtbl,"fill_stipple",INT,&fill_stipple,sizeof(fill_stipple)); awk_declare_sym(Symtbl,"pattern",INT,&pattern,sizeof(pattern)); awk_declare_sym(Symtbl,"display_level",INT,&display_level,sizeof(display_level)); awk_declare_sym(Symtbl,"label_level",INT,&label_level,sizeof(label_level)); awk_declare_sym(Symtbl,"label_color",INT,&label_color,sizeof(label_color)); awk_declare_sym(Symtbl,"font_size",INT,&font_size,sizeof(font_size)); } if (awk_compile_program(Symtbl,sig_info->prog) < 0) { fprintf(stderr,"Unable to compile .dbfawk program\n"); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; } awk_exec_begin(sig_info->prog); /* execute a BEGIN rule if any */ /* find out which dbf fields we care to read */ fld_info = dbfawk_field_list(hDBF, dbffields); } else /* should never be reached anymore! */ { fprintf(stderr,"No DBFAWK signature for %s and no default!\n",filenm); //exit(1); // Debug return; } } /* * Weather alert dbfawk files set the "key" variable to the * appropriate search key for each record which is compared to the * alert->title[]. Use the key to find the record we need to alert on. */ // Search for specific record if we're doing alerts if (weather_alert_flag && (alert->index == -1) ) { int done = 0; // Step through all records for( i = 0; i < recordcount && !done; i++ ) { int keylen; if (sig_info) { char modified_title[50]; dbfawk_parse_record(sig_info->prog,hDBF,fld_info,i); keylen = strlen(key); if (debug_level & 16) { static char old_key[4]; // Used to limit number of output lines in debug mode if (strncmp(old_key, key, 4)) { fprintf(stderr,"dbfawk alert parse: record %d key=%s\n", i,key); memcpy(old_key, key, sizeof(old_key)); } } xastir_snprintf(modified_title, sizeof(modified_title), "%s", alert->title); // Tweak for RED_FLAG alerts: If RED_FLAG alert // we've changed the 'Z' to an 'F' in our // alert->title already. Change the 'F' back to a // 'Z' temporarily (modified_title) for our // compares. // if (modified_title[3] == 'F' && strncmp(alert->filename, "fz", 2) == 0) { modified_title[3] = 'Z'; } // If match using keylen number of chars, try the // same match but using titlelen number of chars if (strncmp(modified_title,key,keylen) == 0) { int titlelen; titlelen = strlen(modified_title); // Try the same match with titlelen number of // chars if (strncmp(modified_title,key,titlelen) == 0) { found_shape = i; done++; if (debug_level & 16) { fprintf(stderr,"dbfawk alert found it: %d \n",i); fprintf(stderr,"Title %s, key %s\n",modified_title,key); } } else { // Found a match using keylen number of // characters, but it's not a match using // titlelen number of characters. if (debug_level & 16) { fprintf(stderr, "dbfawk alert: match w/keylen, not w/titlelen: %s=%d %s=%d\n", key, keylen, modified_title, titlelen); fprintf(stderr,"Title %s, key %s\n",modified_title,key); } } } } } alert->index = found_shape; // Fill it in 'cuz we just found it } /* if (weather_alert_flag && alert_index == -1)... */ else if (weather_alert_flag) { // We've been here before and we already know the index into the // file to fetch this particular shape. found_shape = alert->index; if (debug_level & 16) { fprintf(stderr,"wx_alert: found_shape = %d\n",found_shape); } } //fprintf(stderr,"Found shape: %d\n", found_shape); if (debug_level & 16) { fprintf(stderr,"Calling SHPOpen()\n"); } // Open the .shx/.shp files for reading. // These are the index and the vertice files. hSHP = SHPOpen( file, "rb" ); if( hSHP == NULL ) { fprintf(stderr,"draw_shapefile_map: SHPOpen(%s,\"rb\") failed.\n", file ); DBFClose( hDBF ); // Clean up open file descriptors dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; } // Get the extents of the map file SHPGetInfo( hSHP, &nEntities, &nShapeType, adfBndsMin, adfBndsMax ); // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); statusline(status_text,0); // Indexing ... // We're indexing only. Save the extents in the index. index_update_ll(filenm, // Filename only adfBndsMin[1], // Bottom adfBndsMax[1], // Top adfBndsMin[0], // Left adfBndsMax[0], // Right 1000); // Default Map Level DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; // Done indexing this file } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); statusline(status_text,0); // Loading ... } // We put this section AFTER the code that determines whether we're merely // indexing, so we don't bother to generate rtrees unless we're really // drawing the file. si=NULL; // Don't bother even looking at the hash if this shapefile is completely // contained in the current viewport. We'll have to read every shape // in it anyway, and all we'd be doing is extra work searching the // RTree if (!map_inside_viewport_lat_lon(adfBndsMin[1], adfBndsMax[1], adfBndsMin[0], adfBndsMax[0])) { si = get_shp_from_hash(file); if (!si) { // we don't have what we need, so generate the index and make // the hashtable entry add_shp_to_hash(file,hSHP); // this will index all the shapes in // an RTree and save the root in a // shpinfo structure si=get_shp_from_hash(file); // now get that structure if (!si) { fprintf(stderr, "Panic! added %s, lost it already!\n",file); exit(1); } } } // we need this for the rtree search get_viewport_lat_lon(&rXmin, &rYmin, &rXmax, &rYmax); viewportRect.boundary[0] = (RectReal) rXmin; viewportRect.boundary[1] = (RectReal) rYmin; viewportRect.boundary[2] = (RectReal) rXmax; viewportRect.boundary[3] = (RectReal) rYmax; switch ( nShapeType ) { case SHPT_POINT: sType = "Point"; break; case SHPT_POINTZ: sType = "3D Point"; break; case SHPT_ARC: sType = "Polyline"; break; case SHPT_ARCZ: sType = "3D Polyline"; break; case SHPT_POLYGON: sType = "Polygon"; break; case SHPT_POLYGONZ: sType = "3D Polygon"; break; case SHPT_MULTIPOINT: fprintf(stderr,"Multi-Point Shapefile format not implemented: %s\n",file); sType = "MultiPoint"; DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; // Multipoint type. Not implemented yet. break; default: DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; // Unknown type. Don't know how to process it. break; } if (debug_level & 16) { fprintf(stderr,"%s(%d), %d Records in file\n",sType,nShapeType,nEntities); } if (debug_level & 16) fprintf(stderr,"File Bounds: (%15.10g,%15.10g)\n\t(%15.10g,%15.10g)\n", adfBndsMin[0], adfBndsMin[1], adfBndsMax[0], adfBndsMax[1] ); // Check the bounding box for this shapefile. If none of the // file is within our viewport, we can skip the entire file. if (debug_level & 16) { fprintf(stderr,"Calling map_visible_lat_lon on the entire shapefile\n"); } if (! map_visible_lat_lon( adfBndsMin[1], // Bottom adfBndsMax[1], // Top adfBndsMin[0], // Left adfBndsMax[0]) ) // Right { if (debug_level & 16) { fprintf(stderr,"No shapes within viewport. Skipping file...\n"); } DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; // The file contains no shapes in our viewport } // Set a default line width for all maps. This will most likely // be modified for particular maps in later code. (void)XSetLineAttributes(XtDisplay(w), gc, 0, LineSolid, CapButt,JoinMiter); // NOTE: Setting the color here and in the "else" may not stick if we do more // complex drawing further down like a SteelBlue lake with a black boundary, // or if we have labels turned on which resets our color to black. if (weather_alert_flag) /* XXX */ { char xbm_path[MAX_FILENAME]; unsigned int _w, _h; int _xh, _yh; int ret_val; FILE *alert_fp = NULL; char xbm_filename[MAX_FILENAME]; // This GC is used for weather alerts (writing to the // pixmap: pixmap_alerts) and _was_ used for beam_heading // rays, but no longer is. (void)XSetForeground (XtDisplay (w), gc_tint, colors[(int)alert_color]); // N7TAP: No more tinting as that would change the color of the alert, losing that information. (void)XSetFunction(XtDisplay(w), gc_tint, GXcopy); /* Options are: GXclear 0 (Don't use) GXand src AND dst (Darker colors, black can result from overlap) GXandReverse src AND (NOT dst) (Darker colors) GXcopy src (Don't use) GXandInverted (NOT src) AND dst (Pretty colors) GXnoop dst (Don't use) GXxor src XOR dst (Don't use, overlapping areas cancel each other out) GXor src OR dst (More pastel colors, too bright?) GXnor (NOT src) AND (NOT dst) (Darker colors, very readable) GXequiv (NOT src) XOR dst (Bright, very readable) GXinvert (NOT dst) (Don't use) GXorReverse src OR (NOT dst) (Bright, not as readable as others) GXcopyInverted (NOT src) (Don't use) GXorInverted (NOT src) OR dst (Bright, not very readable) GXnand (NOT src) OR (NOT dst) (Bright, not very readable) GXset 1 (Don't use) */ // Note that we can define more alert files for other countries. They just need to match // the alert text that comes along in the NWS packet. // Current alert files we have defined: // winter_storm.xbm * // snow.xbm // winter_weather.xbm * // flood.xbm // torndo.xbm * // red_flag.xbm // wind.xbm // alert.xbm (Used if no match to another filename) // Alert texts we receive: // FLOOD // SNOW // TORNDO // WIND // WINTER_STORM // WINTER_WEATHER // RED_FLAG // SVRTSM (no file defined for this yet) // Many others. // Attempt to open the alert filename: .xbm (lower-case alert text) // to detect whether we have a matching filename for our alert text. xastir_snprintf(xbm_filename, sizeof(xbm_filename), "%s", alert->alert_tag); // Convert the filename to lower-case to_lower(xbm_filename); // Construct the complete path/filename strcpy(xbm_path, SYMBOLS_DIR); xbm_path[sizeof(xbm_path)-1] = '\0'; // Terminate string strcat(xbm_path, "/"); xbm_path[sizeof(xbm_path)-1] = '\0'; // Terminate string strcat(xbm_path, xbm_filename); xbm_path[sizeof(xbm_path)-1] = '\0'; // Terminate string strcat(xbm_path, ".xbm"); xbm_path[sizeof(xbm_path)-1] = '\0'; // Terminate string // Try opening the file alert_fp = fopen(xbm_path, "rb"); if (alert_fp == NULL) { // Failed to find a matching file: Instead use the "alert.xbm" file xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "alert.xbm"); } else { // Success: Close the file pointer fclose(alert_fp); } /* XXX - need to add SVRTSM */ (void)XSetLineAttributes(XtDisplay(w), gc_tint, 0, LineSolid, CapButt,JoinMiter); XFreePixmap(XtDisplay(w), pixmap_wx_stipple); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_wx_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); // We shouldn't exit on this one, as it's not so severe // that we should kill Xastir. I've seen this happen // after very long runtimes though, so perhaps there's a // problem somewhere in the X11 server and/or it's // caching? // //exit(1); } else { // We successfully loaded the bitmap, so set the stipple // properly to use it. Skip this part if we were // unsuccessful at loading the bitmap. (void)XSetStipple(XtDisplay(w), gc_tint, pixmap_wx_stipple); } } /* ...end if (weather_alert_flag) */ else /* !weather_alert_flag */ { // Are these actually used anymore by the code? Colors get set later // when we know more about what we're dealing with. } // Now that we have the file open, we can read out the structures. // We can handle Point, PolyLine and Polygon shapefiles at the moment. HandlePendingEvents(app_context); if (interrupt_drawing_now) { DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } return; } // Now instead of looping over all the shapes, search for the ones that // are in our viewport and only loop over those //fprintf(stderr,"Deciding how to process this file...\n"); if (weather_alert_flag) // We're drawing _one_ weather alert shape { //fprintf(stderr," weather alert flag set...\n"); if (found_shape != -1) // Found the record { //fprintf(stderr," found_shape set...\n"); // just in case we haven't drawn any real maps yet... if (!RTree_hitarray) { //fprintf(stderr," mallocing hitarray...\n"); RTree_hitarray = (int *)malloc(sizeof(int)*1000); RTree_hitarray_size=1000; } CHECKMALLOC(RTree_hitarray); RTree_hitarray[0]=found_shape; //fprintf(stderr," %s contains alert\n",file); nhits=1; } else // Didn't find the record { //fprintf(stderr," found_shape is -1...\n"); nhits=0; } } else // Draw an entire Shapefile map { //fprintf(stderr," weather_alert_flag not set...\n"); if (si) { //fprintf(stderr," si is 0x%lx...\n",(unsigned long int) si); RTree_hitarray_index=0; // the callback will be executed every time the search finds a // shape whose bounding box overlaps the viewport. nhits = Xastir_RTreeSearch(si->root, &viewportRect, (void *)RTreeSearchCallback, 0); //fprintf(stderr,"Found %d hits in %s\n",nhits,file); } else { //fprintf(stderr," si not set ...\n"); // we read the entire shapefile nhits=nEntities; // fprintf(stderr," %s entirely in view, with %d shapes\n",file,nhits); } } //fprintf(stderr," Done with decision, nhits is %d\n",nhits); // only iterate over the hits found by RTreeSearch, not all of them for (RTree_hitarray_index=0; RTree_hitarray_indexsig == NULL)) { dbfawk_free_sigs(sig_info); } return; } } if (si) { structure=RTree_hitarray[RTree_hitarray_index]; } else if ((weather_alert_flag && found_shape!=-1)) { structure = RTree_hitarray[0]; } else { structure = RTree_hitarray_index; } // Have had segfaults before at the SHPReadObject() call // when the Shapefile was corrupted. //fprintf(stderr,"Before SHPReadObject:%d\n",structure); object = SHPReadObject( hSHP, structure ); // Note that each structure can have multiple rings //fprintf(stderr,"After SHPReadObject\n"); if (object == NULL) { continue; // Skip this iteration, go on to the next } // Fill in the boundary variables in the alert record. We use // this info in load_alert_maps() to determine which alerts are // within our view, without having to open up the shapefiles to // get this info (faster). if (weather_alert_flag) { alert->top_boundary = object->dfYMax; alert->left_boundary = object->dfXMin; alert->bottom_boundary = object->dfYMin; alert->right_boundary = object->dfXMax; } // Here we check the bounding box for this shape against our // current viewport. If we can't see it, don't draw it. // if (debug_level & 16) // fprintf(stderr,"Calling map_visible_lat_lon on a shape\n"); if ( map_visible_lat_lon( object->dfYMin, // Bottom object->dfYMax, // Top object->dfXMin, // Left object->dfXMax) ) // Right { const char *temp; int jj; int x0 = 0; // Used for computing label rotation int x1 = 0; int y0 = 0; int y1 = 0; if (debug_level & 16) { fprintf(stderr,"Shape %d is visible, drawing it.", structure); fprintf(stderr," Parts in shape: %d\n", object->nParts ); // Number of parts in this structure } if (debug_level & 16) { // Print the field contents for (jj = 0; jj < fieldcount; jj++) { if (fieldcount >= (jj + 1) ) { temp = DBFReadStringAttribute( hDBF, structure, jj ); if (temp != NULL) { fprintf(stderr,"%s, ", temp); } } } fprintf(stderr,"\n"); fprintf(stderr,"Done with field contents\n"); } if (sig_info) { dbfawk_parse_record(sig_info->prog,hDBF,fld_info,structure); if (debug_level & 16) { fprintf(stderr,"dbfawk parse of structure %d: ",structure); fprintf(stderr,"color=%d ",color); fprintf(stderr,"lanes=%d ",lanes); fprintf(stderr,"name=%s ",name); fprintf(stderr,"key=%s ",key); fprintf(stderr,"symbol=%s ",sym); fprintf(stderr,"filled=%d ",filled); fprintf(stderr,"fill_style=%d ",fill_style); fprintf(stderr,"fill_color=%d ",fill_color); fprintf(stderr,"fill_stipple=%d ",fill_stipple); fprintf(stderr,"pattern=%d ",pattern); fprintf(stderr,"display_level=%d ",display_level); fprintf(stderr,"label_level=%d ",label_level); fprintf(stderr,"label_color=%d\n",label_color); // fprintf(stderr,"layer=%d\n",layer); } /* set attributes */ (void)XSetForeground(XtDisplay(w), gc, colors[color]); // Let the user decide whether to make the map // filled or unfilled via the Map Properties dialog. // This allows things like the NOAA counties map to // be used as a base map (filled) or as a vector // overlay map at the user's discretion. The // choices available are: // 0: Global No-Fill. Don't fill any polygons. // 1: Global Fill. Fill all polygons. // 2: Auto. dbfawk file, if present, takes over control. // if (debug_level & 16) { fprintf(stderr," draw_filled is %d\n",draw_filled_orig); } switch (draw_filled_orig) { case 0: // Global No-Fill (Vector) // Do nothing, user has chosen Global // No_Fill for this map. The draw_filled // variable takes precedence. break; case 1: // Global Fill // Do nothing, user has chosen Global // Fill for this map. The draw_filled // variable takes precedence. break; case 2: // Auto default: // User has chosen Auto Fill for this map, // so the Dbfawk file controls the fill // property. If no dbfawk file, "filled" // will take on the default setting listed // in dbfawk_default_rules[] above. draw_filled = filled; break; } if (weather_alert_flag) /* XXX will this fix WX alerts? */ { fill_style = FillStippled; } skip_it = (map_color_levels && (scale_y > display_level)); skip_label = (map_color_levels && (scale_y > label_level)); } /* This case statement is a mess. Lots of common code could be used before the case but currently isn't */ switch ( nShapeType ) { case SHPT_POINT: case SHPT_POINTZ: // We hit this case once for each point shape in // the file, iff that shape is within our // viewport. if (debug_level & 16) { fprintf(stderr,"Found Point Shapefile\n"); } // Read each point, place a label there, and an optional symbol //object->padfX //object->padfY //object->padfZ // if ( mapshots_labels_flag // && map_labels // && (fieldcount >= 3) ) { if (!skip_it) // Need a bracket so we can define { // some local variables. const char *temp = NULL; int ok = 1; int temp_ok; if (map_labels) { temp = name; } // Convert point to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[0], (float)object->padfY[0]); //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map1: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; } if (ok == 1) { char symbol_table = '/'; char symbol_id = '.'; /* small x */ char symbol_over = ' '; // Fine-tuned the location here so that // the middle of the 'X' would be at the // proper pixel. if (*sym) { symbol(w,0,sym[0],sym[1],sym[2],pixmap,1,x-10,y-10,' '); } else { symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); } // Fine-tuned this string so that it is // to the right of the 'X' and aligned // nicely. if (map_labels && !skip_label) { // Labeling of points done here draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)temp, 0xf, 0x10, strlen(temp)); //(void)draw_label_text ( w, x, y, strlen(temp), colors[label_color], (char *)temp); //(void)draw_rotated_label_text (w, 90, x+10, y, strlen(temp), colors[label_color], (char *)temp); } } } break; case SHPT_ARC: case SHPT_ARCZ: // We hit this case once for each polyline shape // in the file, iff at least part of that shape // is within our viewport. if (debug_level & 16) { fprintf(stderr,"Found Polylines\n"); } // Draw the PolyLines themselves: // Default in case we forget to set the line // width later: (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineSolid, CapButt,JoinMiter); if (!skip_it) { (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetLineAttributes(XtDisplay (w), gc, (lanes)?lanes:1, pattern, CapButt,JoinMiter); } //WE7U // I'd like to be able to change the color of each GPS track for // each team in the field. It'll help to differentiate the tracks // where they happen to cross. /* XXX - WITH_DBFAWK should handle this case too. Need to add a color attribute to the generated dbf file */ if (gps_flag) { int jj; int done = 0; // Fill in the label we'll use later xastir_snprintf(gps_label, sizeof(gps_label), "%s", filename); // Knock off the "_Color.shp" portion of the // label. Find the last underline character // and change it to an end-of-string. jj = strlen(gps_label); while ( !done && (jj > 0) ) { if (gps_label[jj] == '_') { gps_label[jj] = '\0'; // Terminate it here done++; } jj--; } // Check for a color in the filename: i.e. // "Team2_Track_Red.shp" if (strstr(filenm,"_Red.shp")) { gps_color = 0x0c; // Red } else if (strstr(filenm,"_Green.shp")) { // gps_color = 0x64; // ForestGreen gps_color = 0x23; // Area Green Hi } else if (strstr(filenm,"_Black.shp")) { gps_color = 0x08; // black } else if (strstr(filenm,"_White.shp")) { gps_color = 0x0f; // white } else if (strstr(filenm,"_Orange.shp")) { // gps_color = 0x06; // orange // gps_color = 0x19; // orange2 // gps_color = 0x41; // DarkOrange3 (good medium orange) gps_color = 0x62; // orange3 (brighter) } else if (strstr(filenm,"_Blue.shp")) { gps_color = 0x03; // cyan } else if (strstr(filenm,"_Yellow.shp")) { gps_color = 0x0e; // yellow } else if (strstr(filenm,"_Purple.shp")) { gps_color = 0x0b; // mediumorchid } else // Default color { gps_color = 0x0c; // Red } // Set the color for the arc's (void)XSetForeground(XtDisplay(w), gc, colors[gps_color]); // Make the track nice and wide: Easy to // see. // (void)XSetLineAttributes (XtDisplay (w), gc, 3, LineSolid, CapButt,JoinMiter); (void)XSetLineAttributes (XtDisplay (w), gc, 3, LineOnOffDash, CapButt,JoinMiter); // (void)XSetLineAttributes (XtDisplay (w), gc, 3, LineDoubleDash, CapButt,JoinMiter); } // End of gps flag portion index = 0; // Index into our own points array. // Tells how many points we've // collected so far. if (ok_to_draw && !skip_it) { // Read the vertices for each vector now for (ring = 0; ring < object->nVertices; ring++ ) { int temp_ok; ok = 1; //fprintf(stderr,"\t%d:%g %g\t", ring, object->padfX[ring], object->padfY[ring] ); // Convert to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[ring], (float)object->padfY[ring]); //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map2: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; // Save the endpoints of the first line // segment for later use in label rotation if (ring == 0) { // Save the first set of screen coordinates x0 = (int)x; y0 = (int)y; } else if (ring == 1) { // Save the second set of screen coordinates x1 = (int)x; y1 = (int)y; } } if (ok == 1) { // XDrawLines uses 16-bit unsigned // integers (shorts). Make sure we // stay within the limits. points[index].x = l16(x); points[index].y = l16(y); //fprintf(stderr,"%d %d\t", points[index].x, points[index].y); index++; } if (index > high_water_mark_index) { high_water_mark_index = index; } if (index >= MAX_MAP_POINTS) { index = MAX_MAP_POINTS - 1; fprintf(stderr,"Trying to overrun the points array: SHPT_ARC, index=%d\n",index); } } // End of "for" loop for polyline points } if (ok_to_draw && !skip_it) { (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(index), CoordModeOrigin); } // Figure out and draw the labels for PolyLines. Note that we later // determine whether we want to draw the label at all. Move all // code possible below that decision point to keep everything fast. // Don't do unnecessary calculations if we're not going to draw the // label. temp = (gps_flag)?gps_label:name; if ( (temp != NULL) && (strlen(temp) != 0) && map_labels && !skip_it && !skip_label ) { int temp_ok; ok = 1; // Convert to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[0], (float)object->padfY[0]); //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map3: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = l16(x / scale_x); y = l16(y / scale_y); } if (ok == 1 && ok_to_draw) { int new_label = 1; int mod_number; // Set up the mod_number, which is used // below to determine how many of each // identical label are skipped at each // zoom level. // The goal here is to have one complete label visible on the screen // for each road. We end up skipping labels based on zoom level, // which, if the road doesn't have very many segments, may end up // drawing one label almost entirely off-screen. :-( // If we could check the first line segment to see if the label // would be drawn off-screen, perhaps we could start drawing at // segment #2? We'd have to check whether there is a segment #2. // Another possibility would be to shift the label on-screen. Would // this work for twisty/turny roads though? I suppose, 'cuz they'd // end up with more line segments and we could just draw at segment // #2 in that case instead of shifting. if (scale_y == 1) { mod_number = 1; } else if (scale_y <= 2) { mod_number = 1; } else if (scale_y <= 4) { mod_number = 2; } else if (scale_y <= 8) { mod_number = 4; } else if (scale_y <= 16) { mod_number = 8; } else if (scale_y <= 32) { mod_number = 16; } else { mod_number = (int)(scale_y); } // Check whether we've written out this string // already: Look for a match in our linked list // The problem with this method is that we might get strings // "written" at the extreme top or right edge of the display, which // means the strings wouldn't be visible, but Xastir thinks that it // wrote the string out visibly. To partially counteract this I've // set it up to write only some of the identical strings. This // still doesn't help in the cases where a street only comes in from // the top or right and doesn't have an intersection with another // street (and therefore another label) within the view. // Hash index is just the first // character. Tried using lower 6 bits // of first two chars and lower 7 bits // of first two chars but the result was // slower than just using the first // character. hash_index = (uint8_t)(temp[0]); ptr2 = label_hash[hash_index]; while (ptr2 != NULL) // Step through the list { // Check 2nd character (fast!) if ( (uint8_t)(ptr2->label[1]) == (uint8_t)(temp[1]) ) { if (strcasecmp(ptr2->label,temp) == 0) // Found a match { //fprintf(stderr,"Found a match!\t%s\n",temp); new_label = 0; ptr2->found = ptr2->found + 1; // Increment the "found" quantity // We change this "mod" number based on zoom level, so that long // strings don't overwrite each other, and so that we don't get too // many or too few labels drawn. This will cause us to skip // intersections (the tiger files appear to have a label at each // intersection). Between rural and urban areas, this method might // not work well. Urban areas have few intersections, so we'll get // fewer labels drawn. // A better method might be to check the screen location for each // one and only write the strings if they are far enough apart, and // only count a string as written if the start of it is onscreen and // the angle is correct for it to be written on the screen. // Draw a number of labels // appropriate for the zoom // level. // Labeling: Skip label logic if ( ((ptr2->found - 1) % mod_number) != 0) { skip_label++; } ptr2 = NULL; // End the loop } else { ptr2 = ptr2->next; } } else { ptr2 = ptr2->next; } } if (!skip_label) // Draw the string { // Compute the label rotation angle float diff_X = (int)x1 - x0; float diff_Y = (int)y1 - y0; float angle = 0.0; // Angle for the beginning of this polyline if (diff_X == 0.0) // Avoid divide by zero errors { diff_X = 0.0000001; } angle = atan( diff_X / diff_Y ); // Compute in radians // Convert to degrees angle = angle / (2.0 * M_PI ); angle = angle * 360.0; // Change to fit our rotate label function's idea of angle angle = 360.0 - angle; //fprintf(stderr,"Y: %f\tX: %f\tAngle: %f ==> ",diff_Y,diff_X,angle); if ( angle > 90.0 ) { angle += 180.0; } if ( angle >= 360.0 ) { angle -= 360.0; } //fprintf(stderr,"%f\t%s\n",angle,temp); // Labeling of polylines done here // (void)draw_label_text ( w, x, y, strlen(temp), colors[label_color], (char *)temp); if (gps_flag) { (void)draw_rotated_label_text (w, //(int)angle, -90, // Horizontal, easiest to read x, y, strlen(temp), colors[gps_color], (char *)temp, font_size); } else { (void)draw_rotated_label_text(w, (int)angle, x, y, strlen(temp), colors[label_color], (char *)temp, font_size); } } if (new_label) { // Create a new record for this string // and add it to the head of the list. // Make sure to "free" this linked // list. //fprintf(stderr,"Creating a new record: %s\n",temp); ptr2 = (label_string *)malloc(sizeof(label_string)); CHECKMALLOC(ptr2); memcpy(ptr2->label, temp, sizeof(ptr2->label)); ptr2->label[sizeof(ptr2->label)-1] = '\0'; // Terminate string ptr2->found = 1; // We use first character of string // as our hash index. hash_index = temp[0]; ptr2->next = label_hash[hash_index]; label_hash[hash_index] = ptr2; //if (label_hash[hash_index]->next == NULL) // fprintf(stderr,"only one record\n"); } } } break; case SHPT_POLYGON: case SHPT_POLYGONZ: if (debug_level & 16) { fprintf(stderr,"Found Polygons\n"); } // User requested filled polygons with stippling. // Set the stipple now. need to do here, because if // done earlier the labels get stippled, too. (void)XSetFillStyle(XtDisplay(w), gc, fill_style); if (draw_filled != 0 && fill_style == FillStippled) { switch (fill_stipple) { case 0: (void)XSetStipple(XtDisplay(w), gc, pixmap_13pct_stipple); break; case 1: (void)XSetStipple(XtDisplay(w), gc, pixmap_25pct_stipple); break; default: (void)XSetStipple(XtDisplay(w), gc, pixmap_25pct_stipple); break; } } // Each polygon can be made up of multiple // rings, and each ring has multiple points that // define it. We hit this case once for each // polygon shape in the file, iff at least part // of that shape is within our viewport. // We now handle the "hole" drawing in polygon shapefiles, where // clockwise direction around the ring means a fill, and CCW means a // hole in the polygon. // // Possible implementations: // // 1) Snag an algorithm for a polygon "fill" function from // somewhere, but add a piece that will check for being inside a // "hole" polygon and just not draw while traversing it (change the // pen color to transparent over the holes?). // SUMMARY: How to do this? // // 2) Draw to another layer, then copy only the filled pixels to // their final destination pixmap. // SUMMARY: Draw polygons once, then a copy operation. // // 3) Separate area: Draw polygon. Copy from other map layer into // holes, then copy the result back. // SUMMARY: How to determine outline? // // 4) Use clip-masks to prevent drawing over the hole areas: Draw // to another 1-bit pixmap or region. This area can be the size of // the max shape extents. Filled = 1. Holes = 0. Use that pixmap // as a clip-mask to draw the polygons again onto the final pixmap. // SUMMARY: We end up drawing the shape twice! // // MODIFICATION: Draw a filled rectangle onto the map pixmap using // the clip-mask to control where it actually gets drawn. // SUMMARY: Only end up drawing the shape once. // // 5) Inverted clip-mask: Draw just the holes to a separate pixmap: // Create a pixmap filled with 1's (XFillRectangle & GXset). Draw // the holes and use GXinvert to draw zero's to the mask where the // holes go. Use this as a clip-mask to draw the filled areas of // the polygon to the map pixmap. // SUMMARY: Faster than methods 1-4? // // 6) Use Regions to do the same method as #5 but with more ease. // Create a polygon Region, then create a Region for each hole and // subtract the hole from the polygon Region. Once we have a // complete polygon + holes, use that as the clip-mask for drawing // the real polygon. Use XSetRegion() on the GC to set this up. We // might have to do offsets as well so that the region maps properly // to our map pixmap when we draw the final polygon to it. // SUMMARY: Should be faster than methods 1-5. // // 7) Do method 6 but instead of drawing a polygon region, draw a // rectangle region first, then knock holes in it. Use that region // as the clip-mask for the XFillPolygon() later by calling // XSetRegion() on the GC. We don't really need a polygon region // for a clip-mask. A rectangle with holes in it will work just as // well and should be faster overall. We might have to do offsets // as well so that the region maps properly to our map pixmap when // we draw the final polygon to it. // SUMMARY: This might be the fastest method of the ones listed, if // drawing a rectangle region is faster than drawing a polygon // region. We draw the polygon once here instead of twice, and each // hole only once. The only added drawing time would be the // creation of the rectangle region, which should be fairly fast, // and the subtracting of the hole regions from it. // // // Shapefiles also allow identical points to be next to each other // in the vertice list. We should look for that and get rid of // duplicate vertices. //if (object->nParts > 1) //fprintf(stderr,"Number of parts: %d\n", object->nParts); // Unfortunately, for Polygon shapes we must make one pass through // the entire set of rings to see if we have any "hole" rings (as // opposed to "fill" rings). If we have any "hole" rings, we must // handle the drawing of the Shape quite differently. // // Read the vertices for each ring in the Shape. Test whether we // have a hole ring. If so, save the ring index away for the next // step when we actually draw the shape. polygon_hole_flag = 0; // Allocate storage for a flag for each ring in // this Shape. // !!Remember to free this storage later!! polygon_hole_storage = (int *)malloc(object->nParts*sizeof(int)); CHECKMALLOC(polygon_hole_storage); // Run through the entire shape (all rings of it) once. Create an // array of flags that specify whether each ring is a fill or a // hole. If any holes found, set the global polygon_hole_flag as // well. for (ring = 0; ring < object->nParts; ring++ ) { // Testing for fill or hole ring. This will // determine how we ultimately draw the // entire shape. // switch ( shape_ring_direction( object, ring) ) { case 0: // Error in trying to compute whether fill or hole fprintf(stderr,"Error in computing fill/hole ring\n"); /* Falls through. */ case 1: // It's a fill ring // Do nothing for these two cases // except clear the flag in our // storage polygon_hole_storage[ring] = 0; break; case -1: // It's a hole ring // Add it to our list of hole rings // here and set a flag. That way we // won't have to run through // SHPRingDir_2d again in the next // loop. polygon_hole_flag++; polygon_hole_storage[ring] = 1; // fprintf(stderr, "Ring %d/%d is a polygon hole\n", // ring, // object->nParts); break; } } // We're done with the initial run through the vertices of all // rings. We now know which rings are fills and which are holes and // have recorded the data. // Speedup: Only loop through the vertices once, by determining // hole/fill polygons as we go. //WE7U3 // Speedup: If not draw_filled, then don't go // through the math and region code. Set the // flag to zero so that we won't do all the math // and the regions. if (!map_color_fill || !draw_filled) { polygon_hole_flag = 0; } if (polygon_hole_flag) { XRectangle rectangle; long width, height; double top_ll, left_ll, bottom_ll, right_ll; int temp_ok; // fprintf(stderr, "%s:Found %d hole rings in shape %d\n", // file, // polygon_hole_flag, // structure); //WE7U3 //////////////////////////////////////////////////////////////////////// // Now that we know which are fill/hole rings, worry about drawing // each ring of the Shape: // // 1) Create a filled rectangle region, probably the size of the // Shape extents, and at the same screen coordinates as the entire // shape would normally be drawn. // // 2) Create a region for each hole ring and subtract these new // regions one at a time from the rectangle region created above. // // 3) When the "swiss-cheese" rectangle region is complete, draw // only the filled polygons onto the map pixmap using the // swiss-cheese rectangle region as the clip-mask. Use a temporary // GC for this operation, as I can't find a way to remove a // clip-mask from a GC. We may have to use offsets to make this // work properly. // Create three regions and rotate between // them, due to the XSubtractRegion() // needing three parameters. If we later // find that two of the parameters can be // repeated, we can simplify our code. // We'll rotate through them mod 3. temp_region1 = 0; // Create empty region region[temp_region1] = XCreateRegion(); // Draw a rectangular clip-mask inside the // Region. Use the same extents as the full // Shape. // Set up the real sizes from the Shape // extents. top_ll = object->dfYMax; left_ll = object->dfXMin; bottom_ll = object->dfYMin; right_ll = object->dfXMax; // Convert point to Xastir coordinates: temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, left_ll, top_ll); //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map4: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; // Here we check for really wacko points that will cause problems // with the X drawing routines, and fix them. if (x > 1700l) { x = 1700l; } if (x < 0l) { x = 0l; } if (y > 1700l) { y = 1700l; } if (y < 0l) { y = 0l; } } // Convert points to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, right_ll, bottom_ll); //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map5: Problem converting from lat/lon\n"); ok = 0; width = 0; height = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. width = my_long - NW_corner_longitude; height = my_lat - NW_corner_latitude; width = width / scale_x; height = height / scale_y; // Here we check for really wacko points that will cause problems // with the X drawing routines, and fix them. if (width > 1700l) { width = 1700l; } if (width < 1l) { width = 1l; } if (height > 1700l) { height = 1700l; } if (height < 1l) { height = 1l; } } //TODO // We can run into trouble here because we only have 16-bit values // to work with. If we're zoomed in and the Shape is large in // comparison to the screen, we'll easily exceed these numbers. // Perhaps we'll need to work with something other than screen // coordinates? Perhaps truncating the values will be adequate. rectangle.x = (short) x; rectangle.y = (short) y; rectangle.width = (unsigned short) width; rectangle.height = (unsigned short) height; //fprintf(stderr,"*** Rectangle: %d,%d %dx%d\n", rectangle.x, rectangle.y, rectangle.width, rectangle.height); // Create the initial region containing a // filled rectangle. XUnionRectWithRegion(&rectangle, region[temp_region1], region[temp_region1]); // Create a region for each set of hole // vertices (CCW rotation of the vertices) // and subtract each from the rectangle // region. for (ring = 0; ring < object->nParts; ring++ ) { int endpoint; int on_screen; if (polygon_hole_storage[ring] == 1) { // It's a hole polygon. Cut the // hole out of our rectangle region. int num_vertices = 0; // int nVertStart; // nVertStart = object->panPartStart[ring]; if( ring == object->nParts-1 ) num_vertices = object->nVertices - object->panPartStart[ring]; else num_vertices = object->panPartStart[ring+1] - object->panPartStart[ring]; //TODO // Snag the vertices and put them into the "points" array, // converting to screen coordinates as we go, then subtracting the // starting point, so that the regions remain small? // // We could either subtract the starting point of each shape from // each point, or take the hit on region size and just use the full // screen size (or whatever part of it the shape required plus the // area from the starting point to 0,0). if ( (ring+1) < object->nParts) { endpoint = object->panPartStart[ring+1]; } //else endpoint = object->nVertices; else { endpoint = object->panPartStart[0] + object->nVertices; } //fprintf(stderr,"Endpoint %d\n", endpoint); //fprintf(stderr,"Vertices: %d\n", endpoint - object->panPartStart[ring]); i = 0; // i = Number of points to draw for one ring on_screen = 0; // index = ptr into the shapefile's array of points for (index = object->panPartStart[ring]; index < endpoint; ) { int temp_ok; // Get vertice and convert to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[index], (float)object->padfY[index]); //fprintf(stderr,"%lu %lu\t", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map6: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; //fprintf(stderr,"%ld %ld\t\t", x, y); // Here we check for really // wacko points that will // cause problems with the X // drawing routines, and fix // them. Increment // on_screen if any of the // points might be on // screen. if (x > 1700l) { x = 1700l; } else if (x < 0l) { x = 0l; } else { on_screen++; } if (y > 1700l) { y = 1700l; } else if (y < 0l) { y = 0l; } else { on_screen++; } points[i].x = l16(x); points[i].y = l16(y); if (on_screen) { // fprintf(stderr,"%d x:%d y:%d\n", // i, // points[i].x, // points[i].y); } i++; } index++; if (index > high_water_mark_index) { high_water_mark_index = index; } if (index > endpoint) { index = endpoint; fprintf(stderr,"Trying to run past the end of shapefile array: index=%d\n",index); } } // End of converting vertices for a ring // Create and subtract the region // only if it might be on screen. if (on_screen) { temp_region2 = (temp_region1 + 1) % 3; temp_region3 = (temp_region1 + 2) % 3; // Create empty regions. region[temp_region2] = XCreateRegion(); region[temp_region3] = XCreateRegion(); // Draw the hole polygon if (num_vertices >= 3) { XDestroyRegion(region[temp_region2]); // Release the old region[temp_region2] = XPolygonRegion(points, num_vertices, WindingRule); } else { fprintf(stderr, "draw_shapefile_map:XPolygonRegion with too few vertices:%d\n", num_vertices); } // Subtract region2 from region1 and // put the result into region3. //fprintf(stderr, "Subtracting region\n"); XSubtractRegion(region[temp_region1], region[temp_region2], region[temp_region3]); // Get rid of the two regions we no // longer need XDestroyRegion(region[temp_region1]); XDestroyRegion(region[temp_region2]); // Indicate the final result region for // the next iteration or the exit of the // loop. temp_region1 = temp_region3; } } } // region[temp_region1] now contains a // clip-mask of the original polygon with // holes cut out of it (swiss-cheese // rectangle). // Create temporary GC. It looks like we // don't need this to create the regions, // but we'll need it when we draw the filled // polygons onto the map pixmap using the // final region as a clip-mask. // Offsets? // XOffsetRegion // gc_temp_values.function = GXcopy; gc_temp = XCreateGC(XtDisplay(w), XtWindow(w), 0, &gc_temp_values); // now copy the fill style and stipple from gc. XCopyGC(XtDisplay(w), gc, (GCFillStyle|GCStipple), gc_temp); // Set the clip-mask into the GC. This GC // is now ruined for other purposes, so // destroy it when we're done drawing this // one shape. XSetRegion(XtDisplay(w), gc_temp, region[temp_region1]); XDestroyRegion(region[temp_region1]); } //WE7U3 //////////////////////////////////////////////////////////////////////// // Read the vertices for each ring in this Shape for (ring = 0; ring < object->nParts; ring++ ) { int endpoint; //fprintf(stderr,"Ring: %d\t\t", ring); if ( (ring+1) < object->nParts) { endpoint = object->panPartStart[ring+1]; } //else endpoint = object->nVertices; else { endpoint = object->panPartStart[0] + object->nVertices; } //fprintf(stderr,"Endpoint %d\n", endpoint); //fprintf(stderr,"Vertices: %d\n", endpoint - object->panPartStart[ring]); i = 0; // i = Number of points to draw for one ring // index = ptr into the shapefile's array of points for (index = object->panPartStart[ring]; index < endpoint; ) { int temp_ok; ok = 1; //fprintf(stderr,"\t%d:%g %g\t", index, object->padfX[index], object->padfY[index] ); // Get vertice and convert to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[index], (float)object->padfY[index]); //fprintf(stderr,"%lu %lu\t", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map7: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; index++; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; //fprintf(stderr,"%ld %ld\t\t", x, y); // Here we check for really wacko points that will cause problems // with the X drawing routines, and fix them. points[i].x = l16(x); points[i].y = l16(y); i++; // Number of points to draw if (i > high_water_mark_i) { high_water_mark_i = i; } if (i >= MAX_MAP_POINTS) { i = MAX_MAP_POINTS - 1; fprintf(stderr,"Trying to run past the end of our internal points array: i=%d\n",i); } //fprintf(stderr,"%d %d\t", points[i].x, points[i].y); index++; if (index > high_water_mark_index) { high_water_mark_index = index; } if (index > endpoint) { index = endpoint; fprintf(stderr,"Trying to run past the end of shapefile array: index=%d\n",index); } } } if ( (i >= 3) && (ok_to_draw && !skip_it) && ( !draw_filled || !map_color_fill || (draw_filled && polygon_hole_storage[ring] == 0) ) ) { // We have a polygon to draw! //WE7U3 if ((!draw_filled || !map_color_fill) && polygon_hole_storage[ring] == 1) { // We have a hole drawn as unfilled. // Draw as a black dashed line. (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineOnOffDash, CapButt, JoinMiter); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(i), CoordModeOrigin); (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineSolid, CapButt, JoinMiter); } else if (quad_overlay_flag) { (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(i), CoordModeOrigin); } /* old glacier, lake and river code was identical with the exception of what color to use! */ else if (!weather_alert_flag) { /* color is already set by dbfawk(?) */ /* And so are lanes and pattern. Let's use what was specified. */ (void)XSetLineAttributes(XtDisplay(w), gc, (lanes)?lanes:1, pattern, CapButt, JoinMiter); (void)XSetForeground(XtDisplay(w), gc, colors[color]); if (map_color_fill && draw_filled) { if (polygon_hole_flag) { (void)XSetForeground(XtDisplay(w), gc_temp, colors[fill_color]); if (i >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap, gc_temp, points, i, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_shapefile_map:Too few points:%d, Skipping XFillPolygon()", npoints); } } else /* no holes in this polygon */ { if (i >= 3) { /* draw the filled polygon */ (void)XSetForeground(XtDisplay(w), gc, colors[fill_color]); (void)XFillPolygon(XtDisplay(w), pixmap, gc, points, i, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_shapefile_map:Too few points:%d, Skipping XFillPolygon()", npoints); } } } /* draw the polygon border */ (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetFillStyle(XtDisplay(w), gc, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(i), CoordModeOrigin); } else if (weather_alert_flag) { (void)XSetFillStyle(XtDisplay(w), gc_tint, FillStippled); // We skip the hole/fill thing for these? if (i >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap_alerts, gc_tint, points, i, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_shapefile_map:Too few points:%d, Skipping XFillPolygon()", npoints); } (void)XSetFillStyle(XtDisplay(w), gc_tint, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap_alerts, gc_tint, points, l16(i), CoordModeOrigin); } else if (map_color_fill && draw_filled) // Land masses? { if (polygon_hole_flag) { (void)XSetForeground(XtDisplay(w), gc_temp, colors[fill_color]); if (i >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap, gc_temp, points, i, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_shapefile_map:Too few points:%d, Skipping XFillPolygon()", npoints); } } else /* no polygon hole */ { (void)XSetForeground(XtDisplay(w), gc, colors[fill_color]); if (i >= 3) { (void)XFillPolygon(XtDisplay (w), pixmap, gc, points, i, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_shapefile_map:Too few points:%d, Skipping XFillPolygon()", npoints); } } (void)XSetForeground(XtDisplay(w), gc, colors[color]); // border color // Draw a thicker border for city boundaries (void)XSetForeground(XtDisplay(w), gc, colors[color]); // border (void)XSetFillStyle(XtDisplay(w), gc, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(i), CoordModeOrigin); } else // Use whatever color is defined by this point. { (void)XSetLineAttributes(XtDisplay(w), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetFillStyle(XtDisplay(w), gc, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(i), CoordModeOrigin); } } } // Free the storage that we allocated to hold // the "hole" flags for the shape. free(polygon_hole_storage); if (polygon_hole_flag) { //Free the temporary GC that we may have used to //draw polygons using the clip-mask: XFreeGC(XtDisplay(w), gc_temp); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Done with drawing shapes, now draw labels //////////////////////////////////////////////////////////////////////////////////////////////////// temp = name; // Set fill style back to defaults, or labels will get // stippled along with polygons! XSetFillStyle(XtDisplay(w), gc, FillSolid); /* XXX - figure out how to set this from dbfawk: */ if (quad_overlay_flag) { if (fieldcount >= 5) { // Use just the last two characters of // the quad index. "44072-A3" converts // to "A3" temp = DBFReadStringAttribute( hDBF, structure, 4 ); xastir_snprintf(quad_label, sizeof(quad_label), "%s ", &temp[strlen(temp) - 2]); // Append the name of the quad temp = DBFReadStringAttribute( hDBF, structure, 0 ); strncat(quad_label, temp, sizeof(quad_label) - 1 - strlen(quad_label)); } else { quad_label[0] = '\0'; } } if ( (temp != NULL) && (strlen(temp) != 0) && map_labels && !skip_label ) { int temp_ok; if (debug_level & 16) { fprintf(stderr,"I think I should display labels\n"); } ok = 1; // Convert to Xastir coordinates: // If quad overlay shapefile, need to // snag the label coordinates from the DBF // file instead. Note that the coordinates // are for the bottom right corner of the // quad, so we need to shift it left by 7.5' // to make the label appear inside the quad // (attached to the bottom left corner in // this case). /* XXX - figure out how to do WITH_DBFAWK: */ if (quad_overlay_flag) { const char *dbf_temp; float lat_f; float lon_f; if (fieldcount >= 4) { dbf_temp = DBFReadStringAttribute( hDBF, structure, 2 ); if (1 != sscanf(dbf_temp, "%f", &lat_f)) { fprintf(stderr,"draw_shapefile_map:sscanf parsing error\n"); } dbf_temp = DBFReadStringAttribute( hDBF, structure, 3 ); if (1 != sscanf(dbf_temp, "%f", &lon_f)) { fprintf(stderr,"draw_shapefile_map:sscanf parsing error\n"); } lon_f = lon_f - 0.125; } else { lat_f = 0.0; lon_f = 0.0; } //fprintf(stderr,"Lat: %f, Lon: %f\t, Quad: %s\n", lat_f, lon_f, quad_label); temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)lon_f, (float)lat_f); } else // Not quad overlay, use vertices { // XXX - todo: center large polygon labels in the center (e.g. county boundary) /* center label in polygon bounding box */ temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, ((float)(object->dfXMax + object->dfXMin))/2.0, ((float)(object->dfYMax + object->dfYMin))/2.0); #ifdef notdef temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, (float)object->padfX[0], (float)object->padfY[0]); #endif // notdef } //fprintf(stderr,"%ld %ld\n", my_long, my_lat); if (!temp_ok) { fprintf(stderr,"draw_shapefile_map8: Problem converting from lat/lon\n"); ok = 0; x = 0; y = 0; } else { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. x = my_long - NW_corner_longitude; y = my_lat - NW_corner_latitude; x = x / scale_x; y = y / scale_y; // Labeling of polygons done here if (ok == 1 && ok_to_draw) { if (quad_overlay_flag) { draw_nice_string(w, pixmap, 0, x+2, y-1, (char*)quad_label, 0xf, 0x10, strlen(quad_label)); } else { #ifdef notdef (void)draw_label_text ( w, x, y, strlen(temp), colors[label_color], (char *)temp); #endif // notdef if (debug_level & 16) { fprintf(stderr, " displaying label %s with color %x\n", temp,label_color); } (void)draw_centered_label_text(w, -90, x, y, strlen(temp), colors[label_color], (char *)temp, font_size); } } } } break; case SHPT_MULTIPOINT: case SHPT_MULTIPOINTZ: // Not implemented. fprintf(stderr,"Shapefile Multi-Point format files aren't supported!\n"); break; default: // Not implemented. fprintf(stderr,"Shapefile format not supported: Subformat unknown (default clause of switch)!\n"); break; } // End of switch } SHPDestroyObject( object ); // Done with this structure } // Free our hash of label strings, if any. Each hash entry may // have a linked list attached below it. for (i = 0; i < 256; i++) { ptr2 = label_hash[i]; while (ptr2 != NULL) { label_hash[i] = ptr2->next; //fprintf(stderr,"free: %s\n",ptr2->label); free(ptr2); ptr2 = label_hash[i]; } } dbfawk_free_info(fld_info); if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } DBFClose( hDBF ); SHPClose( hSHP ); // XmUpdateDisplay (XtParent (da)); if (debug_level & 16) { fprintf(stderr,"High-Mark Index:%d,\tHigh-Mark i:%d\n", high_water_mark_index, high_water_mark_i); } // Set fill style back to defaults XSetFillStyle(XtDisplay(w), gc, FillSolid); } // End of draw_shapefile_map() // This function will delete any pre-loaded dbfawk sigs and clear Dbf_sigs // This will trigger a reload the first time a shapfile is redisplayed void clear_dbfawk_sigs(void) { // fprintf(stderr,"Clearing signatures.\n"); if (Dbf_sigs ) { dbfawk_free_sigs(Dbf_sigs); Dbf_sigs = NULL; } } #endif // HAVE_LIBSHP Xastir-Release-2.2.2/src/map_tif.c000066400000000000000000002530751501463444000167340ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #define DOS_HDR_LINES 8 #define GRID_MORE 5000 extern int npoints; /* tsk tsk tsk -- globals */ extern int mag; #ifdef HAVE_LIBGEOTIFF #include "xtiffio.h" //#include "geotiffio.h" #include "geo_normalize.h" // Must be last include file #include "leak_detection.h" /********************************************************** * get_alt_fgd_path() * * Used to search for .fgd in ../metadata subdir, as it is * laid out on a USGS CDROM. **********************************************************/ void get_alt_fgd_path(char *fullpath, int fullpath_length) { int len; int i, j = 0; char *dir = fullpath; char fname[MAX_FILENAME]; // Split up into directory and filename len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i]; break; } } for (++i; i <= len; i++) { fname[j++] = fullpath[i]; // Grab the filename if (fullpath[i] == '\0') { break; } } // We have the filename now. dir now points to // the '/' at the end of the path. // Now do it again to knock off the "data" subdirectory // from the end. dir[0] = '\0'; // Terminate the current string, wiping out the '/' character len = (int)strlen (fullpath); // Length of the new shortened string for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i + 1]; // Dir now points to one past the '/' character break; } } for (++i; i <= len; i++) { if (fullpath[i] == '\0') { break; } } // Add "metadata/" into the path xastir_snprintf(dir, fullpath_length, "metadata/%s", fname); //fprintf(stderr,"FGD Directory: %s\n", fullpath); } /********************************************************** * get_alt_fgd_path2() * * Used to search for .fgd in Metadata subdir. This function * is no longer used. **********************************************************/ void get_alt_fgd_path2(char *fullpath, int fullpath_length) { int len; int i, j = 0; char *dir = fullpath; char fname[MAX_FILENAME]; // Split up into directory and filename len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i + 1]; break; } } for (++i; i <= len; i++) { fname[j++] = fullpath[i]; if (fullpath[i] == '\0') { break; } } // Add "Metadata/" into the path xastir_snprintf(dir, fullpath_length, "Metadata/%s", fname); } /*********************************************************** * read_fgd_file() * * Read in the "*.fgd" file associated with the geoTIFF * file. Get the corner points from it and return. If * no fgd file exists for this map, return a 0. ***********************************************************/ int read_fgd_file ( char* tif_filename, float* f_west_bounding, float* f_east_bounding, float* f_north_bounding, float* f_south_bounding) { char fgd_file[MAX_FILENAME];/* Complete path/name of .fgd file */ FILE *fgd; /* Filehandle of .fgd file */ char line[MAX_FILENAME]; /* One line from .fgd file */ int length; char *ptr; /* Substring pointer */ int num_coordinates = 0; /* Read the .fgd file to find corners of the map neat-line */ xastir_snprintf(fgd_file, sizeof(fgd_file), "%s", tif_filename); length = strlen(fgd_file); /* Change the extension to ".fgd" */ fgd_file[length-3] = 'f'; fgd_file[length-2] = 'g'; fgd_file[length-1] = 'd'; if (debug_level & 512) { fprintf(stderr,"%s\n",fgd_file); } /* * Search for the WEST/EAST/NORTH/SOUTH BOUNDING COORDINATES * in the .fgd file. */ fgd = fopen (fgd_file, "r"); // Try an alternate path (../metadata/ subdirectory) if the first path didn't work // This allows working with USGS maps directly from CDROM if (fgd == NULL) { get_alt_fgd_path(fgd_file, sizeof(fgd_file) ); if (debug_level & 512) { fprintf(stderr,"%s\n",fgd_file); } fgd = fopen (fgd_file, "r"); } if (fgd != NULL) { while ( ( !feof (fgd) ) && ( num_coordinates < 4 ) ) { get_line (fgd, line, MAX_FILENAME); if (*f_west_bounding == 0.0) { if ( ( (ptr = strstr(line, "WEST BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "West_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 25, " %f", f_west_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"West Bounding: %f\n",*f_west_bounding); } num_coordinates++; } } else if (*f_east_bounding == 0.0) { if ( ( (ptr = strstr(line, "EAST BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "East_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 25, " %f", f_east_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"East Bounding: %f\n",*f_east_bounding); } num_coordinates++; } } else if (*f_north_bounding == 0.0) { if ( ( (ptr = strstr(line, "NORTH BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "North_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 26, " %f", f_north_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"North Bounding: %f\n",*f_north_bounding); } num_coordinates++; } } else if (*f_south_bounding == 0.0) { if ( ( (ptr = strstr(line, "SOUTH BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "South_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 26, " %f", f_south_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"South Bounding: %f\n",*f_south_bounding); } num_coordinates++; } } } fclose (fgd); } else { if (debug_level & 512) fprintf(stderr,"Couldn't open '.fgd' file, assuming no map collar to chop %s\n", tif_filename); return(0); } /* * We should now have exactly four bounding coordinates. * These specify the map neat-line corners. We can use * them to chop off the white collar from around the map. */ if (num_coordinates != 4) { fprintf(stderr,"Couldn't find 4 bounding coordinates in '.fgd' file, map %s\n", tif_filename); return(0); } if (debug_level & 512) { fprintf(stderr,"%f %f %f %f\n", *f_south_bounding, *f_north_bounding, *f_west_bounding, *f_east_bounding); } return(1); /* Successful */ } /*********************************************************** * draw_geotiff_image_map() * * Here's where we handle geoTIFF files, such as USGS DRG * topo maps. The .fgd file gives us the lat/lon of the map * neat-line corners for USGS maps. We use this info to * chop off the white map border. If no .fgd file is present, * we assume there is no map collar to be cropped and display * every pixel. * We also translate from the map datum to WGS84. We use * libgeotiff/libtiff/libproj for these operations. * TODO: * Provide support for datums other than NAD27/NAD83/WGS84. * Libproj doesn't currently support many datums. * * Provide support for handling different map projections. * Perhaps by reprojecting the map data and storing it on * disk in another format. * * Select 'o', 'f', 'k', or 'c' maps based on zoom level. * Might also put some hysteresis in this so that it keeps * the current type of map through one extra zoom each way. * 'c': Good from x256 to x064. * 'f': Good from x128 to x032. Not very readable at x128. * 'k': Good from x??? to x???. * 'o': Good from x064 to x004. Not very readable at x64. ***********************************************************/ void draw_geotiff_image_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags *mdf) { char file[MAX_FILENAME]; /* Complete path/name of image file */ char short_filenm[MAX_FILENAME]; TIFF *tif = (TIFF *) 0; /* Filehandle for tiff image file */ GTIF *gtif = (GTIF *) 0; /* GeoKey-level descriptor */ /* enum { VERSION = 0, MAJOR, MINOR }; */ int versions[3]; uint32 width; /* Width of the image */ uint32 height; /* Height of the image */ uint16 bitsPerSample; /* Should be 8 for USGS DRG's */ uint16 samplesPerPixel = 1; /* Should be 1 for USGS DRG's. Some maps don't have this tag so we default to 1 */ uint32 rowsPerStrip; /* Should be 1 for USGS DRG's */ uint16 planarConfig; /* Should be 1 for USGS DRG's */ uint16 photometric; /* DRGs are RGB (2) */ int bytesPerRow; /* Bytes per scanline row of tiff file */ GTIFDefn defn; /* Stores geotiff details */ u_char *imageMemory; /* Fixed pointer to same memory area */ uint32 row; /* My row counter for the loop */ int num_colors; /* Number of colors in the geotiff colormap */ uint16 *red_orig, *green_orig, *blue_orig; /* Used for storing geotiff colors */ XColor my_colors[256]; /* Used for translating colormaps */ unsigned long west_bounding = 0; unsigned long east_bounding = 0; unsigned long north_bounding = 0; unsigned long south_bounding = 0; float f_west_bounding = 0.0; float f_east_bounding = 0.0; float f_north_bounding = 0.0; float f_south_bounding = 0.0; unsigned long west_bounding_wgs84 = 0; unsigned long east_bounding_wgs84 = 0; unsigned long north_bounding_wgs84 = 0; unsigned long south_bounding_wgs84 = 0; float f_NW_x_bounding; float f_NW_y_bounding; float f_NE_x_bounding; float f_NE_y_bounding; float f_SW_x_bounding; float f_SW_y_bounding; float f_SE_x_bounding; float f_SE_y_bounding; unsigned long NW_x_bounding_wgs84 = 0; unsigned long NW_y_bounding_wgs84 = 0; double f_NW_x_bounding_wgs84 = 0.0; double f_NW_y_bounding_wgs84 = 0.0; unsigned long NE_x_bounding_wgs84 = 0; unsigned long NE_y_bounding_wgs84 = 0; double f_NE_x_bounding_wgs84 = 0.0; double f_NE_y_bounding_wgs84 = 0.0; unsigned long SW_x_bounding_wgs84 = 0; unsigned long SW_y_bounding_wgs84 = 0; double f_SW_x_bounding_wgs84 = 0.0; double f_SW_y_bounding_wgs84 = 0.0; unsigned long SE_x_bounding_wgs84 = 0; unsigned long SE_y_bounding_wgs84 = 0; double f_SE_x_bounding_wgs84 = 0.0; double f_SE_y_bounding_wgs84 = 0.0; int NW_x = 0; /* Store pixel values for map neat-line */ int NW_y = 0; /* ditto */ int NE_x = 0; /* ditto */ int NE_y = 0; /* ditto */ int SW_x = 0; /* ditto */ int SW_y = 0; /* ditto */ int SE_x = 0; /* ditto */ int SE_y = 0; /* ditto */ int left_crop; /* Pixel cropping value */ int right_crop; /* Pixel cropping value */ int top_crop; /* Pixel cropping value */ int bottom_crop; /* Pixel cropping value */ double xxx, yyy; /* LFM: needs more accuracy here */ long sxx, syy; /* X Y screen plot positions */ float steph; float stepw; int stepwc, stephc; char map_it[MAX_FILENAME]; /* Used to hold filename for status line */ int have_fgd; /* Tells where we have an associated *.fgd file */ //short datum; char *datum_name; /* Points to text name of datum */ //double *GeoTie; int crop_it = 0; /* Flag which tells whether the image should be cropped */ uint32 column; float xastir_left_x_increment; float left_x_increment; float xastir_left_y_increment; float left_y_increment; float xastir_right_x_increment; float right_x_increment; float xastir_right_y_increment; float right_y_increment; float xastir_top_y_increment; float top_y_increment; float xastir_bottom_y_increment; float bottom_y_increment; // float xastir_avg_y_increment; float avg_y_increment; int row_offset; unsigned long current_xastir_left; unsigned long current_xastir_right; uint32 current_left; uint32 current_right; // uint32 current_line_width; unsigned long xastir_current_y; uint32 column_offset; unsigned long xastir_current_x; double *PixelScale; int have_PixelScale; uint16 qty; int SkipRows; unsigned long view_min_x, view_max_x; unsigned long view_min_y, view_max_y; unsigned long xastir_total_y; int NW_line_offset; int NE_line_offset; int NW_xastir_x_offset; int NE_xastir_x_offset; int NW_xastir_y_offset; int NW_x_offset; int NE_x_offset; float xastir_avg_left_right_y_increment; float total_avg_y_increment; unsigned long view_left_minus_pixel_width; unsigned long view_top_minus_pixel_height; int proj_is_latlong; short PCS; int usgs_drg; char *imagedesc; usgs_drg = mdf->usgs_drg; // yes, no, or auto if (debug_level & 16) { fprintf(stderr,"%s/%s\n", dir, filenm); } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display (one that fits the // status line more closely). Subtract the length of the // "Indexing " and/or "Loading " strings as well. if (strlen(filenm) > (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filenm) - avail; xastir_snprintf(short_filenm, sizeof(short_filenm), "..%s", &filenm[new_len]); } else { xastir_snprintf(short_filenm, sizeof(short_filenm), "%s", filenm); } /* Check whether we have an associated *.fgd file. This * file contains the neat-line corner points for USGS DRG * maps, which allows us to chop off the map collar. */ have_fgd = read_fgd_file( file, &f_west_bounding, &f_east_bounding, &f_north_bounding, &f_south_bounding ); /* * If we are able to read the fgd file then we have the lat/lon * corner points in floating point variables. If there isn't * an fgd file then we must get the info from the geotiff * tags themselves and we assume that there's no map collar to * chop off. */ /* * What we NEED to do (implemented a bit later in this function * in order to support geotiff files created with other map * datums, is to open up the geotiff file and get the map datum * used for the data. Then convert the corner points to WGS84 * and check to see whether the image is inside our viewport. * Some USGS geotiff maps have map data in NAD83 datum and the * .fgd file incorrectly specifying NAD27 datum. There are also * some USGS geotiff maps created with WGS84 datum. */ /* convert_to_xastir_coordinates( x,y,longitude,latitude ); */ if (have_fgd) /* Could be a USGS file */ { int temp_ok1, temp_ok2; if (debug_level & 16) { fprintf(stderr,"FGD: W:%f E:%f N:%f S:%f\n", f_west_bounding, f_east_bounding, f_north_bounding, f_south_bounding); } crop_it = 1; /* The map collar needs to be cropped */ temp_ok1 = convert_to_xastir_coordinates( &west_bounding, &north_bounding, f_west_bounding, f_north_bounding ); temp_ok2 = convert_to_xastir_coordinates( &east_bounding, &south_bounding, f_east_bounding, f_south_bounding ); if (!temp_ok1 || !temp_ok2) { fprintf(stderr,"draw_geotiff_image_map: problem converting from lat/lon\n"); return; } /* * Check whether map is inside our current view. It'd be * good to do a datum conversion first, but we don't know * what the datum is by this point in the code. I'm just * doing this check here for speed, so that I can eliminate * maps that aren't even close to our viewport area, without * having to open those map files. All other maps that pass * this test (at the next go-around later in the code) must * have their corner points datum-shifted so that we can * REALLY tell whether a map fits within the viewport. * * Perhaps add a bit to the corners (the max datum shift?) * to do our quick check? I decided to add about 10 seconds * to the map edges, which equates to 1000 in the Xastir * coordinate system. That should be greater than any datum * shift in North America for USGS topos. I'm artificially * inflating the size of the map just for this quick * elimination check. * * bottom top left right */ // Check whether we're indexing or drawing the map if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { // We're drawing. if (!map_visible( south_bounding + 1000, north_bounding - 1000, west_bounding - 1000, east_bounding + 1000 ) ) { if (debug_level & 16) { fprintf(stderr,"Map not within current view.\n"); fprintf(stderr,"Skipping map: %s\n", file); } // Map isn't inside our current view. We're done. // Free any memory used and return. // return; // Skip this map } else { if (debug_level & 16) { fprintf(stderr,"Map is viewable\n"); } } } } // End of if have_fgd /* * At this point the map MAY BE in our current view. * We don't know for sure until we do a datum translation * on the bounding coordinates and check again. Note that * if there's not an accompanying .fgd file, we don't have * the bounding coordinates yet by this point. */ if (debug_level & 16) { fprintf(stderr,"XTIFFOpen\n"); } /* Open TIFF descriptor to read GeoTIFF tags */ tif = XTIFFOpen (file, "r"); if (!tif) { return; } if (debug_level & 16) { fprintf(stderr,"GTIFNew\n"); } /* Open GTIF Key parser. Keys will be read at this time */ gtif = GTIFNew (tif); if (!gtif) { /* Close the TIFF file descriptor */ XTIFFClose (tif); return; } if (debug_level & 16) { fprintf(stderr,"GTIFDirectoryInfo\n"); } /* * Get the GeoTIFF directory info. Need this for * some of the operations further down in the code. */ GTIFDirectoryInfo (gtif, versions, 0); /* if (versions[MAJOR] > 1) { fprintf(stderr,"This file is too new for me\n"); GTIFFree (gtif); XTIFFClose (tif); return; } */ if (debug_level & 16) { fprintf(stderr,"GTIFGetDefn\n"); } /* I might want to attempt to avoid the GTIFGetDefn * call, as it takes a bit of time per file. It * normalizes the info. Try getting just the tags * or keys that I need individually instead. I * need "defn" for the GTIFProj4ToLatLong calls though. */ if (GTIFGetDefn (gtif, &defn)) { if (debug_level & 16) { GTIFPrintDefn (&defn, stdout); } } else { fprintf(stderr,"GTIFGetDefn failed\n"); } proj_is_latlong=FALSE; if( !GTIFKeyGet(gtif,ProjectedCSTypeGeoKey, &PCS,0,1)) { // fprintf(stderr,"Warning: no PCS in geotiff file %s, assuming map is in lat/lon!\n", filenm); proj_is_latlong=TRUE; } /* Fetch a few TIFF fields for this image */ if ( !TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) ) { width = 5493; fprintf(stderr,"No width tag found in file, setting it to 5493\n"); } if ( !TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) ) { height = 6840; fprintf(stderr,"No height tag found in file, setting it to 6840\n"); } // If we're autodetecting usgs_drg, check the image description tag // Note, the TIFFGetField doesn't allocate a string, it returns a pointer // to an existing one. Don't free it! if (usgs_drg == 2) { if ( TIFFGetField (tif, TIFFTAG_IMAGEDESCRIPTION, &imagedesc)) { if (strncasecmp(imagedesc,"USGS GeoTIFF DRG",16) == 0) { usgs_drg = 1; // Yes } else { usgs_drg = 0; // No } } else { usgs_drg = 0; // No tag, assume not a usgs topo } } /* * If we don't have an associated .fgd file for this map, * check for corner points in the ImageDescription * tag (proposed new USGS DRG standard). Boundary * coordinates will be the outside corners of the image * unless I can find some other proof. * Currently I assume that the map has no * map collar to chop off and set the neat-line corners * to be the outside corners of the image. * * NOTE: For the USGS files (with a map collar), the * image must be cropped and rotated and is slightly * narrower at one end (top for northern hemisphere, bottom * for southern hemisphere). For other files with no map * collar, the image is rectangular but the lat/lon * coordinates may be rotated. */ if (!have_fgd) // Not a USGS map or perhaps a newer spec { crop_it = 1; /* crop this map image */ /* * Snag and parse ImageDescription tag here. */ /* Code goes here for getting ImageDescription tag... */ /* Figure out the bounding coordinates for this map */ if (debug_level & 16) { fprintf(stderr,"\nCorner Coordinates:\n"); } /* Find lat/lon for NW corner of image */ xxx = 0.0; yyy = 0.0; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) // Do all 4 of these in one call? { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Upper Left" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) // Do all 4 of these in one call? { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_NW_x_bounding = (float)xxx; f_NW_y_bounding = (float)yyy; /* Find lat/lon for NE corner of image */ xxx = width - 1; yyy = 0.0; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_NE_x_bounding = (float)xxx; f_NE_y_bounding = (float)yyy; /* Find lat/lon for SW corner of image */ xxx = 0.0; yyy = height - 1; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_SW_x_bounding = (float)xxx; f_SW_y_bounding = (float)yyy; /* Find lat/lon for SE corner of image */ xxx = width - 1; yyy = height - 1; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_SE_x_bounding = (float)xxx; f_SE_y_bounding = (float)yyy; if (f_NW_y_bounding > 0) { yyy=((f_NW_y_bounding > f_NE_y_bounding) ? f_NE_y_bounding : f_NW_y_bounding); xxx=((f_SW_y_bounding < f_SE_y_bounding) ? f_SE_y_bounding : f_SW_y_bounding); } else { yyy=((f_NW_y_bounding < f_NE_y_bounding) ? f_NE_y_bounding : f_NW_y_bounding); xxx=((f_SW_y_bounding > f_SE_y_bounding) ? f_SE_y_bounding : f_SW_y_bounding); } f_north_bounding = (float)yyy; f_south_bounding = (float)xxx; if (f_NE_x_bounding > 0) { xxx=((f_NE_x_bounding < f_SE_x_bounding) ? f_SE_x_bounding : f_NE_x_bounding); yyy=((f_NW_x_bounding > f_SW_x_bounding) ? f_SW_x_bounding : f_NW_x_bounding); } else { xxx=((f_NE_x_bounding > f_SE_x_bounding) ? f_SE_x_bounding : f_NE_x_bounding); yyy=((f_NW_x_bounding < f_SW_x_bounding) ? f_SW_x_bounding : f_NW_x_bounding); } f_west_bounding = (float)yyy; f_east_bounding = (float)xxx; } f_NW_x_bounding = f_west_bounding; f_NW_y_bounding = f_north_bounding; f_SW_x_bounding = f_west_bounding; f_SW_y_bounding = f_south_bounding; f_NE_x_bounding = f_east_bounding; f_NE_y_bounding = f_north_bounding; f_SE_x_bounding = f_east_bounding; f_SE_y_bounding = f_south_bounding; // Fill in the wgs84 variables so we can do a datum // conversion but keep our original values also. f_NW_x_bounding_wgs84 = f_NW_x_bounding; f_NW_y_bounding_wgs84 = f_NW_y_bounding; f_SW_x_bounding_wgs84 = f_SW_x_bounding; f_SW_y_bounding_wgs84 = f_SW_y_bounding; f_NE_x_bounding_wgs84 = f_NE_x_bounding; f_NE_y_bounding_wgs84 = f_NE_y_bounding; f_SE_x_bounding_wgs84 = f_SE_x_bounding; f_SE_y_bounding_wgs84 = f_SE_y_bounding; /* Get the datum */ // GTIFKeyGet( gtif, GeogGeodeticDatumGeoKey, &datum, 0, 1 ); // if (debug_level & 16) // fprintf(stderr,"GeogGeodeticDatumGeoKey: %d\n", datum ); /* Get the tiepoints (in UTM coordinates always?) * In our case they look like: * * 0.000000 Y * 0.000000 X * 0.000000 Z * 572983.025771 Y in UTM (longitude for some maps?) * 5331394.085064 X in UTM (latitude for some maps?) * 0.000000 Z * */ /* if (debug_level & 16) { fprintf(stderr,"Tiepoints:\n"); if ( TIFFGetField( tif, TIFFTAG_GEOTIEPOINTS, &qty, &GeoTie ) ) { for ( i = 0; i < qty; i++ ) { fprintf(stderr,"%f\n", *(GeoTie + i) ); } } } */ /* Get the geotiff horizontal datum name */ if ( defn.Datum != 32767 ) { GTIFGetDatumInfo( defn.Datum, &datum_name, NULL ); if (debug_level & 16) { fprintf(stderr,"Datum: %d/%s\n", defn.Datum, datum_name ); } } /* * Perform a datum shift on the bounding coordinates before we * check whether the map is inside our viewport. At the moment * this is still hard-coded to NAD27 datum. If the map is already * in WGS84 or NAD83 datum, skip the datum conversion code. */ if ( (defn.Datum != 6030) /* DatumE_WGS84 */ && (defn.Datum != 6326) /* Datum_WGS84 */ && (defn.Datum != 6269) ) /* Datum_North_American_Datum_1983 */ { if (debug_level & 16) { fprintf(stderr,"***** Attempting Datum Conversions\n"); } // This code uses datum.h/datum.c to do the conversion // instead of the proj.4 library as we had before. // Here we assume that if it's not one of the three datums // listed above, it's NAD27. // Convert NW corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_NW_y_bounding_wgs84, &f_NW_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert NE corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_NE_y_bounding_wgs84, &f_NE_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert SW corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_SW_y_bounding_wgs84, &f_SW_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert SE corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_SE_y_bounding_wgs84, &f_SE_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS (131) } else if (debug_level & 16) { fprintf(stderr,"***** Skipping Datum Conversion\n"); } /* * Convert new datum-translated bounding coordinates to the * Xastir coordinate system. * convert_to_xastir_coordinates( x,y,longitude,latitude ) */ // NW corner if (!convert_to_xastir_coordinates( &NW_x_bounding_wgs84, &NW_y_bounding_wgs84, (float)f_NW_x_bounding_wgs84, (float)f_NW_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // NE corner if (!convert_to_xastir_coordinates( &NE_x_bounding_wgs84, &NE_y_bounding_wgs84, (float)f_NE_x_bounding_wgs84, (float)f_NE_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // SW corner if (!convert_to_xastir_coordinates( &SW_x_bounding_wgs84, &SW_y_bounding_wgs84, (float)f_SW_x_bounding_wgs84, (float)f_SW_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // SE corner if (!convert_to_xastir_coordinates( &SE_x_bounding_wgs84, &SE_y_bounding_wgs84, (float)f_SE_x_bounding_wgs84, (float)f_SE_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } /* * Check whether map is inside our current view. These * are the real datum-shifted bounding coordinates now, * so this is the final decision as to whether the map * should be loaded. */ // Find the largest dimensions if (NW_y_bounding_wgs84 <= NE_y_bounding_wgs84) { north_bounding_wgs84 = NW_y_bounding_wgs84; } else { north_bounding_wgs84 = NE_y_bounding_wgs84; } if (NW_x_bounding_wgs84 <= SW_x_bounding_wgs84) { west_bounding_wgs84 = NW_x_bounding_wgs84; } else { west_bounding_wgs84 = SW_x_bounding_wgs84; } if (SW_y_bounding_wgs84 >= SE_y_bounding_wgs84) { south_bounding_wgs84 = SW_y_bounding_wgs84; } else { south_bounding_wgs84 = SE_y_bounding_wgs84; } if (NE_x_bounding_wgs84 >= SE_x_bounding_wgs84) { east_bounding_wgs84 = NE_x_bounding_wgs84; } else { east_bounding_wgs84 = SE_x_bounding_wgs84; } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Indexing ... // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only south_bounding_wgs84, // Bottom north_bounding_wgs84, // Top west_bounding_wgs84, // Left east_bounding_wgs84, // Right 0); // Default Map Level //Free any memory used and return /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); return; // Done indexing this file } else { xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... } // bottom top left right if (!map_visible( south_bounding_wgs84, north_bounding_wgs84, west_bounding_wgs84, east_bounding_wgs84 ) ) { if (debug_level & 16) { fprintf(stderr,"Map not within current view.\n"); fprintf(stderr,"Skipping map: %s\n", file); } /* * Map isn't inside our current view. We're done. * Free any memory used and return */ /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); return; /* Skip this map */ } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* From running in debug mode: Width: 5493 Height: 6840 Rows Per Strip: 1 Bits Per Sample: 8 Samples Per Pixel: 1 Planar Config: 1 */ /* Fetch a few TIFF fields for this image */ if ( !TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric) ) { photometric = PHOTOMETRIC_RGB; fprintf(stderr,"No photometric tag found in file, setting it to RGB\n"); } if ( !TIFFGetField (tif, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip) ) { rowsPerStrip = 1; fprintf(stderr,"No rowsPerStrip tag found in file, setting it to 1\n"); } if ( !TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample) ) { bitsPerSample = 8; fprintf(stderr,"No bitsPerSample tag found in file, setting it to 8\n"); } if ( !TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel) ) { samplesPerPixel = 1; fprintf(stderr,"No samplesPerPixel tag found in file, setting it to 1\n"); } if ( !TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planarConfig) ) { planarConfig = 1; fprintf(stderr,"No planarConfig tag found in file, setting it to 1\n"); } if (debug_level & 16) { fprintf(stderr," Width: %ld\n", (long int)width); fprintf(stderr," Height: %ld\n", (long int)height); fprintf(stderr," Photometric: %d\n", photometric); fprintf(stderr," Rows Per Strip: %ld\n", (long int)rowsPerStrip); fprintf(stderr," Bits Per Sample: %d\n", bitsPerSample); fprintf(stderr,"Samples Per Pixel: %d\n", samplesPerPixel); fprintf(stderr," Planar Config: %d\n", planarConfig); } /* * Check for properly formatted geoTIFF file. If it isn't * in the standard format we're looking for, spit out an * error message and return. * * Should we also check compression method here? */ /* if ( ( rowsPerStrip != 1) */ if ( (samplesPerPixel != 1) || ( bitsPerSample != 8) || ( planarConfig != 1) ) { fprintf(stderr,"*** geoTIFF file %s is not in the proper format:\n", file); if (samplesPerPixel != 1) fprintf(stderr,"***** Has %d samples per pixel instead of 1\n", samplesPerPixel); if (bitsPerSample != 8) fprintf(stderr,"***** Has %d bits per sample instead of 8\n", bitsPerSample); if (planarConfig != 1) fprintf(stderr,"***** Has planarConfig of %d instead of 1\n", planarConfig); fprintf(stderr,"*** Please reformat it and try again.\n"); XTIFFClose(tif); return; } if (debug_level & 16) { fprintf(stderr,"Loading geoTIFF map: %s\n", file); } /* * Snag the original map colors out of the colormap embedded * inside the tiff file. */ if (photometric == PHOTOMETRIC_PALETTE) { if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &red_orig, &green_orig, &blue_orig)) { TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag"); GTIFFree (gtif); XTIFFClose (tif); return; } } /* Here are the number of possible colors. It turns out to * be 256 for a USGS geotiff file, of which only the first * 13 are used. Other types of geotiff's may use more * colors (and do). A proposed revision to the USGS DRG spec * allows using more colors. */ num_colors = (1L << bitsPerSample); /* Print out the colormap info */ //if (debug_level & 16) { // int l; // // for (l = 0; l < num_colors; l++) // fprintf(stderr," %5u: %5u %5u %5u\n", // l, // red_orig[l], // green_orig[l], // blue_orig[l]); //} // Example output from a USGS 7.5' map: // // 0: 0 0 0 black // 1: 65280 65280 65280 light grey // 2: 0 38656 41984 // 3: 51968 0 5888 // 4: 33536 16896 9472 contour lines, brownish-red // 5: 51456 59904 40192 green // 6: 35072 13056 32768 purple? freeways, some roads // 7: 65280 59904 0 // 8: 42752 57856 57856 blue, bodies of water // 9: 65280 47104 47104 red brick color, cities? // 10: 55808 45824 54784 purple. freeways, some roads // 11: 53504 53504 53504 grey // 12: 52992 41984 36352 contour lines, tan, more dots/less lines // 13: 0 0 0 black, unused slot? // 14: 0 0 0 black, unused slot? // 15: 0 0 0 black, unused slot? // 16: 0 0 0 black, unused slot? // The rest are all 0's. if (crop_it) // USGS geoTIFF map { /* * Next: * Convert the map neat-line corners to image x/y coordinates. * This will give the map neat-line coordinates in pixels. * Use this data to chop the image at these boundaries * and to stretch the shorter lines to fit a rectangle. * * Note that at this stage we're using the bounding coordinates * that are in the map original datum so that the translations * to pixel coordinates will be correct. * * Note that we already have the datum-shifted values for all * the corners in the *_wgs84 variables. In short: We use the * non datum-shifted values to work with the tiff file, and the * datum-shifted values to plot the points in Xastir. */ HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (debug_level & 16) fprintf(stderr,"\nNW neat-line corner = %f\t%f\n", f_NW_x_bounding, f_NW_y_bounding); xxx = (double)f_NW_x_bounding; yyy = (double)f_NW_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) // Do all 4 in one call? { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) // Do all 4 in one call? { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } NW_x = (int)(xxx + 0.5); /* Tricky way of rounding */ NW_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", NW_x, NW_y); } if (NW_x < 0 || NW_y < 0 || NW_x >= (int)width || NW_y >= (int)height) { fprintf(stderr, "\nWarning: NW Neat-line corner calculated at x:%d, y:%d, %s\n", NW_x, NW_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (NW_x < 0) { NW_x = 0; } if (NW_x >= (int)width) { NW_x = width - 1; } if (NW_y < 0) { NW_y = 0; } if (NW_y >= (int)height) { NW_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"NE neat-line corner = %f\t%f\n", f_NE_x_bounding, f_NE_y_bounding); xxx = (double)f_NE_x_bounding; yyy = (double)f_NE_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } NE_x = (int)(xxx + 0.5); /* Tricky way of rounding */ NE_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", NE_x, NE_y); } if (NE_x < 0 || NE_y < 0 || NE_x >= (int)width || NE_y >= (int)height) { fprintf(stderr, "\nWarning: NE Neat-line corner calculated at x:%d, y:%d, %s\n", NE_x, NE_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (NE_x < 0) { NE_x = 0; } if (NE_x >= (int)width) { NE_x = width - 1; } if (NE_y < 0) { NE_y = 0; } if (NE_y >= (int)height) { NE_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"SW neat-line corner = %f\t%f\n", f_SW_x_bounding, f_SW_y_bounding); xxx = (double)f_SW_x_bounding; yyy = (double)f_SW_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } SW_x = (int)(xxx + 0.5); /* Tricky way of rounding */ SW_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", SW_x, SW_y); } if (SW_x < 0 || SW_y < 0 || SW_x >= (int)width || SW_y >= (int)height) { fprintf(stderr, "\nWarning: SW Neat-line corner calculated at x:%d, y:%d, %s\n", SW_x, SW_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (SW_x < 0) { SW_x = 0; } if (SW_x >= (int)width) { SW_x = width - 1; } if (SW_y < 0) { SW_y = 0; } if (SW_y >= (int)height) { SW_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"SE neat-line corner = %f\t%f\n", f_SE_x_bounding, f_SE_y_bounding); xxx = (double)f_SE_x_bounding; yyy = (double)f_SE_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } SE_x = (int)(xxx + 0.5); /* Tricky way of rounding */ SE_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", SE_x, SE_y); } if (SE_x < 0 || SE_y < 0 || SE_x >= (int)width || SE_y >= (int)height) { fprintf(stderr, "\nWarning: SE Neat-line corner calculated at x:%d, y:%d, %s\n", SE_x, SE_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (SE_x < 0) { SE_x = 0; } if (SE_x >= (int)width) { SE_x = width - 1; } if (SE_y < 0) { SE_y = 0; } if (SE_y >= (int)height) { SE_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } } else /* * No map collar to crop off, so we already know * where the corner points are. This is for non-USGS * maps. */ { NW_x = 0; NW_y = 0; NE_x = width - 1; NE_y = 0; SW_x = 0; SW_y = height - 1; SE_x = width - 1; SE_y = height - 1; } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Here's where we crop off part of the black border for USGS maps. if (crop_it) // USGS maps only { int i = 3; NW_x += i; NW_y += i; NE_x -= i; NE_y += i; SW_x += i; SW_y -= i; SE_x -= i; SE_y -= i; } // Now figure out the rough pixel crop values from what we know. // Image rotation means a simple rectangular crop isn't sufficient. if (NW_y < NE_y) { top_crop = NW_y; } else { top_crop = NE_y; } if (SW_y > SE_y) { bottom_crop = SW_y; } else { bottom_crop = SE_y; } if (NE_x > SE_x) { right_crop = NE_x; } else { right_crop = SE_x; } if (NW_x < SW_x) { left_crop = NW_x; } else { left_crop = SW_x; } if (!crop_it) /* If we shouldn't crop the map collar... */ { top_crop = 0; bottom_crop = height - 1; left_crop = 0; right_crop = width - 1; } // The four crop variables are the maximum rectangle that we // wish to keep, rotation notwithstanding (we may want to crop // part of some lines due to rotation). Crop all lines/pixels // outside these ranges. //WE7U if (top_crop < 0 || top_crop >= (int)height) { top_crop = 0; } if (bottom_crop < 0 || bottom_crop >= (int)height) { bottom_crop = height - 1; } if (left_crop < 0 || left_crop >= (int)width) { left_crop = 0; } if (right_crop < 0 || right_crop >= (int)width) { right_crop = width - 1; } if (debug_level & 16) { fprintf(stderr,"Crop points (pixels):\n"); fprintf(stderr,"Top: %d\tBottom: %d\tLeft: %d\tRight: %d\n", top_crop, bottom_crop, left_crop, right_crop); } /* * The color map is embedded in the geoTIFF file as TIFF tags. * We get those tags out of the file and translate to our own * colormap. * Allocate colors for the map image. We allow up to 256 colors * and allow only 8-bits per pixel in the original map file. We * get our 24-bit RGB colors right out of the map file itself, so * the colors should look right. * We're picking existing colormap colors that are closest to * the original map colors, so we shouldn't run out of colors * for other applications. * * Brightness adjust for the colors? Implemented in the * "raster_map_intensity" variable below. */ { int l; switch (photometric) { case PHOTOMETRIC_PALETTE: for (l = 0; l < num_colors; l++) { my_colors[l].red = (uint16)(red_orig[l] * raster_map_intensity); my_colors[l].green = (uint16)(green_orig[l] * raster_map_intensity); my_colors[l].blue = (uint16)(blue_orig[l] * raster_map_intensity); if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; case PHOTOMETRIC_MINISBLACK: for (l = 0; l < num_colors; l++) { int v = (l * 255) / (num_colors-1); my_colors[l].red = my_colors[l].green = my_colors[l].blue = (uint16)(v * raster_map_intensity) << 8; if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; case PHOTOMETRIC_MINISWHITE: for (l = 0; l < num_colors; l++) { int v = (((num_colors-1)-l) * 255) / (num_colors-1); my_colors[l].red = my_colors[l].green = my_colors[l].blue = (uint16)(v * raster_map_intensity) << 8; if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; } } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Each data value should be an 8-bit value, which is a // pointer into a color // table. Later we perform a translation from the geoTIFF // color table to our current color table (matching values // as close as possible), at the point where we're writing // the image to the pixmap. /* We should be ready now to actually read in some * pixels and deposit them on the screen. We will * allocate memory for the data area based on the * sizes of fields and data in the geoTIFF file. */ bytesPerRow = TIFFScanlineSize(tif); if (debug_level & 16) { fprintf(stderr,"\nInitial Bytes Per Row: %d\n", bytesPerRow); } // Here's a tiny malloc that'll hold only one scanline worth of pixels imageMemory = (u_char *) malloc(bytesPerRow + 2); CHECKMALLOC(imageMemory); // TODO: Figure out the middle boundary on each edge for // lat/long and adjust the crop values to match the largest // of either the middle or the corners for each edge. This // will help to handle edges that are curved. /* * There are some optimizations that can still be done: * * 1) Read in all scanlines but throw away unneeded pixels, * paying attention not to lose smaller details. Compare * neighboring pixels? * * 3) Keep a map cache or a screenmap cache to reduce need * for reading map files so often. */ // Here we wish to start at the top line that may have // some pixels of interest and proceed to the bottom line // of interest. Process scanlines from top_crop to bottom_crop. // Start at the left/right_crop pixels, compute the lat/long // of each, using x/y increments so we can quickly scan across // the line. // Iterate across the line checking whether each pixel is // within the viewport. If so, plot it on the pixmap at // the correct scale. // Later I may wish to get the lat/lon of each pixel and plot // it at the correct point, to handle the curvature of each // line (this might be VERY slow). Right now I treat them as // straight lines. // At this point we have these variables defined. The // first column contains map corners in Xastir coordinates, // the second column contains map corners in pixels: // // NW corner: // NW_x_bounding_wgs84 <-> NW_x // NW_y_bounding_wgs84 <-> NW_y // // NE corner: // NE_x_bounding_wgs84 <-> NE_x // NE_y_bounding_wgs84 <-> NE_y // // SW corner: // SW_x_bounding_wgs84 <-> SW_x // SW_y_bounding_wgs84 <-> SW_y // // SE corner: // SE_x_bounding_wgs84 <-> SE_x // SE_y_bounding_wgs84 <-> SE_y // I should be able to use these variables to figure out // the xastir coordinates of each scanline pixel using // linear interpolation along each edge. // // I don't want to use the crop values in general. I'd // rather crop properly along the neat line instead of a // rectangular crop. // // Define lines along the left/right edges so that I can // compute the Xastir coordinates of each pixel along these // two lines. These will be the start/finish of each of my // scanlines, and I can use these values to compute the // x/y_increment values for each line. This way I can // stretch short lines as I go along, and auto-crop the // white border as well. // Left_line goes from (top to bottom): // NW_x,NW_y -> SW_x,SW_y // and from: // west_bounding_wgs84,north_bounding_wgs84 -> west_bounding_wgs84,south_bounding_wgs84 // // Right_line goes from(top to bottom): // NE_x,NE_y -> SE_x,SE-Y // and from: // east_bounding_wgs84,north_bounding_wgs84 -> east_bounding_wgs84,south_bounding_wgs84 // // Simpler: Along each line, Xastir coordinates change how much // and in what direction as we move down one scanline? // These increments are how much we change in Xastir coordinates and // in pixel coordinates as we move down either the left or right // neatline one pixel. // Be prepared for 0 angle of rotation as well (x-increments = 0). // Xastir Coordinate System: // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // Watch out for division by zero here. // // Left Edge X Increment Per Scanline (Going from top to bottom). // This increment will help me to keep track of the left edge of // the image, both in Xastir coordinates and in pixel coordinates. // if (SW_y != NW_y) { // Xastir coordinates xastir_left_x_increment = (float) (1.0 * labs( (long)SW_x_bounding_wgs84 - (long)NW_x_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SW_y - NW_y)); // Pixel coordinates left_x_increment = (float)(1.0 * abs(SW_x - NW_x) / abs(SW_y - NW_y)); if (SW_x_bounding_wgs84 < NW_x_bounding_wgs84) { xastir_left_x_increment = -xastir_left_x_increment; } if (SW_x < NW_x) { left_x_increment = -left_x_increment; } //WE7U //if (abs(left_x_increment) > (width/10)) { // left_x_increment = 0.0; // xastir_left_x_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_left_x_increment: %f %ld %ld %f %d %d %d %d\n", xastir_left_x_increment, SW_x_bounding_wgs84, NW_x_bounding_wgs84, left_x_increment, SW_x, NW_x, bottom_crop, top_crop); } else { // Xastir coordinates xastir_left_x_increment = 0; // Pixel coordinates left_x_increment = 0; } // // Left Edge Y Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the left edge of // the image, both in Xastir coordinates and in pixel coordinates. // if (SW_y != NW_y) { // Xastir coordinates xastir_left_y_increment = (float) (1.0 * labs( (long)SW_y_bounding_wgs84 - (long)NW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SW_y - NW_y)); // Pixel coordinates left_y_increment = (float)1.0; // Aren't we going down one pixel each time? if (SW_y_bounding_wgs84 < NW_y_bounding_wgs84) // Ain't gonn'a happen { xastir_left_y_increment = -xastir_left_y_increment; } //WE7U //if (abs(left_y_increment) > (width/10)) { // xastir_left_y_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_left_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_left_y_increment, SW_y_bounding_wgs84, NW_y_bounding_wgs84, left_y_increment, SW_y, NW_y, bottom_crop, top_crop); } else { // Xastir coordinates xastir_left_y_increment = 0; // Pixel coordinates left_y_increment = 0; } // // Right Edge X Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the right edge of // the image, both in Xastir coordinates and image coordinates. // if (SE_y != NE_y) { // Xastir coordinates xastir_right_x_increment = (float) (1.0 * labs( (long)SE_x_bounding_wgs84 - (long)NE_x_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_y - NE_y)); // Pixel coordinates right_x_increment = (float)(1.0 * abs(SE_x - NE_x) / abs(SE_y - NE_y)); if (SE_x_bounding_wgs84 < NE_x_bounding_wgs84) { xastir_right_x_increment = -xastir_right_x_increment; } if (SE_x < NE_x) { right_x_increment = -right_x_increment; } //WE7U //if (abs(right_x_increment) > (width/10)) { // right_x_increment = 0.0; // xastir_right_x_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_right_x_increment: %f %ld %ld %f %d %d %d %d\n", xastir_right_x_increment, SE_x_bounding_wgs84, NE_x_bounding_wgs84, right_x_increment, SE_x, NE_x, bottom_crop, top_crop); } else { // Xastir coordinates xastir_right_x_increment = 0; // Pixel coordinates right_x_increment = 0; } // // Right Edge Y Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the right edge of // the image, both in Xastir coordinates and in image coordinates. // if (SE_y != NE_y) { // Xastir coordinates xastir_right_y_increment = (float) (1.0 * labs( (long)SE_y_bounding_wgs84 - (long)NE_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_y - NE_y)); // Pixel coordinates right_y_increment = (float)1.0; // Aren't we going down one pixel each time? if (SE_y_bounding_wgs84 < NE_y_bounding_wgs84) // Ain't gonn'a happen { xastir_right_y_increment = -xastir_right_y_increment; } //WE7U //if (abs(right_y_increment) > (width/10)) { // xastir_right_y_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_right_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_right_y_increment, SE_y_bounding_wgs84, NE_y_bounding_wgs84, right_y_increment, SE_y, NE_y, bottom_crop, top_crop); } else { // Xastir coordinates xastir_right_y_increment = 0; // Pixel coordinates right_y_increment = 0; } if (debug_level & 16) { fprintf(stderr," Left x increments: %f %f\n", xastir_left_x_increment, left_x_increment); fprintf(stderr," Left y increments: %f %f\n", xastir_left_y_increment, left_y_increment); fprintf(stderr,"Right x increments: %f %f\n", xastir_right_x_increment, right_x_increment); fprintf(stderr,"Right y increments: %f %f\n", xastir_right_y_increment, right_y_increment); } // Compute how much "y" changes per pixel as we traverse from left to right // along a scanline along the top of the image. // // Top Edge Y Increment Per X-Pixel Width (Going from left to right). // This increment will help me to get rid of image rotation. // if (NE_x != NW_x) { // Xastir coordinates xastir_top_y_increment = (float) (1.0 * labs( (long)NE_y_bounding_wgs84 - (long)NW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(NE_x - NW_x)); // And a "+ 1.0" here? // Pixel coordinates top_y_increment = (float)(1.0 * abs(NE_y - NW_y) / abs(NE_x - NW_x)); if (NE_y_bounding_wgs84 < NW_y_bounding_wgs84) { xastir_top_y_increment = -xastir_top_y_increment; } if (NE_y < NW_y) { top_y_increment = -top_y_increment; } if (debug_level & 16) fprintf(stderr,"xastir_top_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_top_y_increment, NE_y_bounding_wgs84, NW_y_bounding_wgs84, top_y_increment, NE_y, NW_y, right_crop, left_crop); } else { // Xastir coordinates xastir_top_y_increment = 0; // Pixel coordinates top_y_increment = 0; } // Compute how much "y" changes per pixel as you traverse from left to right // along a scanline along the bottom of the image. // // Bottom Edge Y Increment Per X-Pixel Width (Going from left to right). // This increment will help me to get rid of image rotation. // if (SE_x != SW_x) { // Xastir coordinates xastir_bottom_y_increment = (float) (1.0 * labs( (long)SE_y_bounding_wgs84 - (long)SW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_x - SW_x)); // And a "+ 1.0" here? // Pixel coordinates bottom_y_increment = (float)(1.0 * abs(SE_y - SW_y) / abs(SE_x - SW_x)); if (SE_y_bounding_wgs84 < SW_y_bounding_wgs84) { xastir_bottom_y_increment = -xastir_bottom_y_increment; } if (SE_y < SW_y) { bottom_y_increment = -bottom_y_increment; } if (debug_level & 16) fprintf(stderr,"xastir_bottom_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_bottom_y_increment, SE_y_bounding_wgs84, SW_y_bounding_wgs84, bottom_y_increment, SE_y, SW_y, right_crop, left_crop); } else { // Xastir coordinates xastir_bottom_y_increment = 0; // Pixel coordinates bottom_y_increment = 0; } // Find the average change in Y as we traverse from left to right one pixel // xastir_avg_y_increment = (float)(xastir_top_y_increment + xastir_bottom_y_increment) / 2.0; avg_y_increment = (float)(top_y_increment + bottom_y_increment) / 2.0; // Find edges of current viewport in Xastir coordinates // view_min_x = NW_corner_longitude; // left edge of view if (view_min_x > 129600000l) { view_min_x = 0; } view_max_x = SE_corner_longitude; // right edge of view if (view_max_x > 129600000l) { view_max_x = 129600000l; } view_min_y = NW_corner_latitude; // top edge of view if (view_min_y > 64800000l) { view_min_y = 0; } view_max_y = SE_corner_latitude; // bottom edge of view if (view_max_y > 64800000l) { view_max_y = 64800000l; } /* Get the pixel scale */ have_PixelScale = TIFFGetField( tif, TIFFTAG_GEOPIXELSCALE, &qty, &PixelScale ); if (debug_level & 16) { if (have_PixelScale) { fprintf(stderr,"PixelScale: %f %f %f\n", *PixelScale, *(PixelScale + 1), *(PixelScale + 2) ); } else { fprintf(stderr,"No PixelScale tag found in file\n"); } } // Use PixelScale to determine lines to skip at each // zoom level? // O-size map: // ModelPixelScaleTag (1,3): // 2.4384 2.4384 0 // // F-size map: // ModelPixelScaleTag (1,3): // 10.16 10.16 0 // // C-size map: // ModelPixelScaleTag (1,3): // 25.400001 25.400001 0 // if (debug_level & 16) { fprintf(stderr,"Size: x %ld, y %ld\n", scale_x,scale_y); } // I tried to be very aggressive with the scaling factor // below (3.15) in order to skip the most possible rows // to speed things up. If you see diagonal lines across // the maps, increase this number (up to a max of 4.0 // probably). A higher number means less rows skipped, // which improves the look but slows the map drawing down. // // This needs modification somewhat when the raster is already in // lat/long, and the PixelScale is already in degrees per pixel. // The scale_y is the integer number of hundredths of seconds per pixel. // The decision of how many rows to skip can simply be made by converting // the PixelScale to the same units as scale_y, and skipping accordingly. if (have_PixelScale) { double coef; if (!proj_is_latlong) { coef = 3.15; } else { coef=100*60*60; // xastir coords are in 1/100 of a second, // and lat/lon pixel scales will be in degrees } SkipRows = (int)( ( scale_y / ( *PixelScale * coef ) ) + 0.5 ); if (SkipRows < 1) { SkipRows = 1; } if (SkipRows > (int)(height / 10) ) { SkipRows = height / 10; } } else { SkipRows = 1; } if (debug_level & 16) { fprintf(stderr,"SkipRows: %d\n", SkipRows); } // Use SkipRows to set increments for the loops below. if ( top_crop <= 0 ) { top_crop = 0; // First row of image } if ( ( bottom_crop + 1) >= (int)height ) { bottom_crop = height - 1; // Last row of image } // Here I pre-compute some of the values I'll need in the // loops below in order to save some time. NW_line_offset = (int)(NW_y - top_crop); NE_line_offset = (int)(NE_y - top_crop); NW_xastir_x_offset = (int)(xastir_left_x_increment * NW_line_offset); NE_xastir_x_offset = (int)(xastir_right_x_increment * NE_line_offset); NW_xastir_y_offset = (int)(xastir_left_y_increment * NW_line_offset); NW_x_offset = (int)(1.0 * left_x_increment * NW_line_offset); NE_x_offset = (int)(1.0 * right_x_increment * NE_line_offset); xastir_avg_left_right_y_increment = (float)((xastir_right_y_increment + xastir_left_y_increment) / 2.0); total_avg_y_increment = (float)(xastir_avg_left_right_y_increment * avg_y_increment); // (Xastir bottom - Xastir top) / height //steph = (double)( (left_y_increment + right_y_increment) / 2); // NOTE: This one does not take into account current height steph = (float)( (SW_y_bounding_wgs84 - NW_y_bounding_wgs84) / (1.0 * (SW_y - NW_y) ) ); // Compute scaled pixel size for XFillRectangle stephc = (int)( ( (1.50 * steph / scale_x) + 1.0) + 1.5); view_top_minus_pixel_height = (unsigned long)(view_min_y - steph); HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (imageMemory) { free(imageMemory); } GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Set the bit-blitting function to XOR. This is only used if // DRG_XOR_colors is set to a non-zero value, but we set it here // outside the pixel loop for speed reasons. // if (DRG_XOR_colors) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt,JoinMiter); // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); // yellow // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x0f]); // White // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x03]); // cyan // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x06]); // orange (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); } // Iterate over the rows of interest only. Using the rectangular // top/bottom crop values for these is ok at this point. // // Put row multipliers above loops. Try to get as many // multiplications as possible outside the loops. Adds and // subtracts are ok. Try to do as little floating point stuff // as possible inside the loops. // for ( row = top_crop; (int)row < bottom_crop + 1; row+= SkipRows ) { int skip = 0; HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (imageMemory) { free(imageMemory); } GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Our offset from the top row of the map neatline // (kind of... ignoring rotation anyway). row_offset = row - top_crop; //fprintf(stderr,"row_offset: %d\n", row_offset); // Compute the line end-points in Xastir coordinates // Initially was a problem here: Offsetting from NW_x_bounding but // starting at top_crop line. Fixed by last term added to two // equations below. current_xastir_left = (unsigned long) ( NW_x_bounding_wgs84 + ( 1.0 * xastir_left_x_increment * row_offset ) - NW_xastir_x_offset ); current_xastir_right = (unsigned long) ( NE_x_bounding_wgs84 + ( 1.0 * xastir_right_x_increment * row_offset ) - NE_xastir_x_offset ); //if (debug_level & 16) // fprintf(stderr,"Left: %ld Right: %ld\n", // current_xastir_left, // current_xastir_right); // In pixel coordinates: current_left = (int) ( NW_x + ( 1.0 * left_x_increment * row_offset ) + 0.5 - NW_x_offset ); current_right = (int) ( NE_x + ( 1.0 * right_x_increment * row_offset ) + 0.5 - NE_x_offset ); //WE7U: This comparison is always false: current_left is unsigned //therefore always positive! //if (current_left < 0) // current_left = 0; if (current_right >= width) { current_right = width - 1; } // current_line_width = current_right - current_left + 1; // Pixels // if (debug_level & 16) // fprintf(stderr,"Left: %ld Right: %ld Width: %ld\n", // current_left, // current_right, current_line_width); // Compute original pixel size in Xastir coordinates. Note // that this can change for each scanline in a USGS geoTIFF. // (Xastir right - Xastir left) / width-of-line // Need the "1.0 *" or the math will be incorrect (won't be a float) stepw = (float)( (current_xastir_right - current_xastir_left) / (1.0 * (current_right - current_left) ) ); // if (debug_level & 16) // fprintf(stderr,"\t\t\t\t\t\tPixel Width: %f\n",stepw); // Compute scaled pixel size for XFillRectangle stepwc = (int)( ( (1.0 * stepw / scale_x) + 1.0) + 0.5); // In Xastir coordinates xastir_current_y = (unsigned long)(NW_y_bounding_wgs84 + (xastir_left_y_increment * row_offset) ); xastir_current_y = (unsigned long)(xastir_current_y - NW_xastir_y_offset); view_left_minus_pixel_width = view_min_x - stepw; // Check whether any part of the scanline will be within the // view. If so, read the scanline from the file and iterate // across the pixels. If not, skip this line altogether. // Compute right edge of image xastir_total_y = (unsigned long) ( xastir_current_y - ( total_avg_y_increment * (current_right - current_left) ) ); // Check left edge y-value then right edge y-value. // If either are within view, process the line, else skip it. if ( ( ( xastir_current_y <= view_max_y) && (xastir_total_y >= view_top_minus_pixel_height) ) || ( ( xastir_total_y <= view_max_y ) && ( xastir_total_y >= view_top_minus_pixel_height ) ) ) { // Read one geoTIFF scanline if (TIFFReadScanline(tif, imageMemory, row, 0) < 0) { break; // No more lines to read or we couldn't read the file at all } // Iterate over the columns of interest, skipping the left/right // cropped pixels, looking for pixels that fit within our viewport. // for ( column = current_left; column < (current_right + 1); column++ ) { skip = 0; column_offset = column - current_left; // Pixels //fprintf(stderr,"Column Offset: %ld\n", column_offset); // Pixels //fprintf(stderr,"Current Left: %ld\n", current_left); // Pixels xastir_current_x = (unsigned long) current_xastir_left + (stepw * column_offset); // In Xastir coordinates // Left line y value minus // avg y-increment per scanline * avg y-increment per x-pixel * column_offset xastir_total_y = (unsigned long) ( xastir_current_y - ( total_avg_y_increment * column_offset ) ); //fprintf(stderr,"Xastir current: %ld %ld\n", xastir_current_x, xastir_current_y); // Check whether pixel fits within boundary lines (USGS maps) // This is how we get rid of the last bit of white border at // the top and bottom of the image. if (have_fgd) // USGS map { if ( (xastir_total_y > SW_y_bounding_wgs84) || (xastir_total_y < NW_y_bounding_wgs84) ) { skip++; } // Here's a trick to make it look like the map pages join better. // If we're within a certain distance of a border, change any black // pixels to white (changes map border to less obtrusive color). if ( *(imageMemory + column) == 0x00 ) // If pixel is Black { if ( (xastir_total_y > (SW_y_bounding_wgs84 - 25) ) || (xastir_total_y < (NW_y_bounding_wgs84 + 25) ) || (xastir_current_x < (SW_x_bounding_wgs84 + 25) ) || (xastir_current_x > (SE_x_bounding_wgs84 - 25) ) ) { //WE7U: column is unsigned so "column >= 0" is always true // if ((int)column < bytesPerRow && column >= 0) { if ((int)column < bytesPerRow) { *(imageMemory + column) = 0x01; // Change to White } else { //WE7U // fprintf(stderr,"draw_geotiff_image_map: Bad fgd file for map?: %s\n", filenm); } } } } /* Look for left or right map boundaries inside view */ if ( !skip && ( xastir_current_x <= view_max_x ) && ( xastir_current_x >= view_left_minus_pixel_width ) && ( xastir_total_y <= view_max_y ) && ( xastir_total_y >= view_top_minus_pixel_height ) ) { // Here are the corners of our viewport, using the Xastir // coordinate system. Notice that Y is upside down: // // left edge of view = NW_corner_longitude // right edge of view = SE_corner_longitude // top edge of view = NW_corner_latitude // bottom edge of view = SE_corner_latitude // Compute the screen position of the pixel and scale it sxx = (xastir_current_x - NW_corner_longitude) / scale_x; syy = (xastir_total_y - NW_corner_latitude ) / scale_y; // If we wish some colors to be transparent, we could check for a // color match here and refuse to draw those that are on our list of // transparent colors. Might be useful for drawing say contour // lines on top of satellite images. Since the USGS topo's use the // same colormap for all of the topo's (I believe that is true) then // we could just compare on the index into the array instead of the // color contents in the array. // // Example output from a USGS 7.5' map: // // 0: 0 0 0 black // 1: 65280 65280 65280 light grey // 2: 0 38656 41984 // 3: 51968 0 5888 // 4: 33536 16896 9472 contour lines, brownish-red // 5: 51456 59904 40192 green // 6: 35072 13056 32768 purple? freeways, some roads // 7: 65280 59904 0 // 8: 42752 57856 57856 blue, bodies of water // 9: 65280 47104 47104 red brick color, cities? // 10: 55808 45824 54784 purple. freeways, some roads // 11: 53504 53504 53504 grey // 12: 52992 41984 36352 contour lines, tan, more dots/less lines // 13: 0 0 0 black, unused slot? // 14: 0 0 0 black, unused slot? // 15: 0 0 0 black, unused slot? // 16: 0 0 0 black, unused slot? // The rest are all 0's. // either show all colors (usgs_drg==0) or show selected // colors (usgs_drg == 1) if ( usgs_drg == 0 || (usgs_drg ==1 && (*(imageMemory + column) >= 13 || DRG_show_colors[*(imageMemory + column)] == 1))) { // If this is set, use gc_tint for drawing // with "GXxor" as the bit-blit operation. // if (DRG_XOR_colors) { // Draw the pixel using "gc_tint" // instead of "gc". XSetForeground (XtDisplay (w), gc_tint, my_colors[*(imageMemory + column)].pixel); XFillRectangle (XtDisplay (w), pixmap, gc_tint, sxx, syy, stepwc, stephc); } else { // Set the color for the pixel XSetForeground (XtDisplay (w), gc, my_colors[*(imageMemory + column)].pixel); // And draw the pixel XFillRectangle (XtDisplay (w), pixmap, gc, sxx, syy, stepwc, stephc); } } } } } } /* Free up any malloc's that we did */ if (imageMemory) { free(imageMemory); } if (debug_level & 16) { fprintf(stderr,"%d rows read in\n", (int) row); } /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); // Close the filehandles that are left open after the // four GTIFImageToPCS calls. //(void)CSVDeaccess(NULL); } #endif /* HAVE_LIBGEOTIFF */ Xastir-Release-2.2.2/src/maps.c000066400000000000000000012102771501463444000162530ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //#define MAP_SCALE_CHECK #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define GRID_MORE 5000 #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } // Check for XPM and/or ImageMagick. We use "NO_GRAPHICS" // to disable some routines below if the support for them // is not compiled in. #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK)) #define NO_GRAPHICS 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK) #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM)) #define NO_XPM 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM) void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color); int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize); // Constants defining the color of the labeled grid border. int outline_border_labels = TRUE; // if true put an outline around the border labels int border_foreground_color = 0x20; // color of the map border, if shown // 0x08 is black. // 0x20 is white. int outline_border_labels_color = 0x20; // outline_border_labels_color = border_foreground_color; // color of outline to draw around border labels // use color of border to help make text more legible. // Print options Widget print_properties_dialog = (Widget)NULL; static xastir_mutex print_properties_dialog_lock; Widget print_postscript_dialog = (Widget)NULL; static xastir_mutex print_postscript_dialog_lock; Widget printer_data; Widget previewer_data; Widget rotate_90 = (Widget)NULL; Widget auto_rotate = (Widget)NULL; //char print_paper_size[20] = "Letter"; // Displayed in dialog, but not used yet. int print_rotated = 0; int print_auto_rotation = 0; //float print_scale = 1.0; // Not used yet. int print_auto_scale = 0; //int print_blank_background_color = 0; // Not used yet. int print_in_monochrome = 0; int print_resolution = 150; // 72 dpi is normal for Postscript. // 100 or 150 dpi work well with HP printer int print_invert = 0; // Reverses black/white char printer_program[MAX_FILENAME+1]; char previewer_program[MAX_FILENAME+1]; time_t last_snapshot = 0; // Used to determine when to take next snapshot time_t last_kmlsnapshot = 0; // Used to determine when to take next kml snapshot int doing_snapshot = 0; int snapshot_interval = 0; int mag; int npoints; /* number of points in a line */ float raster_map_intensity = 0.65; // Raster map color intensity, set from Maps->Map Intensity float imagemagick_gamma_adjust = 0.0; // Additional imagemagick map gamma correction, set from Maps->Adjust Gamma // Storage for the index file timestamp time_t map_index_timestamp; int grid_size = 0; // Rounding #ifndef HAVE_ROUNDF // Poor man's rounding, but rounds away from zero as roundf is supposed to. float roundf(float x) { int i; i= (((x)>=0)?(((x)+.5)):(((x)-.5))); return ((float)i); } #endif // UTM Grid stuff // //#define UTM_DEBUG //#define UTM_DEBUG_VERB //#define UTM_DEBUG_ALLOC // static inline int max_i(int a, int b) { return (a > b ? a : b); } #define UTM_GRID_EQUATOR 10000000 // the maximum number of UTM zones that will appear on a screen that has a // high enough resolution to display the within-zone utm grid #define UTM_GRID_MAX_ZONES 4 // the maximum number of grid lines in each direction shown in each zone // on the screen at one time #define UTM_GRID_MAX_COLS_ROWS 64 #define UTM_GRID_DEF_NALLOCED 8 #define UTM_GRID_RC_EMPTY 0xffff // the hash stores the upper left and lower right boundaries of the // display of a utm grid to determine whether it matches the current // screen boundaries or whether the grid needs to be recalculated // for the current screen. typedef struct { long ul_x; long ul_y; long lr_x; long lr_y; } hash_t; // The utm grid is drawn by connecting a grid of points marking the // intersection of the easting and northing lines. col_or_row holds // this grid of points for the portion of a utm zone visible on the // screen. Zone boundaries are not directly represented here. // In particular, the parallels separating lettered zone rows are // not directly represented here. typedef struct { int firstpoint; int npoints; int nalloced; XPoint *points; } col_or_row_t; // The portion of a utm zone visible on the screen has some number of // visible easting lines and northing lines forming a grid that covers // part or all of the screen. Zone holds arrays of the coordinates // of the visible easting and northing intersections, and the next set // of intersections off screen. The coarseness of this grid is // determined by the current scale and stored in utm_grid_spacing_m. typedef struct { unsigned int ncols; col_or_row_t col[UTM_GRID_MAX_COLS_ROWS]; unsigned int nrows; col_or_row_t row[UTM_GRID_MAX_COLS_ROWS]; int boundary_x; } zone_t; // A utm grid is represented by its hash (upper left and lower right coordinates) // which are used to check whether or not it fits the current screen or needs to // be recalculated, and an array of the zones visible on the screen, each containing // arrays of the points marking the easting/northing intersections of a zone (with // one or more lettered zone rows). typedef struct { hash_t hash; unsigned int nzones; zone_t zone[UTM_GRID_MAX_ZONES]; } utm_grid_t; utm_grid_t utm_grid; unsigned int utm_grid_spacing_m; // ^ the above is extern'ed in maps.h for use by draw_ruler_text in // db.c // Clear out/set up the UTM/MGRS minor grid intersection arrays. // // do_alloc = 0: Don't allocate memory // 1: Allocate memory for the points // // Returns: 0 if ok // 1 if malloc problem // int utm_grid_clear(int do_alloc) { int i, j; utm_grid.hash.ul_x = 0; utm_grid.hash.ul_y = 0; utm_grid.hash.lr_x = 0; utm_grid.hash.lr_y = 0; utm_grid.nzones = 0; for (i=0; i < UTM_GRID_MAX_ZONES; i++) { utm_grid.zone[i].ncols = utm_grid.zone[i].nrows = 0; utm_grid.zone[i].boundary_x = 0; for (j=0; j < UTM_GRID_MAX_COLS_ROWS; j++) { // // Clear out column arrays // utm_grid.zone[i].col[j].firstpoint = UTM_GRID_RC_EMPTY; utm_grid.zone[i].col[j].npoints = 0; if (utm_grid.zone[i].col[j].nalloced) { free(utm_grid.zone[i].col[j].points); } utm_grid.zone[i].col[j].nalloced = 0; utm_grid.zone[i].col[j].points = NULL; if (do_alloc) { // Allocate enough space for 8 points utm_grid.zone[i].col[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint)); if (!utm_grid.zone[i].col[j].points) { fprintf(stderr,"calloc(%d, %d) for z=%d col=%d FAILED!\n", UTM_GRID_DEF_NALLOCED, (int)sizeof(XPoint), i, j); // abort(); // Causes a segfault return(1); } utm_grid.zone[i].col[j].nalloced = UTM_GRID_DEF_NALLOCED; } // // Clear out row arrays // utm_grid.zone[i].row[j].firstpoint = UTM_GRID_RC_EMPTY; utm_grid.zone[i].row[j].npoints = 0; utm_grid.zone[i].row[j].nalloced = 0; if (utm_grid.zone[i].row[j].nalloced) { free(utm_grid.zone[i].row[j].points); } utm_grid.zone[i].row[j].nalloced = 0; utm_grid.zone[i].row[j].points = NULL; if (do_alloc) { // Allocate enough space for 8 points utm_grid.zone[i].row[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint)); if (!utm_grid.zone[i].row[j].points) { fprintf(stderr,"calloc(%d, %d) for z=%d row=%d FAILED!\n", UTM_GRID_DEF_NALLOCED, (int)sizeof(XPoint), i, j); // abort(); // Causes a segfault return(1); } utm_grid.zone[i].row[j].nalloced = UTM_GRID_DEF_NALLOCED; } } } return(0); } void maps_init(void) { fprintf(stderr,"\n\nBuilt-in map types:\n"); fprintf(stderr,"%10s USGS GNIS Datapoints\n","gnis"); fprintf(stderr,"%10s USGS GNIS Datapoints w/population\n","pop"); fprintf(stderr,"%10s APRSdos Maps\n","map"); fprintf(stderr,"%10s WinAPRS/MacAPRS/X-APRS Maps\n","map"); fprintf(stderr,"\nSupport for these additional map types has been compiled in: \n"); #ifdef HAVE_MAGICK fprintf(stderr,"%10s Image Map (ImageMagick/GraphicsMagick library, many formats allowed)\n","geo"); #endif // HAVE_MAGICK #ifndef NO_GRAPHICS #ifdef HAVE_LIBCURL fprintf(stderr,"%10s URL (Internet maps via libcurl library)\n","geo"); fprintf(stderr,"%10s URL (OpenStreetMaps via libcurl library\n","geo"); fprintf(stderr,"%10s Copyright OpenStreetMap and contributors, CC-BY-SA)\n", ""); #else #ifdef HAVE_WGET fprintf(stderr,"%10s URL (Internet maps via wget)\n","geo"); fprintf(stderr,"%10s URL (OpenStreetMaps via wget\n","geo"); fprintf(stderr,"%10s Copyright OpenStreetMap and contributors, CC-BY-SA)\n", ""); #endif // HAVE_WGET #endif // HAVE_LIBCURL #endif // NO_GRAPHICS #ifdef HAVE_LIBSHP fprintf(stderr,"%10s ESRI Shapefile Maps (Shapelib library)\n","shp"); #endif // HAVE_LIBSHP #ifdef HAVE_LIBGEOTIFF fprintf(stderr,"%10s USGS DRG Geotiff Topographic Maps (libgeotiff/libproj)\n","tif"); #endif // HAVE_LIBGEOTIFF #ifndef NO_XPM fprintf(stderr,"%10s X Pixmap Maps (XPM library)\n","xpm"); #endif // NO_XPM init_critical_section( &print_properties_dialog_lock ); init_critical_section( &print_postscript_dialog_lock ); // Clear the minor UTM/MGRS grid arrays. Do _not_ allocate // memory for the points. (void)utm_grid_clear(0); } /* * Calculate NS distance scale at a given location * in meters per Xastir unit */ double calc_dscale_y(long UNUSED(x), long UNUSED(y) ) { // approximation by looking at +/- 0.5 minutes offset // (void)(calc_distance(y-3000, x, y+3000, x)/6000.0); // but this scale is fixed at 1852/6000 return((double)(1852.0/6000.0)); } /* * Calculate EW distance scale at a given location * in meters per Xastir unit */ double calc_dscale_x(long x, long y) { // approximation by looking at +/- 0.5 minutes offset // we should find a better formula... return(calc_distance(y, x-3000, y, x+3000)/6000.0); } /* * Calculate x map scaling for current location * With that we could have equal distance scaling or a better * view for pixel maps */ long get_x_scale(long x, long y, long ysc) { long xsc; double sc_x; double sc_y; sc_x = calc_dscale_x(x,y); // meter per Xastir unit sc_y = calc_dscale_y(x,y); if (sc_x < 0.01 || ysc > 50000) // keep it near the poles (>88 deg) or if big parts of world seen { xsc = ysc; } else // adjust y scale, so that the distance is identical in both directions: { xsc = (long)(ysc * sc_y / sc_x +0.4999); } //fprintf(stderr,"Scale: x %5.3fkm/deg, y %5.3fkm/deg, x %ld y %ld\n",sc_x*360,sc_y*360,xsc,ysc); return(xsc); } /** MAP DRAWING ROUTINES **/ // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d() function below. This // function is set up for float values. See the clipt_long() and // clipt_int() functions for use with other types of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt(float p, float q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / p; if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / p; if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function is set up for float values. See the clip2d_long() // and clip2d_screen() functions for use with other types of values. // int clip2d(float *x0, float *y0, float *x1, float *y1) { float t0, t1; float delta_x, delta_y; int visible = False; float x_left, y_top; // NW corner of screen float x_right, y_bottom; // SE corner of screen // Assign floating point values for screen corners y_top = f_NW_corner_latitude; y_bottom = f_SE_corner_latitude; x_left = f_NW_corner_longitude; x_right = f_SE_corner_longitude; if ( ((*x0 < x_left) && (*x1 < x_left)) || ((*x0 > x_right) && (*x1 > x_right)) || ((*y0 < y_bottom) && (*y1 < y_bottom)) || ((*y0 > y_top) && (*y1 > y_top)) ) { // Both endpoints are on outside and same side of visible // region, so reject. return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } } } } return(visible); } // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d_long() function below. This // function is set up for Xastir coordinate values (unsigned longs). // See the clipt() and clipt_int() functions for use with other // types of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt_long(long p, long q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / (p * 1.0); if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / (p * 1.0); if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } //fprintf(stderr,"clipt_long: %d\n",accept); return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt_long() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function uses the Xastir coordinate system. We had to flip // y_bottom/y_top below due to the coordinate system being // upside-down. // // This function is set up for Xastir coordinate values (unsigned // longs). See the clip2d() or clip2d_screen() functions for use // with other types of values. // int clip2d_long(unsigned long *x0, unsigned long *y0, unsigned long *x1, unsigned long *y1) { float t0, t1; long delta_x, delta_y; int visible = False; unsigned long x_left = NW_corner_longitude; unsigned long x_right = SE_corner_longitude; // Reverse the following two as our Xastir coordinate system is // upside down. The algorithm requires this order. unsigned long y_top = SE_corner_latitude; unsigned long y_bottom = NW_corner_latitude; if ( ( (*x0 < x_left ) && (*x1 < x_left ) ) || ( (*x0 > x_right ) && (*x1 > x_right ) ) || ( (*y0 < y_bottom) && (*y1 < y_bottom) ) || ( (*y0 > y_top ) && (*y1 > y_top ) ) ) { // Both endpoints are on same side of visible region and // outside of it, so reject. //fprintf(stderr,"reject 1\n"); return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt_long(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt_long(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt_long(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt_long(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } else { //fprintf(stderr,"reject top\n"); } } else { //fprintf(stderr,"reject bottom\n"); } } else { //fprintf(stderr,"reject right\n"); } } else { //fprintf(stderr,"reject left\n"); } return(visible); } // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d_screen() function below. This // function is set up for screen coordinate values (unsigned ints). // See the clipt() and clipt_long functions for use with other types // of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt_int(int p, int q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / (p * 1.0); if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / (p * 1.0); if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } //fprintf(stderr,"clipt_int: %d\n",accept); return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt_int() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function uses the screen coordinate system. We had to flip // y_bottom/y_top below due to the coordinate system being // upside-down. // // This function is set up for screen coordinate values (unsigned // ints). See the clip2d() and clip2d_long() functions for use // with other types of values. // int clip2d_screen(unsigned int *x0, unsigned int *y0, unsigned int *x1, unsigned int *y1) { float t0, t1; int delta_x, delta_y; int visible = False; unsigned int x_right = screen_width; unsigned int x_left = 0; // Reverse the following two as our screen coordinate system is // upside down. The algorithm requires this order. unsigned int y_top = screen_height; unsigned int y_bottom = 0; if ( ( (*x0 < x_left ) && (*x1 < x_left ) ) || ( (*x0 > x_right ) && (*x1 > x_right ) ) || ( (*y0 < y_bottom) && (*y1 < y_bottom) ) || ( (*y0 > y_top ) && (*y1 > y_top ) ) ) { // Both endpoints are on same side of visible region and // outside of it, so reject. //fprintf(stderr,"reject 1\n"); return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt_int(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt_int(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt_int(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt_int(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } else { //fprintf(stderr,"reject top\n"); } } else { //fprintf(stderr,"reject bottom\n"); } } else { //fprintf(stderr,"reject right\n"); } } else { //fprintf(stderr,"reject left\n"); } return(visible); } // Draws a point onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. If the bounding box containing the point doesn't intersect // with the current view, the point isn't drawn. // // Input point is in the Xastir coordinate system. // void draw_point(Widget w, unsigned long x1, unsigned long y1, GC gc, Pixmap which_pixmap, int skip_duplicates) { int x1i, y1i; static int last_x1i; static int last_y1i; // Check whether the two bounding boxes intersect. If not, skip // the rest of this function. Do we need to worry about // special-case code here to handle vertical/horizontal lines // (width or length of zero)? // // // WE7U // Check to see if we can do this faster than map_visible() can. A // point is a special case that should take only four compares // against the map window boundaries. // if (!map_visible(y1, y1, x1, x1)) { // Skip this vector //fprintf(stderr,"Point not visible\n"); return; } // Convert to screen coordinates. Careful here! // The format conversions you'll need if you try to // compress this into two lines will get you into // trouble. x1i = x1 - NW_corner_longitude; x1i = x1i / scale_x; y1i = y1 - NW_corner_latitude; y1i = y1i / scale_y; if (skip_duplicates) { if (x1i == last_x1i && y1i == last_y1i) { return; } } // XDrawPoint uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. (void)XDrawPoint(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i)); last_x1i = x1i; last_y1i = y1i; } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. // // Input points are in lat/long coordinates. // void draw_point_ll(Widget w, float y1, // lat1 float x1, // long1 GC gc, Pixmap which_pixmap, int skip_duplicates) { unsigned long x1L, y1L; // // WE7U // We should probably do four floating point compares against the // map boundaries here in order to speed up rejection of points that // don't fit our window. If we change to that, copy the conversion- // to-screen-coordinates and drawing stuff from draw_point() down to // this routine so that we don't go through the comparisons again // there. // // Convert the point to the Xastir coordinate system. convert_to_xastir_coordinates(&x1L, &y1L, x1, y1); // Call the draw routine above. draw_point(w, x1L, y1L, gc, which_pixmap, skip_duplicates); } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. If the bounding box containing the vector doesn't intersect // with the current view, the line isn't drawn. // // Input points are in the Xastir coordinate system. // void draw_vector(Widget w, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2, GC gc, Pixmap which_pixmap, int skip_duplicates) { int x1i, x2i, y1i, y2i; static int last_x1i, last_x2i, last_y1i, last_y2i; //fprintf(stderr,"%ld,%ld %ld,%ld\t",x1,y1,x2,y2); if ( !clip2d_long(&x1, &y1, &x2, &y2) ) { // Skip this vector //fprintf(stderr,"Line not visible\n"); //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1,y1,x2,y2); return; } //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1,y1,x2,y2); // Convert to screen coordinates. Careful here! // The format conversions you'll need if you try to // compress this into two lines will get you into // trouble. x1i = x1 - NW_corner_longitude; x1i = x1i / scale_x; y1i = y1 - NW_corner_latitude; y1i = y1i / scale_y; x2i = x2 - NW_corner_longitude; x2i = x2i / scale_x; y2i = y2 - NW_corner_latitude; y2i = y2i / scale_y; if (skip_duplicates) { if (last_x1i == x1i && last_x2i == x2i && last_y1i == y1i && last_y2i == y2i) { return; } } // XDrawLine uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. // clip2d_long() should make sure of this anyway as it clips // lines to fit the window. // (void)XDrawLine(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i), l16(x2i), l16(y2i)); last_x1i = x1i; last_x2i = x2i; last_y1i = y1i; last_y2i = y2i; } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. // // Input points are in lat/long coordinates. // void draw_vector_ll(Widget w, float y1, // lat1 float x1, // long1 float y2, // lat2 float x2, // long2 GC gc, Pixmap which_pixmap, int skip_duplicates) { unsigned long x1L, x2L, y1L, y2L; int x1i, x2i, y1i, y2i; static int last_x1i, last_x2i, last_y1i, last_y2i; //fprintf(stderr,"%lf,%lf %lf,%lf\t",x1,y1,x2,y2); if ( !clip2d(&x1, &y1, &x2, &y2) ) { // Skip this vector //fprintf(stderr,"Line not visible: %lf,%lf %lf,%lf\n",y1,x1,y2,x2); return; } //fprintf(stderr,"%lf,%lf %lf,%lf\n",x1,y1,x2,y2); // Convert the points to the Xastir coordinate system. convert_to_xastir_coordinates(&x1L, &y1L, x1, y1); convert_to_xastir_coordinates(&x2L, &y2L, x2, y2); //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1L,y1L,x2L,y2L); // Convert to screen coordinates. Careful here! // The format conversions you'll need if you try to // compress this into two lines will get you into // trouble. x1i = (int)(x1L - NW_corner_longitude); x1i = x1i / scale_x; y1i = (int)(y1L - NW_corner_latitude); y1i = y1i / scale_y; x2i = (int)(x2L - NW_corner_longitude); x2i = x2i / scale_x; y2i = (int)(y2L - NW_corner_latitude); y2i = y2i / scale_y; if (skip_duplicates) { if (last_x1i == x1i && last_x2i == x2i && last_y1i == y1i && last_y2i == y2i) { // fprintf(stderr,"Duplicate line\n"); return; } } //fprintf(stderr,"NW_corner_latitude:%ld, NW_corner_longitude:%ld, scale_x:%ld, scale_y:%ld\n", // NW_corner_latitude, // NW_corner_longitude, // scale_x, // scale_y); //fprintf(stderr,"%d,%d %d,%d\n\n",x1i,y1i,x2i,y2i); // XDrawLine uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. // clip2d() should make sure of this anyway as it clips lines to // fit the window. // (void)XDrawLine(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i), l16(x2i), l16(y2i)); last_x1i = x1i; last_x2i = x2i; last_y1i = y1i; last_y2i = y2i; } // Find length of a standard string of seven zeroes in the border font. // Supporting function for draw_grid() and the grid drawing functions. int get_standard_border_string_width_pixels(Widget w, int length) { int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels. char seven_zeroes[8] = "0000000"; char five_zeroes[6] = "00000"; if (length==5) { string_width_pixels = get_rotated_label_text_length_pixels(w, five_zeroes, FONT_BORDER); } string_width_pixels = get_rotated_label_text_length_pixels(w, seven_zeroes, FONT_BORDER); return string_width_pixels; } // Find height of a standard string in the border font // Supporting function for draw_grid() and the grid drawing functions. int get_standard_border_string_height_pixels(Widget w) { int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels. char one_zero[2] = "0"; string_width_pixels = get_rotated_label_text_height_pixels(w, one_zero, FONT_BORDER); return string_width_pixels; } // Find out the width to use for the border to apply when uing a labeled grid. // Border width is determined from the height of the border font. // Supporting function for draw_grid() and the grid drawing functions. int get_border_width(Widget w) { int border_width = 14; // The width of the border to draw around the // map to place labeled tick marks into // should be an even number. // The default here is overidden by size of the border font. int string_height_pixels = 0; // Height of a string in the border font in pixels string_height_pixels = get_standard_border_string_height_pixels(w); // Rotated text functions used to draw the border text add some // blank space at the bottom of the text so make the border wide enough // to compensate for this. border_width = string_height_pixels + (string_height_pixels/2) + 1; // check to see if string_height_pixels is even if ((float)string_height_pixels/2.0!=floor((float)string_height_pixels/2.0)) { border_width++; } // we are using draw nice string to write the metadata in the top border, so // make sure the border is wide enough for it, even if the grid labels are small. if (border_width < 14) { border_width = 14; } return border_width; } // *********************************************************** // // get_horizontal_datum() // // Provides the current map datum. Current default is WGS84. // Parameters: datum, character array ponter for the string // that will be filled with the current datum // sizeof_datum, the size of the datum character array. // //*********************************************************** void get_horizontal_datum(char *datum, int sizeof_datum) { char metadata_datum[6] = "WGS84"; // datum to display in metadata on top border xastir_snprintf(datum, sizeof_datum, "%s", metadata_datum); if (sizeof_datum<6) { fprintf(stderr,"Datum [%s] truncated to [%s]\n",metadata_datum,datum); } } // Lat/Long coordinate system, draw lat/long lines. Called by // draw_grid() below. // void draw_complete_lat_lon_grid(Widget w) { int coord; char dash[2]; unsigned int x,x1,x2; unsigned int y,y1,y2; unsigned int stepsx; // spacing of grid lines unsigned int stepsy; // spacing of grid lines int coordinate_format; // Format to use for coordinates on border (e.g. decimal degrees). char grid_label[25]; // String to draw labels on grid lines int screen_width_xastir; // screen width in xastir units (1/100 of a second) // int screen_height_xastir; // screen height in xastir units (1/100 of a second) int border_width; // the width of the labeled border in pixels. int string_width_pixels = 0;// Width of a grid label string in pixels. float screen_width_degrees; // Width of the screen in degrees int log_screen_width_degrees; // Log10 of the screen width in degrees, used to scale degrees long xx2, yy2; long xx, yy; unsigned int last_label_end; // cordinate of the end of the previous label char metadata_datum[6]; // datum to display in metadata on top border char grid_label1[25]; // String to draw latlong metadata char grid_label2[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border if (!long_lat_grid) // We don't wish to draw a map grid { return; } // convert between selected coordinate format constant and display format constants if (coordinate_system == USE_DDDDDD) { coordinate_format = CONVERT_DEC_DEG; } else if (coordinate_system == USE_DDMMSS) { coordinate_format = CONVERT_DMS_NORMAL_FORMATED; } else { coordinate_format = CONVERT_HP_NORMAL_FORMATED; } border_width = get_border_width(w); // Find xastir coordinates of upper left and lower right corners. xx = NW_corner_longitude + (border_width * scale_x); yy = NW_corner_latitude + (border_width * scale_y); xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); screen_width_xastir = xx2 - xx; // screen_height_xastir = yy2 - yy; // Determine some parameters used in drawing the border. string_width_pixels = get_standard_border_string_width_pixels(w, 7); // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 64800000 xastir coordinates = 180 degrees // 360000 xastir coordinates = 1 degree // scale_x * (screen_width/10) = one tenth of the screen width in xastir coordinates // scale_x number of xastir coordinates per pixel screen_width_degrees = (float)(screen_width_xastir / (float)360000); log_screen_width_degrees = log10(screen_width_degrees); if (draw_labeled_grid_border==TRUE) { get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); // Put metadata in top border. // find location of upper left corner of map, convert to Lat/Long convert_lon_l2s(xx, grid_label1, sizeof(grid_label1), coordinate_format); convert_lat_l2s(yy, grid_label2, sizeof(grid_label2), coordinate_format); strcpy(grid_label, grid_label1); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, " "); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, grid_label2); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string // find location of lower right corner of map, convert to Lat/Long convert_lon_l2s(xx2, grid_label1, sizeof(grid_label1), coordinate_format); convert_lat_l2s(yy2, grid_label2, sizeof(grid_label2), coordinate_format); //"XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA002"), grid_label,grid_label1,grid_label2,metadata_datum); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } // A crude grid spacing can be obtained from scaling one tenth of the screen width. // This works, but puts the grid lines at arbitrary increments of a degree. //stepsx = (scale_x*(screen_width/10)); // Setting the grid using the base 10 log of the screen width in degrees allows // both scaling the grid to the screen and spacing the grid lines at appropriately // rounded increments of a degree. // // Set default grid to 0.1 degree. This will be used when the screen width is about 1 degree. stepsx = 36000; // if (log_screen_width_degrees == 0) // Work out an appropriate grid spacing for the screen size and coordinate system. if (log_screen_width_degrees > 0) { // grid spacing is rounded to 10 degree increment. stepsx = ((int)(screen_width_degrees / (pow(10,log_screen_width_degrees)))*pow(10,log_screen_width_degrees)) * 36000; } if (log_screen_width_degrees < 0) { // Grid spacing is rounded to less than one degree. if (coordinate_system == USE_DDDDDD) { // Round to tenths or hundrethds or thousanths of a degree. stepsx = ((float)(int)(((float)screen_width_degrees / pow(10,log_screen_width_degrees)*10.0)))*pow(10,log_screen_width_degrees) * 3600; } else { // For decimal minutes or minutes and seconds. // Find screen width and log screen width in minutes. screen_width_degrees = screen_width_degrees * 60.0; log_screen_width_degrees = log10(screen_width_degrees); // round to minutes or tenths of minutes. stepsx = ((float)(int) ((float)(screen_width_degrees) / pow(10,log_screen_width_degrees) * 10.0) ) * pow(10,log_screen_width_degrees) * 3600; if (log_screen_width_degrees==0) { stepsx = 600; // 6000 = 1 minute } } } // Grid should now be close to reasonable spacing for screen size, but // may need to be tuned. // Test for too tightly or too coarsely spaced grid. if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5)) { stepsx = stepsx * 2.0; } if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5)) { stepsx = stepsx * 2.0; } if (stepsx>(unsigned int)((scale_x * screen_width)/3.5)) { stepsx = stepsx / 2.0; } // Handle special case of very small screen - only draw a single grid line if (screen_width < (string_width_pixels * 2)) { stepsx = (scale_x*(screen_width/2)); } // Make sure we don't pass an erronous stepsx of 0 on. if (stepsx==0) { stepsx=36000; } // Use the same grid spacing for both latitude and longitude grids. // We could use a scaling factor related to the screen height width ratio here. stepsy = stepsx; // protect against division by zero if (scale_x==0) { scale_x = 1; } if (scale_y==0) { scale_y = 1; } // Now draw and label the grid. // Draw vertical longitude lines if (NW_corner_latitude >= 0) { y1 = 0; } else { y1 = -NW_corner_latitude/scale_y; } y2 = (180*60*60*100-NW_corner_latitude)/scale_y; if (y2 > (unsigned int)screen_height) { y2 = screen_height-1; } coord = NW_corner_longitude+stepsx-(NW_corner_longitude%stepsx); if (coord < 0) { coord = 0; } last_label_end = 0; for (; coord < SE_corner_longitude && coord <= 360*60*60*100; coord += stepsx) { x = (coord-NW_corner_longitude)/scale_x; if ((coord%(648000*100)) == 0) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt, JoinMiter); (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x), l16(y1), l16(x), l16(y2)); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt, JoinMiter); continue; // Go to next iteration of for loop } else if ((coord%(72000*100)) == 0) { dash[0] = dash[1] = 8; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } else if ((coord%(7200*100)) == 0) { dash[0] = dash[1] = 4; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } else if ((coord%(300*100)) == 0) { dash[0] = dash[1] = 2; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x), l16(y1), l16(x), l16(y2)); if (draw_labeled_grid_border==TRUE) { // Label the longitudes in lower border. convert_lon_l2s(coord, grid_label, sizeof(grid_label), coordinate_format); if (log_screen_width_degrees > 0 && strlen(grid_label) > 5) { // truncate the grid_label string if (coordinate_system==USE_DDMMMM) { // Add ' and move EW and null characters forward. grid_label[strlen(grid_label)-5] = '\''; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)]; } else { // Move EW and null characters forward. grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)]; } } string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER); // test for overlap of label with previously printed label if (x > last_label_end + 3 && x < (unsigned int)(screen_width - string_width_pixels)) { draw_rotated_label_text_to_target (w, 270, x, screen_height, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); last_label_end = x + string_width_pixels; } } } // Draw horizontal latitude lines. last_label_end = 0; if (NW_corner_longitude >= 0) { x1 = 0; } else { x1 = -NW_corner_longitude/scale_x; } x2 = (360*60*60*100-NW_corner_longitude)/scale_x; if (x2 > (unsigned int)screen_width) { x2 = screen_width-1; } coord = NW_corner_latitude+stepsy-(NW_corner_latitude%stepsy); if (coord < 0) { coord = 0; } for (; coord < SE_corner_latitude && coord <= 180*60*60*100; coord += stepsy) { y = (coord-NW_corner_latitude)/scale_y; if ((coord%(324000*100)) == 0) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt, JoinMiter); (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x1), l16(y), l16(x2), l16(y)); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt, JoinMiter); continue; // Go to next iteration of for loop } else if ((coord%(36000*100)) == 0) { dash[0] = dash[1] = 8; (void)XSetDashes (XtDisplay (w), gc_tint, 4, dash, 2); } else if ((coord%(3600*100)) == 0) { dash[0] = dash[1] = 4; (void)XSetDashes (XtDisplay (w), gc_tint, 2, dash, 2); } else if ((coord%(150*100)) == 0) { dash[0] = dash[1] = 2; (void)XSetDashes (XtDisplay (w), gc_tint, 1, dash, 2); } (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x1), l16(y), l16(x2), l16(y)); if (draw_labeled_grid_border==TRUE) { // label the latitudes on left and right borders // (unlike UTM where easting before northing order is important) convert_lat_l2s(coord, grid_label, sizeof(grid_label), coordinate_format); if (log_screen_width_degrees > 0 && strlen(grid_label) > 5) { // truncate the grid_label string if (coordinate_system==USE_DDMMMM) { // Add ' and move EW and null characters forward. grid_label[strlen(grid_label)-5] = '\''; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)]; } else { // Move EW and null characters forward. grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)]; } } string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER); // check to make sure we aren't overwriting the previous label text if ((y > last_label_end+3) && (y > (unsigned int)string_width_pixels)) { draw_rotated_label_text_to_target (w, 180, screen_width, y, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); draw_rotated_label_text_to_target (w, 180, border_width, y, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); last_label_end = y + string_width_pixels; } } } } // End of draw_complete_lat_lon_grid() // Draw the major zones for UTM and MGRS. Called by draw_grid() // below. // // These are based off 6-degree lat/long lines, with a few irregular // zones that have to be special-cased. This part of the code // handles the irregular zones in SW Norway (31V/32V) and the // regions near Svalbard (31X/33X/35X/37X) just fine. // These are based off the central meridian running up the middle of // each zone (3 degrees from either side of the standard six-degree // zones). Even the irregular zones key off the same medians. UTM // grids are defined in terms of meters instead of lat/long, so they // don't line up with the left/right edges of the zones or with the // longitude lines. // // According to Peter Dana (Geographer's Craft web pages), even when // the major grid boundaries have been shifted, the meridian used // for drawing the subgrids is still based on six-degree boundaries // (as if the major grid hadn't been shifted at all). That means we // are drawing the subgrids correctly as it stands now for the // irregular grids (31V/32V/31X/33X/35X/37X). The irregular zones // have sizes of 3/9/12 degrees (width) instead of 6 degrees. // // UTM NOTES: 84 degrees North to 80 degrees South. 60 zones, each // covering six (6) degrees of longitude. Each zone extends three // degrees eastward and three degrees westward from its central // meridian. Zones are numbered consecutively west to east from the // 180 degree meridian. From 84 degrees North and 80 degrees South // to the respective poles, the Universal Polar Stereographic (UPS) // is used. // // For MGRS and UTM-Special grid only: // UTM Zone 32 has been widened to 9 (at the expense of zone 31) // between latitudes 56 and 64 (band V) to accommodate southwest // Norway. Thus zone 32 extends westwards to 3E in the North Sea. // Similarly, between 72 and 84 (band X), zones 33 and 35 have // been widened to 12 to accommodate Svalbard. To compensate for // these 12 wide zones, zones 31 and 37 are widened to 9 and zones // 32, 34, and 36 are eliminated. Thus the W and E boundaries of // zones are 31: 0 - 9 E, 33: 9 - 21 E, 35: 21 - 33 E and 37: 33 - // 42 E. // // UTM is depending on the ellipsoid and the datum used. For our // purposes, we're always using WGS84 ellipsoid and datum, so it's a // non-issue. // // Horizontal bands corresponding to the NATO UTM/UPS lettering: // Zones go from A (south pole) to Z (north pole). South of -80 are // zones A/B, north of +84 are zones Y/Z. "I" and "O" are not used. // Zones from C to W are 8 degrees high. Zone X is 12 degrees high. // // We need these NATO letters or a N/S designator in order to // specify which hemisphere the UTM coordinates are in. Often, the // same coordinates can appear in either hemisphere. Some computer // software uses +/- to designate northings instead of N/S or the // NATO lettered bands. // // UPS system is used at the poles instead of UTM. UPS uses a false // northing and easting of 2,000,000 meters. // // An arbitrary false northing of 10,000,000 at the equator is used // for southern latitudes only. Northern latitudes assume the // equator northing is at zero. An arbitrary false easting of // 500,000 is along the meridian of each zone (3 degrees from each // side). The lettered grid lines are necessary due to some // coordinates being valid in both the northern and the southern // hemisphere. // // Y/Z 84N to 90N (UPS System) false N/E = 2,000,000 // X 72N to 84N (12 degrees latitude, equator=0) // W 64N to 72N ( 8 degrees latitude, equator=0) // V 56N to 64N ( 8 degrees latitude, equator=0) // U 48N to 56N ( 8 degrees latitude, equator=0) // T 40N to 48N ( 8 degrees latitude, equator=0) // S 32N to 40N ( 8 degrees latitude, equator=0) // R 24N to 32N ( 8 degrees latitude, equator=0) // Q 16N to 24N ( 8 degrees latitude, equator=0) // P 8N to 16N ( 8 degrees latitude, equator=0) // N 0N to 8N ( 8 degrees latitude, equator=0) // M 0S to 8S ( 8 degrees latitude, equator=10,000,000) // L 8S to 16S ( 8 degrees latitude, equator=10,000,000) // K 16S to 24S ( 8 degrees latitude, equator=10,000,000) // J 24S to 32S ( 8 degrees latitude, equator=10,000,000) // H 32S to 40S ( 8 degrees latitude, equator=10,000,000) // G 40S to 48S ( 8 degrees latitude, equator=10,000,000) // F 48S to 56S ( 8 degrees latitude, equator=10,000,000) // E 56S to 64S ( 8 degrees latitude, equator=10,000,000) // D 64S to 72S ( 8 degrees latitude, equator=10,000,000) // C 72S to 80S ( 8 degrees latitude, equator=10,000,000) // A/B 80S to 90S (UPS System) false N/E = 2,000,000 // void draw_major_utm_mgrs_grid(Widget w) { int ii; // need to move metadata to its own function and put it up after grids have been drawn. //******* // variables for metadata in grid border long xx2, yy2; // coordinates of screen corners used for metadata int border_width; // Width of the border to draw labels into. double easting, northing; // Values used in border metadata. int x, y; // Screen coordinates for border labels. char zone_str[10]; char zone_str2[10]; char metadata_datum[6]; char grid_label[25]; // String to draw labels on grid lines char grid_label1[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border // variables to support components of MGRS strings in the metadata char mgrs_zone[4] = " "; // MGRS zone letter char mgrs_eastingL[3] = " "; char mgrs_northingL[3] = " "; unsigned int int_utmEasting; unsigned int int_utmNorthing; char mgrs_space_string[4] = " "; // int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. char mgrs_ul_digraph[3] = " "; // MGRS digraph for upper left corner of screen char mgrs_lr_digraph[3] = " "; // MGRS digraph for lower right corner of screen //fprintf(stderr,"draw_major_utm_mgrs_grid start\n"); if (!long_lat_grid) // We don't wish to draw a map grid { return; } // Vertical lines: // Draw the vertical vectors (except for the irregular regions // and the prime meridian). The polar areas only have two zones // each, so we don't want to draw through those areas. for (ii = -180; ii < 0; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } for (ii = 42; ii <= 180; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } // Draw the short vertical vectors in the polar regions draw_vector_ll(w, -90.0, -180.0, -80.0, -180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -90.0, 180.0, -80.0, 180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, -180.0, 90.0, -180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 180.0, 90.0, 180.0, gc_tint, pixmap_final, 0); if (coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { // For MGRS, we need to draw irregular zones in certain // areas. // Draw the partial vectors from 80S to the irregular region draw_vector_ll(w, -80.0, 6.0, 56.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 12.0, 72.0, 12.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 18.0, 72.0, 18.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 24.0, 72.0, 24.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 30.0, 72.0, 30.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 36.0, 72.0, 36.0, gc_tint, pixmap_final, 0); // Draw the short vertical vectors in the irregular region draw_vector_ll(w, 56.0, 3.0, 64.0, 3.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 64.0, 6.0, 72.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 9.0, 84.0, 9.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 21.0, 84.0, 21.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 33.0, 84.0, 33.0, gc_tint, pixmap_final, 0); // Draw the short vertical vectors above the irregular region draw_vector_ll(w, 84.0, 6.0, 84.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 12.0, 84.0, 12.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 18.0, 84.0, 18.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 24.0, 84.0, 24.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 30.0, 84.0, 30.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 36.0, 84.0, 36.0, gc_tint, pixmap_final, 0); } else { // Draw normal zone boundaries used for civilian UTM // grid. for (ii = 6; ii < 42; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } } // Horizontal lines: // Draw the 8 degree spaced lines, except for the equator for (ii = -80; ii < 0; ii += 8) { draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0); } // Draw the 8 degree spaced lines for (ii = 8; ii <= 72; ii += 8) { draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0); } // Draw the one 12 degree spaced line draw_vector_ll(w, 84.0, -180.0, 84.0, 180.0, gc_tint, pixmap_final, 0); // Draw the pole lines draw_vector_ll(w, -90.0, -180.0, -90.0, 180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 90.0, -180.0, 90.0, 180.0, gc_tint, pixmap_final, 0); // Set to solid line for the equator. Make it extra wide as // well. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 3, LineSolid, CapButt,JoinMiter); // Draw the equator as a solid line draw_vector_ll(w, 0.0, -180.0, 0.0, 180.0, gc_tint, pixmap_final, 0); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineSolid, CapButt,JoinMiter); // Draw the prime meridian in the same manner draw_vector_ll(w, -80.0, 0.0, 84.0, 0.0, gc_tint, pixmap_final, 0); // add metadata and labels if (draw_labeled_grid_border==TRUE && scale_x > 3000) { // Determine the width of the border border_width = get_border_width(w); // Find out what the map datum is. get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); // Put metadata in top border. // find location of upper left corner of map, convert to UTM xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (border_width * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label, sizeof(grid_label), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing); } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label, zone_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, easting_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, northing_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string } // find location of lower right corner of map, convert to UTM xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label1, sizeof(grid_label1), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing); if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0) { // mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } else { // mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label1, zone_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, easting_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, northing_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string } // Write metadata on upper border of map. //"XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA003"), grid_label,grid_label1,metadata_datum); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); // Crudely identify zone boundaries by // iterating across bottom border. xastir_snprintf(zone_str2, sizeof(zone_str2), "%s"," "); for (x=1; x<(screen_width - border_width); x++) { xx2 = NW_corner_longitude + (x * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); zone_str[strlen(zone_str)-1] = '\0'; if (strcmp(zone_str,zone_str2) !=0) { draw_rotated_label_text_to_target (w, 270, x + 1, screen_height, sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } xastir_snprintf(zone_str2, sizeof(zone_str2), "%s",zone_str); } // Crudely identify zone letters by iterating down left border for (y=(border_width*2); y<(screen_height - border_width); y++) { xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (y * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); zone_str[0] = zone_str[strlen(zone_str)-1]; zone_str[1] = '\0'; if (strcmp(zone_str,zone_str2) !=0) { draw_rotated_label_text_to_target (w, 270, 1, y, sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } xastir_snprintf(zone_str2, sizeof(zone_str2), "%s",zone_str); } } // end if draw labeled border // Set the line width and style in the GC to 1 pixel wide for // drawing the smaller grid (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt,JoinMiter); //fprintf(stderr,"draw_major_utm_mgrs_grid end\n"); } // End of draw_major_utm_mgrs_grid() // This is the function which actually draws a minor UTM grid. // Called by draw_minor_utm_mgrs_grid() function below. // draw_minor_utm_mgrs_grid() is the function which calculates the // grid points. // void actually_draw_utm_minor_grid(Widget w) { int border_width; // Width of the border to draw labels into. int numberofzones = 0; // number of elements in utm_grid.zone[] that are used int Zone; int ii; int easting_color; // Colors for the grid labels int northing_color; int zone_color; // zone label color int label_on_left; // if true, draw northing labels on left long xx, yy, xx2, yy2; char zone_str[10]; char zone_str2[10]; double easting, northing; int short_width_pixels = 0; // Width of an unrotated string of five_zeroes in the border font in pixels. int string_width_pixels = 0;// Width of an unrotated string of seven_zeroes in the border font in pixels. char metadata_datum[6]; char grid_label[25]; // String to draw labels on grid lines char grid_label1[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border int grid_spacing_pixels; // Spacing of fine grid lines in pixels. int bottom_point; // utm_grid.zone[].col[].npoints can extend past the // bottom of the screen, this is the lowest point in the // points array that is on the screen. int skip_alternate_label; // Skip alternate easting and northing labels // if they would overlap on the // display. int last_line_labeled; // Marks lines that were labeled // when alternate lines are not // being labeled. // variables to support components of MGRS strings char mgrs_zone[4] = " "; // MGRS zone letter char mgrs_eastingL[3] = " "; char mgrs_northingL[3] = " "; unsigned int int_utmEasting; unsigned int int_utmNorthing; char mgrs_space_string[4] = " "; int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. char mgrs_ul_digraph[3] = " "; // MGRS digraph for upper left corner of screen char mgrs_lr_digraph[3] = " "; // MGRS digraph for lower right corner of screen if (!long_lat_grid) // We don't wish to draw a map grid { return; } // OLD: Draw grid in dashed white lines. // NEW: Tint the lines as they go along, making them appear // no matter what color is underneath. (void)XSetForeground(XtDisplay(w), gc_tint, colors[0x27]); // Note: npoints can be negative here! Make sure our code // checks for that. Initially npoints was an unsigned int. // Changed it to an int so that we can get and check for // negative values, bypassing segfaults. // numberofzones = 0; // Determine the width of the border border_width = get_border_width(w); // Determine some parameters used in drawing the border. string_width_pixels = get_standard_border_string_width_pixels(w, 7); short_width_pixels = get_standard_border_string_width_pixels(w,5); for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { if (utm_grid.zone[Zone].ncols > 0) { // find out how many zones are actually drawn on the map numberofzones++; } } for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++) { if (utm_grid.zone[Zone].col[ii].npoints > 1) { // We need to check for points that are more // than +/- 16383. If we have any, it can cause // X11 to lock up for a while drawing lots of // extra lines, due to bugs in X11. We do that // checking above with xx and yy. // (void)XDrawLines(XtDisplay(w), pixmap_final, gc_tint, utm_grid.zone[Zone].col[ii].points, l16(utm_grid.zone[Zone].col[ii].npoints), CoordModeOrigin); } } for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { if (utm_grid.zone[Zone].row[ii].npoints > 1) { // We need to check for points that are more // than +/- 16383. If we have any, it can cause // X11 to lock up for a while drawing lots of // extra lines, due to bugs in X11. We do that // checking above with xx and yy. // (void)XDrawLines(XtDisplay(w), pixmap_final, gc_tint, utm_grid.zone[Zone].row[ii].points, l16(utm_grid.zone[Zone].row[ii].npoints), CoordModeOrigin); } } // Check each of the 4 possible utm_grid.zone array elements // that might contain a grid, and label the grid if it exists. if (utm_grid.zone[Zone].nrows>0 && utm_grid.zone[Zone].ncols>0) { if (draw_labeled_grid_border==TRUE) { // Label the UTM grid on the border. // Since the coordinate of the current mouse pointer position is // continually updated, labeling the grid is primarily for the // purpose of printing maps and saving screenshots. // // ******* Doesn't work properly near poles when 3 zones are on screen // ******* (e.g. 13,14,15) - overlaps northings for 14 and 15. // ******* Doesn't clearly distinguish one zone with 2 lettered rows // ******* (e.g. 18T,18U) needs color distinction between northings // ******* to indicate which northings are in which lettered row. // // Default labels for just one zone on screen are black text for // zone at lower left corner, eastings on bottom, and northings // at right. // Idea is to normally start at the lower left corner // users can then easily follow left to right to get easting, // and bottom to top to get northing. // For two zones, second zone uses blue text for eastings and northings. easting_color = 0x08; // black text northing_color = 0x08; // black text zone_color = 0x08; // black text // 0x09=blue (0x0e=yellow works well with outline, but not without). label_on_left = FALSE; // Find out what the map datum is. get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); if (numberofzones>1) { // check to see if the upper left and lower left corners are in the same zone // if not, label the upper left corner xx = (border_width * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); yy = (border_width * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy); if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str2); //draw_nice_string(w,pixmap_final,0, // border_width+2, // (2*border_width)+2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); draw_rotated_label_text_to_target (w, 270, border_width+2, (2*border_width)+2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, border_width+2, screen_height - (2*border_width) - 2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } zone_color = 0x09; // likewise for upper and lower right corners xx = ((screen_width - border_width) * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); yy = (border_width * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy); if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str2); //draw_nice_string(w,pixmap_final,0, // screen_width - (border_width * 3) , // (2*border_width)+2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); draw_rotated_label_text_to_target (w, 270, screen_width - (border_width * 3), (2*border_width)+2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, screen_width - (border_width * 3), screen_height - (2*border_width) - 2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } // are we currently the same zone as the upper left corner // if so, we need to place the northing labels on the left side xx = (utm_grid.zone[Zone].col[0].points[0].x * scale_x) + NW_corner_longitude; yy = (utm_grid.zone[Zone].col[0].points[0].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), NW_corner_longitude, NW_corner_latitude); if (strcmp(zone_str,zone_str2)==0) { northing_color = 0x08; // 0x08 = black, same as lower left easting label_on_left = TRUE; } } // check to see if there is a horizontal boundary // compare xone of upper left and lower left corners convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), NW_corner_longitude, NW_corner_latitude); // Overwrite defaults as appropriate and // label zones differently if more than one appears on the screen. if (Zone > 0) { // write the zone label on the bottom border zone_color = 0x09; // blue easting_color = 0x09; // blue northing_color = 0x09; // blue xx2 = utm_grid.zone[Zone].col[0].points[0].x; xx = (xx2 * scale_x) + NW_corner_longitude; yy2 = utm_grid.zone[Zone].col[0].points[utm_grid.zone[Zone].col[0].npoints-1].y; yy = (yy2 * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx,yy); xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, xx2, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); //draw_nice_string(w,pixmap_final,0, // xx2, // screen_height - 2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); } if (Zone==0) { // write the zone of the lower left corner of the map xx = (border_width * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, 1, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); //draw_nice_string(w,pixmap_final,0, // 1, // screen_height - 2, // grid_label, // 0x10,0x20,(int)strlen(grid_label)); } // Put metadata in top border. // find location of upper left corner of map, convert to UTM xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (border_width * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label, sizeof(grid_label), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing); } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label, zone_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, easting_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, northing_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string } // find location of lower right corner of map, convert to UTM xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label1, sizeof(grid_label1), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing); if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0) { mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } else { mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label1, zone_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, easting_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, northing_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string } //"XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA001"), grid_label,grid_label1,utm_grid_spacing_m,metadata_datum); //draw_nice_string(w,pixmap_final,0, // border_width+2, // border_width-2, // top_label, // 0x10,0x20,(int)strlen(top_label)); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); // deterimne whether the easting and northing strings will fit // in a grid box, or whether easting strings in adjacent boxes // will overlap (so that alternate strings can be skipped). if (utm_grid.zone[Zone].ncols > 1) { // find out the number of pixels beteen two grid lines grid_spacing_pixels = utm_grid.zone[Zone].col[1].points[0].x - utm_grid.zone[Zone].col[0].points[0].x; if (grid_spacing_pixels == 0) { grid_spacing_pixels = -1; // Skip } } else { // only one column in this zone, skip alternate doesn't matter grid_spacing_pixels = -1; } // Is truncated easting or northing larger than grid spacing? // If so, skip alternate labels // short_width_pixels+2 seems to work well. if (short_width_pixels+2>grid_spacing_pixels) { skip_alternate_label = TRUE; } else { skip_alternate_label = FALSE; } // Label the grid lines on the border. // Put easting along the bottom for easier correct ordering of easting and northing // by people who are reading the map. last_line_labeled = FALSE; for (ii=1; ii < (int)utm_grid.zone[Zone].ncols; ii++) { // label meridianal grid lines with easting if (utm_grid.zone[Zone].col[ii].npoints > 1) { // adjust up in case npoints goes far below the screen if (grid_spacing_pixels == 0) { continue; // Go to next iteration of for loop } bottom_point = (int)(screen_height/grid_spacing_pixels); if (bottom_point >= utm_grid.zone[Zone].col[ii].npoints) { bottom_point = utm_grid.zone[Zone].col[ii].npoints - 1; } if (skip_alternate_label==TRUE && last_line_labeled==TRUE) { last_line_labeled = FALSE; } else { xx = (utm_grid.zone[Zone].col[ii].points[bottom_point].x * scale_x) + NW_corner_longitude; yy = (utm_grid.zone[Zone].col[ii].points[bottom_point].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); // To display full precision to one meter, use: //xastir_snprintf(grid_label, // sizeof(grid_label), // "%06.0f0", // (float)((utm_grid_spacing_m/10) * roundf(easting/(utm_grid_spacing_m)))); // // Divide easting by utm_grid_spacing to make sure the line is labeled // correctly, and not a few meters off, and truncate to at least 100 m. xastir_snprintf(grid_label, sizeof(grid_label), "%05.0f", (float)((utm_grid_spacing_m/100) * roundf(easting/(utm_grid_spacing_m)))); // truncate the label to an appropriate level of precision for the grid if (utm_grid_spacing_m ==1000) { grid_label[4] = ' '; } if (utm_grid_spacing_m ==10000) { grid_label[3] = ' '; grid_label[4] = ' '; } if (utm_grid_spacing_m ==100000) { grid_label[2] = ' '; grid_label[3] = ' '; grid_label[4] = ' '; } if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx, yy, 0, mgrs_space_string, strlen(mgrs_space_string)); grid_label[0] = mgrs_eastingL[0]; grid_label[1] = mgrs_northingL[0]; if (mgrs_single_digraph==FALSE) { grid_label[1] = '_'; } } // draw each number at the bottom of the screen just to the right of the // relevant grid line at its location at the bottom of the screen //draw_nice_string(w,pixmap_final,0, // utm_grid.zone[Zone].col[i].points[bottom_point].x+1, // screen_height-2, // grid_label, // 0x10,easting_color,(int)strlen(grid_label)); // Don't overwrite the zone label, half the seven zeros string should give it room. // Don't draw the label if it will go off the left edge fo the screen. if ((utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 > (string_width_pixels/2)) && (utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 < (screen_width - string_width_pixels)) ) { // ok to draw the label last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 270, utm_grid.zone[Zone].col[ii].points[bottom_point].x+1, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } } } last_line_labeled = FALSE; // put northing along the right border, again for easier correct ordering of easting and northing. for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { // label latitudinal grid lines with northing if (utm_grid.zone[Zone].row[ii].npoints > 1) { if (skip_alternate_label==TRUE && last_line_labeled==TRUE) { last_line_labeled = FALSE; } else { if (label_on_left==TRUE) { xx = (utm_grid.zone[Zone].row[ii].points[0].x * scale_x) + NW_corner_longitude; } else { xx = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].x * scale_x) + NW_corner_longitude; } yy = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); // To display to full 1 meter precision use: //xastir_snprintf(grid_label, // sizeof(grid_label), // "%06.0f0", // (float)((utm_grid_spacing_m/10) * roundf(northing/(utm_grid_spacing_m)))); // // Divide northing by utm grid spacing to make sure the line is labeled correctly // and displays zeroes in its least significant digits, and truncate to 100 m xastir_snprintf(grid_label, sizeof(grid_label), "%05.0f", (float)((utm_grid_spacing_m/100) * roundf(northing/(utm_grid_spacing_m)))); if (utm_grid_spacing_m ==1000) { grid_label[4] = ' '; } if (utm_grid_spacing_m ==10000) { grid_label[3] = ' '; grid_label[4] = ' '; } if (utm_grid_spacing_m ==100000) { grid_label[2] = ' '; grid_label[3] = ' '; grid_label[4] = ' '; } if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, 3, mgrs_northingL, 3, &int_utmEasting, &int_utmNorthing, xx, yy, 0, mgrs_space_string, strlen(mgrs_space_string)); grid_label[0] = mgrs_eastingL[0]; if (mgrs_single_digraph==FALSE) { grid_label[0] = '_'; } grid_label[1] = mgrs_northingL[0]; } // Draw northing labels. // Draw each number just above the relevant grid line along the right side // of the screen. Don't write in the bottom border or off the top of the screen. if (label_on_left==TRUE) { // label northings on left border // don't overwrite the zone designator in the lower left border if ((utm_grid.zone[Zone].row[ii].points[0].y < (screen_height - border_width)) && (utm_grid.zone[Zone].row[ii].points[0].y > (string_width_pixels)) ) { last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 180, border_width, utm_grid.zone[Zone].row[ii].points[0].y, sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } else { if (((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1) < (screen_height - border_width)) && ((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1) > (string_width_pixels)) ) { // label northings on right border last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 180, screen_width, utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1, sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } } } } // for i=0 to nrows } // if draw labeled grid border } // if utm_grid.zone[Zone] is non-empty } // for each zone in utm_grid.zone } // End of actually_draw_utm_minor_grid() function // Calculate the minor UTM grids. Called by draw_grid() below. // This function calculates and caches a within-zone UTM grid // for the current map view if one does not allready exist, it // then calls actually_draw_utm_minor_grid() function above to do // the drawing once the grid has been calculated. Zone boundaries // are drawn separately by draw_major_utm_mgrs_grid(). // // This routine appears to draw most of the UTM/UPS grid ok, with // the exceptions of: // // 1) Sometimes fails to draw vertical lines nearest zone // boundaries. // 2) Lines connect across zone boundaries in an incorrect manner, // jumping up one grid interval across the boundary. // 3) Segfaults near the special zone intersections as you zoom in. // // The code currently creates a col and row array per zone visible, // with XPoints malloced that contain the grid intersections in // screen coordinates. If the screen is zoomed or panned they are // recalculated. // // Perhaps we could do the same but with lat/long coordinates in the // future so that we'd only have to recalculate when a new Zone came // into view. We'd use the lat/long vector drawing programs above // then, with a possible slowdown due to more calculations if we're // not moving around. // // Returns: 0 if successful or nothing to draw // 1 if malloc error // 2 if iterations error // 3 if out of zones // 4 if realloc failure // int draw_minor_utm_mgrs_grid(Widget w) { long xx, yy, xx1, yy1; double e[4], n[4]; char place_str[10], zone_str[10]; int done = 0; int z1, z2, Zone, col, col_point, row, row_point, row_point_start; int iterations = 0; int finished_with_current_zone = 0; int ii, jj; float slope; int coordinate_system_backup = coordinate_system; col = 0; row = 0; col_point = 0; row_point = 0; row_point_start = 0; Zone = 0; // Set up for drawing zone grid(s) if (scale_x < 15) { utm_grid_spacing_m = 100; } else if (scale_x < 150) { utm_grid_spacing_m = 1000; } else if (scale_x < 1500) { utm_grid_spacing_m = 10000; } else if (scale_x < 3000) { utm_grid_spacing_m = 100000; } else { utm_grid_spacing_m = 0; // All done! Don't draw the minor grids. Major grids // have already been drawn by this point. return(0); } // Check hash to see if utm_grid is already set up if (utm_grid.hash.ul_x == NW_corner_longitude && utm_grid.hash.ul_y == NW_corner_latitude && utm_grid.hash.lr_x == SE_corner_longitude && utm_grid.hash.lr_y == SE_corner_latitude) { // XPoint arrays are already set up. Go draw the grid. actually_draw_utm_minor_grid(w); return(0); } // If we get to this point, we need to re-create the minor UTM/MGRS // grids as they haven't been set up yet or they don't match the // current view. // Clear the minor UTM/MGRS grid arrays. Alloc space for // the points in the grid structure. if (utm_grid_clear(1)) { // If we got here, we had a problem with malloc's return(1); } // Find top left point of current view xx = NW_corner_longitude; yy = NW_corner_latitude; // Note that the minor grid depends on the STANDARD six degree // UTM zones, not the UTM-Special/MGRS zones. Force our // calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy); coordinate_system = coordinate_system_backup; n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere // Select starting point, NW corner of NW zone // Move the coordinates to the nearest subgrid intersection, // based on our current grid spacing. The grid intersection // we calculate here is northwest of our view's northwest // corner. e[0] /= utm_grid_spacing_m; e[0] = (double)((int)e[0] * utm_grid_spacing_m); n[0] /= utm_grid_spacing_m; n[0] = (double)((int)n[0] * utm_grid_spacing_m); n[0] += utm_grid_spacing_m; //WE7U // It appears that the horizontal grid lines get messed up in cases // where the top horizontal line isn't in view on it's left end. // That's a major clue! Read the comment below (again with a "WE7U" // tag). The problem occurs at the point where we copy the last // point from the previous grid over to the first point of a new // grid. That can cause us to be off by one, as for the grid on the // left, the top horizontal line _is_ in view on the left. We end // up connecting the wrong horizontal lines together because of this // mismatch, but again, only if the top horizontal line on the left // grid is above the current view. // // It also appears that the vertical lines that are missing in some // cases are on the right of the zone boundary. This is probably // because the top of that line doesn't go to the top of the view. // On views where it does, the line is drawn. I assume this is // because we're drawing from NW corner to the right, and then down, // which would cause that line to be skipped if it's not present on // the first line? e[1] = e[0]; n[1] = n[0]; ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Start filling in the row/column arrays of grid intersections while (!done) { XPoint *temp_point; // Here's our escape in case we get stuck in this loop. // We can go through this loop multiple times for each // zone though, depending on our grid spacing. 64 rows * 64 // colums * 8 points each = 32768, which gives us our upper // limit. if (iterations++ > 32768) { fprintf(stderr, "draw_minor_utm_mgrs_grid() looped too many times, escaping.\n"); utm_grid_clear(1); return(2); } if (finished_with_current_zone) { // Set up to compute the next zone xx = NW_corner_longitude + ((utm_grid.zone[Zone].boundary_x + 1) * scale_x); yy = NW_corner_latitude; // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. // Force our calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy); coordinate_system = coordinate_system_backup; n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere // Fix the coordinates to the nearest subgrid intersection based on // our current grid spacing. Bump both the easting and northing up // by one subgrid. e[0] /= utm_grid_spacing_m; e[0] = (double)((int)e[0] * utm_grid_spacing_m); e[0] += utm_grid_spacing_m; n[0] /= utm_grid_spacing_m; n[0] = (double)((int)n[0] * utm_grid_spacing_m); n[0] += utm_grid_spacing_m; e[1] = e[0]; n[1] = n[0]; #ifdef UTM_DEBUG fprintf(stderr,"\nFinished Zone=%d\n", Zone); #endif // We're all done with the current zone. Increment // to the next zone and set up to calculate its // points. Zone++; #ifdef UTM_DEBUG fprintf(stderr,"\nstarting Zone=%d, row_point_start=1\n", Zone); #endif row_point = row_point_start = 1; col = row = col_point = 0; finished_with_current_zone = 0; if (Zone >= UTM_GRID_MAX_ZONES) { fprintf(stderr,"Error: Zone=%d: out of zones!\n", Zone); Zone = 0; done = 1; utm_grid_clear(1); return(3); } } // End of if(finished_with_current_zone) // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. Force // our calculations to use the standard zones. coordinate_system = USE_UTM; convert_UTM_to_xastir(e[1], n[1]-UTM_GRID_EQUATOR, place_str, &xx, &yy); coordinate_system = coordinate_system_backup; xx1 = xx; // Save yy1 = yy; // Save // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. Force // our calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[2], &n[2], zone_str, sizeof(zone_str), xx, yy); coordinate_system = coordinate_system_backup; n[2] += UTM_GRID_EQUATOR; xx = (xx - NW_corner_longitude) / scale_x; yy = (yy - NW_corner_latitude) / scale_y; // Not all columns (and maybe rows) will start at point // 0 if (utm_grid.zone[Zone].col[col].firstpoint == UTM_GRID_RC_EMPTY) { utm_grid.zone[Zone].col[col].firstpoint = l16(col_point); #ifdef UTM_DEBUG fprintf(stderr,"col[%d] started at point %d\n", col, col_point); #endif } if (utm_grid.zone[Zone].row[row].firstpoint == UTM_GRID_RC_EMPTY) { utm_grid.zone[Zone].row[row].firstpoint = l16(row_point); #ifdef UTM_DEBUG fprintf(stderr,"row[%d] started at point %d\n", row, row_point); #endif } // Check to see if we need to alloc more space for // column points ii = utm_grid.zone[Zone].col[col].npoints + utm_grid.zone[Zone].col[col].firstpoint + 1; if (ii > utm_grid.zone[Zone].col[col].nalloced) { #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].col[%d].points, ", ii, utm_grid.zone[Zone].col[col].nalloced, Zone, col); #endif ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED; #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"%d)\n", ii); #endif temp_point = realloc(utm_grid.zone[Zone].col[col].points, ii * sizeof(XPoint)); if (temp_point) { utm_grid.zone[Zone].col[col].points = temp_point; utm_grid.zone[Zone].col[col].nalloced = ii; } else { puts("realloc FAILED!"); (void)utm_grid_clear(1); // Clear arrays and allocate memory for points return(4); } } // Check to see if we need to alloc more space for row // points ii = utm_grid.zone[Zone].row[row].npoints + utm_grid.zone[Zone].row[row].firstpoint + 1; if (ii > utm_grid.zone[Zone].row[row].nalloced) { #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].row[%d].points, ", ii, utm_grid.zone[Zone].row[row].nalloced, Zone, row); #endif ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED; #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"%d)\n", ii); #endif temp_point = realloc(utm_grid.zone[Zone].row[row].points, ii * sizeof(XPoint)); if (temp_point) { utm_grid.zone[Zone].row[row].points = temp_point; utm_grid.zone[Zone].row[row].nalloced = ii; } else { puts("realloc FAILED!"); (void)utm_grid_clear(1); // Clear arrays and allocate memory for points return(4); } } // Here we check to see whether we are inserting points // that are greater than about +/- 32767. If so, // truncate at that. This prevents XDrawLines() from // going nuts and drawing hundreds of extra lines. // xx = l16(xx); yy = l16(yy); utm_grid.zone[Zone].col[col].points[col_point].x = l16(xx); utm_grid.zone[Zone].col[col].points[col_point].y = l16(yy); utm_grid.zone[Zone].col[col].npoints++; utm_grid.zone[Zone].row[row].points[row_point].x = l16(xx); utm_grid.zone[Zone].row[row].points[row_point].y = l16(yy); utm_grid.zone[Zone].row[row].npoints++; #ifdef UTM_DEBUG fprintf(stderr,"utm_grid.zone[%d].col[%d].points[%d] = [ %ld,%ld ] npoints=%d\n", Zone, col, col_point, xx, yy, utm_grid.zone[Zone].col[col].npoints); fprintf(stderr,"utm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone, row, row_point, xx, yy); #endif col++; row_point++; if (col >= UTM_GRID_MAX_COLS_ROWS) { finished_with_current_zone++; } z1 = atoi(place_str); z2 = atoi(zone_str); if (z1 != z2 || xx > screen_width) // We hit a boundary { #ifdef UTM_DEBUG_VERB if (z1 != z2) { fprintf(stderr,"Zone boundary! \"%s\" -> \"%s\"\n", place_str, zone_str); } else { puts("Screen boundary!"); } #endif //#warning //#warning I suspect that I should not use just col for the following. //#warning if (col-2 >= 0) slope = (float)(yy - utm_grid.zone[Zone].col[col-2].points[col_point].y) / (float)(xx - utm_grid.zone[Zone].col[col-2].points[col_point].x + 0.001); else { slope = 0.0; } if (xx > screen_width) { xx1 = screen_width; } else { // 360,000 Xastir units equals one degree. This // code appears to be adjusting xx1 to a major // zone edge. xx1 = (xx1 / (6 * 360000)) * 6 * 360000; xx1 = (xx1 - NW_corner_longitude) / scale_x; } utm_grid.zone[Zone].boundary_x = xx1; yy1 = yy - (xx - xx1) * slope; #ifdef UTM_DEBUG fprintf(stderr,"_tm_grid.zone[%d].col[%d].points[%d] = [ %ld,%ld ]\n", Zone, col-1, col_point, xx1, yy1); fprintf(stderr,"_tm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone, row, row_point-1, xx1, yy1); #endif if (col-1 >= 0 && row_point-1 >= 0) { utm_grid.zone[Zone].col[col-1].points[col_point].x = l16(xx1); utm_grid.zone[Zone].col[col-1].points[col_point].y = l16(yy1); utm_grid.zone[Zone].row[row].points[row_point-1].x = l16(xx1); utm_grid.zone[Zone].row[row].points[row_point-1].y = l16(yy1); if (z1 != z2 && Zone+1 < UTM_GRID_MAX_ZONES) { // copy over last points to start off new // zone #ifdef UTM_DEBUG fprintf(stderr,"ztm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone+1, row, 0, xx1, yy1); #endif //WE7U // This is where we can end up linking up/down one grid width // between zones!!! Without it though, we end up have a blank // section to the right of the zone boundary. Perhaps we could do // this here, but when we get the next points calculated, we could // check to see if we're off by about one grid width in the vertical // direction. If so, shift the initial point by that amount? // // Another possibility might be to draw bottom-to-top if in northern // hemisphere, and top-to-bottom if in southern hemisphere. That // way we'd have the max amount of lines present when we start, and // some might peter out as we draw along N/S. Looking at the // southern hemisphere right now though, that method doesn't appear // to work. We get the same problems there even though we're // drawing top to bottom. // utm_grid.zone[Zone+1].row[row].points[0].x = l16(xx1); utm_grid.zone[Zone+1].row[row].points[0].y = l16(yy1); utm_grid.zone[Zone+1].row[row].firstpoint = 0; utm_grid.zone[Zone+1].row[row].npoints = 1; } } // Check last built row to see if it is all off // screen finished_with_current_zone++; // Assume we're done with this zone for (ii=0; ii < utm_grid.zone[Zone].row[row].npoints; ii++) { if (utm_grid.zone[Zone].row[row].points[ii].y <= screen_height) { finished_with_current_zone = 0; // Some points were within the zone, keep computing } } e[1] = e[0]; // carriage return n[1] -= utm_grid_spacing_m; // line feed // Yea, your comments are real funny Olivier... Gets the point // across though! row++; if (row >= UTM_GRID_MAX_COLS_ROWS) { finished_with_current_zone++; } utm_grid.zone[Zone].ncols = max_i(col, utm_grid.zone[Zone].ncols); utm_grid.zone[Zone].nrows = max_i(row, utm_grid.zone[Zone].nrows); col = 0; row_point = row_point_start; col_point++; if (n[1] < 0) { fprintf(stderr,"n[1] < 0\n"); finished_with_current_zone++; } if (finished_with_current_zone && xx > screen_width) { done = 1; } // Go to next iteration of while loop (skip next statement) continue; } e[1] += utm_grid_spacing_m; } // End of while (done) loop ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// //fprintf(stderr, "After while loop\n"); // utm_grid.zone[] now contains an array of points marking fine grid // line intersections for parts of 1 to 4 zones that appear on // the screen. Each utm_grid.zone[] is a vertical stripe, and may include // more than one zone letter, e.g. zone[0] might include 15U and 15T, // while zone[1] might include 16U and 16T. //#define UTM_DEBUG_VERB for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { #ifdef UTM_DEBUG_VERB fprintf(stderr,"\nutm_grid.zone[%d].ncols=%d\nutm_grid.zone[%d].nrows=%d\n", Zone, utm_grid.zone[Zone].ncols, Zone, utm_grid.zone[Zone].nrows); #endif // Cleanup columns for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++) { int np = utm_grid.zone[Zone].col[ii].npoints; int fp = utm_grid.zone[Zone].col[ii].firstpoint; int nbp = 0; #ifdef UTM_DEBUG_VERB fprintf(stderr,"utm_grid.zone[%d].col[%d].npoints=%d .firstpoint=%d\n", Zone, ii, np, fp); if (np < 2) { puts(" Not enough points!"); } else { puts(""); } for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," col[%d].points[%d] = [ %d, %d ]", ii, jj, utm_grid.zone[Zone].col[ii].points[jj].x, utm_grid.zone[Zone].col[ii].points[jj].y); if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { puts(" Boundary"); } else { puts(""); } } #endif for (jj=fp; jj < fp+np; jj++) { if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { nbp++; } else if (nbp > 0) // We had a boundary point, but not anymore { fp = utm_grid.zone[Zone].col[ii].firstpoint = l16(jj - 1); //fprintf(stderr,"np:%d, jj:%d\n",np,jj); // This can result in negative numbers! np = utm_grid.zone[Zone].col[ii].npoints = np - jj + 1; //fprintf(stderr,"new np:%d\n",np); if (np < 0) { np = 0; // Prevents segfaults in // XDrawLines() and memmove() // below. } break; // Exit from for loop } if (nbp == np) // All points are boundary points { fp = utm_grid.zone[Zone].col[ii].firstpoint = 0; np = utm_grid.zone[Zone].col[ii].npoints = 0; } } // What's the below code doing? Can get a segfault without this in // the XDrawLines() functions below (fixed by making npoints an int // instead of an unsigned int). Sometimes we get a segfault right // here due to the memmove() function. In one such case, np was -2. // Latest code keeps some lines from getting drawn, but at least we // don't get a segfault. // if (fp > 0) { if (np > 0) { memmove(&utm_grid.zone[Zone].col[ii].points[0], &utm_grid.zone[Zone].col[ii].points[fp], np * sizeof(XPoint)); fp = utm_grid.zone[Zone].col[ii].firstpoint = 0; } else { //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint)); //fprintf(stderr,"Problem1: in draw_minor_utm_mgrs_grid() memmove, np was %d. Skipping memmove.\n",np); } } #ifdef UTM_DEBUG_VERB fprintf(stderr,"_tm_grid.zone[%d].col[%d].npoints=%d.firstpoint=%d\n", Zone, ii, np, fp); for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," col[%d].points[%d] = [ %d, %d ]", ii, jj, utm_grid.zone[Zone].col[ii].points[jj].x, utm_grid.zone[Zone].col[ii].points[jj].y); if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { puts(" Boundary"); } else { puts(""); } } puts(""); #endif } // Cleanup rows for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { int np = utm_grid.zone[Zone].row[ii].npoints; int fp = utm_grid.zone[Zone].row[ii].firstpoint; #ifdef UTM_DEBUG_VERB fprintf(stderr,"utm_grid.zone[%d].row[%d].npoints=%d.firstpoint=%d\n", Zone, ii, np, fp); if (np < 2) { puts(" Not enough points!"); } else { puts(""); } #endif // What's this doing? This appears to be important, as things get // really messed up if it's commented out. if (fp > 0) { if (np > 0) { memmove(&utm_grid.zone[Zone].row[ii].points[0], &utm_grid.zone[Zone].row[ii].points[fp], np * sizeof(XPoint)); fp = utm_grid.zone[Zone].row[ii].firstpoint = 0; } else { //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint)); //fprintf(stderr,"Problem2: in draw_minor_utm_mgrs_grid() memmove, np was %d. Skipping memmove.\n",np); } } #ifdef UTM_DEBUG_VERB for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," row[%d].points[%d] = [ %d, %d ]\n", ii, jj, utm_grid.zone[Zone].row[ii].points[jj].x, utm_grid.zone[Zone].row[ii].points[jj].y); } #endif } } // Rows and columns ready to go so setup hash utm_grid.hash.ul_x = NW_corner_longitude; utm_grid.hash.ul_y = NW_corner_latitude; utm_grid.hash.lr_x = SE_corner_longitude; utm_grid.hash.lr_y = SE_corner_latitude; // XPoint arrays are set up. Go draw the grid. actually_draw_utm_minor_grid(w); return(0); } // End of draw_minor_utm_mgrs_grid() function //***************************************************************** // draw_grid() // // Draws a lat/lon or UTM/UPS grid on top of the view. // //***************************************************************** void draw_grid(Widget w) { int half; // Center of the white lines used to draw the borders int border_width = 14; // The width of the border to draw around the // map to place labeled tick marks into // should be an even number. // The default here is overidden by the border fontsize. if (!long_lat_grid) // We don't wish to draw a map grid { return; } if (draw_labeled_grid_border==TRUE) { // Determine how wide the border should be. border_width = get_border_width(w); half = border_width/2; // draw a white border around the map. (void)XSetLineAttributes(XtDisplay(w), gc, border_width, LineSolid, CapRound, JoinRound); (void)XSetForeground(XtDisplay(w), gc, colors[border_foreground_color]); // white (void)XDrawLine(XtDisplay(w), pixmap_final, gc, 0, l16(half), l16(screen_width), l16(half)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(half), 0, l16(half), l16(screen_height)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, 0, l16(screen_height-half), l16(screen_width), l16(screen_height-half)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(screen_width-half), 0, l16(screen_width-half), l16(screen_height)); } // Set the line width in the GC to 2 pixels wide for the larger // UTM grid and the complete Lat/Long grid. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { int ret_code; //draw_vector_ll(w, -5.0, -5.0, 5.0, 5.0, gc_tint, pixmap_final, 0); //draw_vector_ll(w, 5.0, 5.0, -5.0, -5.0, gc_tint, pixmap_final, 0); // Draw major UTM/MGRS zones draw_major_utm_mgrs_grid(w); // Draw minor UTM/MGRS zones ret_code = draw_minor_utm_mgrs_grid(w); if (ret_code) { fprintf(stderr, "Encountered problem %d while calculating minor utm grid!\n", ret_code); } } // End of UTM grid section else // Lat/Long coordinate system, draw lat/long lines { draw_complete_lat_lon_grid(w); } // End of Lat/Long section } // End of draw_grid() /********************************************************** * get_map_ext() * * Returns the extension for the filename. We use this to * determine which sort of map file it is. **********************************************************/ char *get_map_ext (char *filename) { int len; int i; char *ext; ext = NULL; len = (int)strlen (filename); for (i = len; i >= 0; i--) { if (filename[i] == '.') { ext = filename + (i + 1); break; } } return (ext); } /********************************************************** * get_map_dir() * * Used to snag just the pathname from a complete filename. * Modifies input parameter "fullpath". **********************************************************/ char *get_map_dir (char *fullpath) { int len; int i; len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { fullpath[i + 1] = '\0'; break; } } return (fullpath); } /*********************************************************** * map_visible() * * Tests whether a particular path/filename is within our * current view. We use this to decide whether to plot or * skip a particular image file (major speed-up!). * Input coordinates are in the Xastir coordinate system. * * Had to fix a bug here where the viewport glanced over the * edge of the earth, causing strange results like this. * Notice the View Edges Top value is out of range: * * * Bottom Top Left Right * View Edges: 31,017,956 4,290,923,492 35,971,339 90,104,075 * Map Edges: 12,818,482 12,655,818 64,079,859 64,357,110 * * Left map boundary inside view * Right map boundary inside view * map_inside_view: 1 view_inside_map: 0 parallel_edges: 0 * Map not within current view. * Skipping map: /usr/local/share/xastir/maps/tif/uk/425_0525_bng.tif * * * I had to check for out-of-bounds numbers for the viewport and * set them to min or max values so that this function always * works properly. Here are the bounds of the earth (Xastir * Coordinate System): * * 0 (90 deg. or 90N) * * 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) * * 64,800,000 (-90 deg. or 90S) * ***********************************************************/ int map_visible (unsigned long map_max_y, // bottom_map_boundary unsigned long map_min_y, // top_map_boundary unsigned long map_min_x, // left_map_boundary unsigned long map_max_x) // right_map_boundary) { { //fprintf(stderr,"map_visible\n"); // From computation geometry equations, intersection of two line // segments, they use the bounding box for two lines. This is // the same as what we want to do: // // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa // http://www.gamedev.net/reference/articles/article735.asp // // The quick rejection algorithm: // if (NW_corner_latitude > (long)map_max_y) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: NW_corner_latitude:%ld > map_max_y:%ld\n", NW_corner_latitude, map_max_y); fprintf(stderr, "\tmap or object is above viewport\n"); } return(0); } if ((long)map_min_y > SE_corner_latitude) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: map_min_y:%ld > SE_corner_latitude:%ld\n", map_min_y, SE_corner_latitude); fprintf(stderr, "\tmap or object is below viewport\n"); } return(0); } if (NW_corner_longitude > (long)map_max_x) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: NW_corner_longitude:%ld > map_max_x:%ld\n", NW_corner_longitude, map_max_x); fprintf(stderr, "\tmap or object is left of viewport\n"); } return(0); } if ((long)map_min_x > SE_corner_longitude) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: map_min_x:%ld > SE_corner_longitude:%ld\n", map_min_x, SE_corner_longitude); fprintf(stderr, "\tmap or object is right of viewport\n"); } return(0); } return (1); // At least part of the map is on-screen } ///////////////////////////////////////////////////////////////////// // get_viewport_lat_lon(double *xmin, double *ymin, double* xmax, double *ymax) // Simply returns the floating point corners of the map display. ///////////////////////////////////////////////////////////////////// void get_viewport_lat_lon(double *xmin, double *ymin, double* xmax, double *ymax) { *xmin=(double)f_NW_corner_longitude; *ymin=(double)f_SE_corner_latitude; *xmax=(double)f_SE_corner_longitude; *ymax=(double)f_NW_corner_latitude; } ///////////////////////////////////////////////////////////////////// // map_inside_viewport_lat_lon() // Returns 1 if the given set of xmin,xmax, ymin,ymax defines a // rectangle entirely contained in the current viewport (as opposed to // merely partially overlapping it. Returns zero otherwise. ///////////////////////////////////////////////////////////////////// int map_inside_viewport_lat_lon(double map_min_y, double map_max_y, double map_min_x, double map_max_x) { int retval=0; if (map_min_x >= f_NW_corner_longitude && map_min_y >= f_SE_corner_latitude && map_max_x <= f_SE_corner_longitude && map_max_y <= f_NW_corner_latitude) { retval=1; } return (retval); } ///////////////////////////////////////////////////////////////////// // map_visible_lat_lon() // // We have the center of the view in floating point format: // // float f_center_longitude; // Floating point map center longitude // float f_center_latitude; // Floating point map center latitude // // So we just need to compute the top/bottom/left/right using those // values and the scale_x/scale_y values before doing the compare. // // y scaling in 1/100 sec per pixel // x scaling in 1/100 sec per pixel, calculated from scale_y // // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // ******************* ******************* max_y // *NW * + * * + // * * * * // * * * * // * View * latitude (y) * Map * // * * * * // * * * * // * SE* - * * - // ******************* ******************* min_y // - longitude(x) + - min_x max_x + ///////////////////////////////////////////////////////////////////// int map_visible_lat_lon (double map_min_y, // f_bottom_map_boundary double map_max_y, // f_top_map_boundary double map_min_x, // f_left_map_boundary double map_max_x) // f_right_map_boundary { //fprintf(stderr,"map_visible_lat_lon\n"); // From computation geometry equations, intersection of two line // segments, they use the bounding box for two lines. This is // the same as what we want to do: // // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa // http://www.gamedev.net/reference/articles/article735.asp // // The quick rejection algorithm: // if (map_max_y < f_SE_corner_latitude ) { return(0); // map below view } if (map_max_x < f_NW_corner_longitude) { return(0); // map left of view } if (map_min_y > f_NW_corner_latitude ) { return(0); // view below map } if (map_min_x > f_SE_corner_longitude) { return(0); // view left of map } return (1); // Draw this map onto the screen } /********************************************************** * draw_label_text() * * Does what it says. Used to draw strings onto the * display. **********************************************************/ void draw_label_text (Widget w, int x, int y, int label_length, int color, char *label_text) { // This draws a gray background rectangle upon which we draw the text. // Probably not needed. It ends up obscuring details underneath. //(void)XSetForeground (XtDisplay (w), gc, colors[0x0ff]); //(void)XFillRectangle (XtDisplay (w), pixmap, gc, x - 1, (y - 10),(label_length * 6) + 2, 11); (void)XSetForeground (XtDisplay (w), gc, color); (void)XDrawString (XtDisplay (w), pixmap, gc, x, y, label_text, label_length); } // Must make sure that fonts are not loaded again and again, as this // takes a big chunk of memory each time. Can you say "memory // leak"? XFontStruct *rotated_label_font[FONT_MAX]= {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; char rotated_label_fontname[FONT_MAX][MAX_LABEL_FONTNAME]; static char current_rotated_label_fontname[FONT_MAX][sizeof(rotated_label_fontname)] = {"","","","","","","","",""}; /********************************************************** * draw_rotated_label_text_common() * call through wrappers: * draw_rotated_label_text_to_pixmap() * draw_rotated_label_text() * draw_centered_label_text() * * Does what it says. Used to draw strings onto the * display. * * Use "xfontsel" or other tools to figure out what fonts * to use here. * * Paramenters: * target_pixmap specifies the pixmap the text is to be drawn to. * draw_outline specifies whether a 1 pixel outline around the * text, TRUE to draw outline. * outline_bg_color is the color of the outline. * color is the color of the text inside the outline, or the * color of the text itself if no outline is added. **********************************************************/ /* common code used by the two entries --- a result of retrofitting a new feature (centered) */ static void draw_rotated_label_text_common (Widget w, float my_rotation, int x, int y, int UNUSED(label_length), int color, char *label_text, int align, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color) { // XPoint *corner; // int i; int x_outline; int y_outline; // Do some sanity checking if (fontsize < 0 || fontsize >= FONT_MAX) { fprintf(stderr,"Font size is out of range: %d\n", fontsize); return; } /* see if fontname has changed */ if (rotated_label_font[fontsize] && strcmp(rotated_label_fontname[fontsize],current_rotated_label_fontname[fontsize]) != 0) { XFreeFont(XtDisplay(w),rotated_label_font[fontsize]); rotated_label_font[fontsize] = NULL; xastir_snprintf(current_rotated_label_fontname[fontsize], sizeof(rotated_label_fontname), "%s", rotated_label_fontname[fontsize]); } /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"draw_rotated_label_text: Couldn't get font %s\n", rotated_label_fontname[fontsize]); return; } } if (draw_outline) { // make outline style (void)XSetForeground(XtDisplay(w),gc,outline_bg_color); // Draw the string repeatedly with 1 pixel offsets in the // background color to make an outline. for (x_outline=-1; x_outline<2; x_outline++) { for (y_outline=-1; y_outline<2; y_outline++) { // draws one extra copy at x,y (void)XRotDrawAlignedString(XtDisplay (w), rotated_label_font[fontsize], my_rotation, target_pixmap, gc, x+x_outline, y+y_outline, label_text, align); } } } // Code to determine the bounding box corner points for the rotated text // corner = XRotTextExtents(w,rotated_label_font,my_rotation,x,y,label_text,BLEFT); // for (i=0;i<5;i++) { // fprintf(stderr,"%d,%d\t",corner[i].x,corner[i].y); // } // fprintf(stderr,"\n"); (void)XSetForeground (XtDisplay (w), gc, color); //fprintf(stderr,"%0.1f\t%s\n",my_rotation,label_text); (void)XRotDrawAlignedString(XtDisplay (w), rotated_label_font[fontsize], my_rotation, target_pixmap, gc, x, y, label_text, align); } // Find the pixel length of an unrotated string in the rotated_label_font. // Parameters: // w - the XtDisplay. // label_text - the string of which the length is to be found. // fontsize - the fontsize in the rotated_label_font in which the string // is to be rendered. // Returns: the length in pixels of the string, -1 on an error. int get_rotated_label_text_length_pixels(Widget w, char *label_text, int fontsize) { int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. int return_value; // value to return int got_font; // flag indicating that a font is available return_value = -1; got_font = TRUE; /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"get_rotated_label_text_length_pixels: Couldn't get font %s\n", rotated_label_fontname[fontsize]); got_font = FALSE; } } if (got_font) { // find out the width in pixels of the unrotated label_text string. XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc, &overall); return_value = overall.width; } return return_value; } // Find the pixel height of an unrotated string in the rotated_label_font. // Parameters: // w - the XtDisplay. // label_text - the string of which the length is to be found. // fontsize - the fontsize in the rotated_label_font in which the string // is to be rendered. // Returns: the height in pixels of the string, -1 on an error. int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize) { int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. int return_value; // value to return int got_font; // flag indicating that a font is available return_value = -1; got_font = TRUE; /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"get_rotated_label_text_height_pixels: Couldn't get font %s\n", rotated_label_fontname[fontsize]); got_font = FALSE; } } if (got_font) { // find out the width in pixels of the unrotated label_text string. XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc, &overall); return_value = overall.ascent + overall.descent; } return return_value; } // Draw a rotated label onto the specified pixmap. // Wrapper for draw_rotated_label_text-common(). void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color) { float my_rotation = (float)((-rotation)-90); if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BRIGHT, fontsize, target_pixmap, draw_outline, outline_bg_color); } else { (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BLEFT, fontsize, target_pixmap, draw_outline, outline_bg_color); } } void draw_rotated_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize) { float my_rotation = (float)((-rotation)-90); if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BRIGHT, fontsize, pixmap, 0, 0); } else { (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BLEFT, fontsize, pixmap, 0, 0); } } void draw_centered_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize) { float my_rotation = (float)((-rotation)-90); (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BCENTRE, fontsize, pixmap, 0, 0); } static void Print_postscript_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; XtPopdown(shell); begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" ); if (print_postscript_dialog) { // Snag the path to the printer program from the print dialog temp_ptr = XmTextFieldGetString(printer_data); xastir_snprintf(printer_program, sizeof(printer_program), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(printer_program); // Check for empty variable if (printer_program[0] == '\0') { #ifdef LPR_PATH // Path to LPR if defined xastir_snprintf(printer_program, sizeof(printer_program), "%s", LPR_PATH); #else // LPR_PATH // Empty path printer_program[0]='\0'; #endif // LPR_PATH } //fprintf(stderr,"%s\n", printer_program); // Snag the path to the previewer program from the print dialog temp_ptr = XmTextFieldGetString(previewer_data); xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(previewer_program); // Check for empty variable if (previewer_program[0] == '\0') { #ifdef GV_PATH // Path to GV if defined xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", GV_PATH); #else // GV_PATH // Empty string previewer_program[0] = '\0'; #endif // GV_PATH } //fprintf(stderr,"%s\n", previewer_program); } XtDestroyWidget(shell); print_postscript_dialog = (Widget)NULL; end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" ); } static void Print_properties_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (!shell) { return; } XtPopdown(shell); begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" ); XtDestroyWidget(shell); print_properties_dialog = (Widget)NULL; end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" ); } // Print_window: Prints the drawing area to a Postscript file and // then sends it to the printer program (usually "lpr). // static void Print_window( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef NO_XPM // fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n"); popup_message_always(langcode("POPEM00035"), "XPM or ImageMagick support not compiled into Xastir! Cannot Print!"); #else // NO_XPM char xpm_filename[MAX_FILENAME]; char ps_filename[MAX_FILENAME]; char command[MAX_FILENAME*2]; char temp[MAX_FILENAME]; int xpmretval; char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/print.xpm", temp_base_dir); xastir_snprintf(ps_filename, sizeof(ps_filename), "%s/print.ps", temp_base_dir); busy_cursor(appshell); // Show a busy cursor while we're doing all of this // Get rid of the Print dialog Print_postscript_destroy_shell(widget, print_postscript_dialog, NULL ); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") ); statusline(temp,1); // Dumping image to file... if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for print_window\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display "print.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); popup_message_always(langcode("POPEM00035"), "Error writing xpm image file! Cannot Print!"); return; } else // We now have the xpm file created on disk { chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename ); } // Convert it to a postscript file for printing. This depends // on the ImageMagick command "convert". // if (debug_level & 512) { fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") ); statusline(temp,1); // Converting to Postscript... #ifdef HAVE_CONVERT strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -filter Point "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command ); } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't convert from XPM to PS!"); return; } #endif // HAVE_CONVERT chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // Delete temporary xpm file if ( !(debug_level & 512) ) { unlink( xpm_filename ); } if ( debug_level & 512 ) { fprintf(stderr,"Printing postscript file %s\n", ps_filename); } // Note: This needs to be changed to "lp" for Solaris. // Also need to have a field to configure the printer name. One // fill-in field could do both. // // Since we could be running SUID root, we don't want to be // calling "system" anyway. Several problems with it. strcpy(command, printer_program); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command); } if (printer_program[0] == '\0') { // fprintf(stderr,"\n\nPrint: No print program defined!\n\n\n"); popup_message_always(langcode("POPEM00035"), "No print program defined!"); return; } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't send to the printer!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't send to the printer!"); return; } /* if ( !(debug_level & 512) ) unlink( ps_filename ); */ if ( debug_level & 512 ) { fprintf(stderr," Done printing.\n"); } } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") ); statusline(temp,1); // Finished creating print file. //popup_message( langcode("PRINT0015"), langcode("PRINT0014") ); #endif // NO_XPM } // Print_preview: Prints the drawing area to a Postscript file. If // previewer_program has "gv" in it, then use the various options // selected by the user. If not, skip those options. // static void Print_preview( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef NO_XPM // fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n"); popup_message_always(langcode("POPEM00035"), "XPM or ImageMagick support not compiled into Xastir! Cannot Print!"); #else // NO_GRAPHICS char xpm_filename[MAX_FILENAME]; char ps_filename[MAX_FILENAME]; char mono[50] = ""; char invert[50] = ""; char rotate[50] = ""; char scale[50] = ""; char density[50] = ""; char command[MAX_FILENAME*2]; char temp[MAX_FILENAME]; char format[100] = " "; int xpmretval; char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/print.xpm", temp_base_dir); xastir_snprintf(ps_filename, sizeof(ps_filename), "%s/print.ps", temp_base_dir); busy_cursor(appshell); // Show a busy cursor while we're doing all of this // Get rid of the Print Properties dialog if it exists Print_properties_destroy_shell(widget, print_properties_dialog, NULL ); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") ); statusline(temp,1); // Dumping image to file... if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for print_preview\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display "print.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); popup_message_always(langcode("POPEM00035"), "Error writing XPM file!"); return; } else // We now have the xpm file created on disk { chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename ); } // If we're not using "gv", skip most of the code below and // go straight to the previewer program portion of the code. // if ( strstr(previewer_program,"gv") ) { // Convert it to a postscript file for printing. This // depends on the ImageMagick command "convert". // // Other options to try in the future: // -label // if ( print_auto_scale ) { // sprintf(scale, "-geometry 612x792 -page 612x792 "); // "Letter" size at 72 dpi // sprintf(scale, "-sample 612x792 -page 612x792 "); // "Letter" size at 72 dpi xastir_snprintf(scale, sizeof(scale), "-page 1275x1650+0+0 "); // "Letter" size at 150 dpi } else { scale[0] = '\0'; // Empty string } if ( print_in_monochrome ) { xastir_snprintf(mono, sizeof(mono), "-monochrome +dither " ); // Monochrome } else { xastir_snprintf(mono, sizeof(mono), "+dither "); // Color } if ( print_invert ) { xastir_snprintf(invert, sizeof(invert), "-negate " ); // Reverse Colors } else { invert[0] = '\0'; // Empty string } if (debug_level & 512) { fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height); } if ( print_rotated ) { xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " ); #ifdef HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "-landscape " ); #else // HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "--orientation=landscape " ); #endif // HAVE_OLD_GV } else if ( print_auto_rotation ) { // Check whether the width or the height of the // pixmap is greater. If width is greater than // height, rotate the image by 270 degrees. if (screen_width > screen_height) { xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " ); #ifdef HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "-landscape " ); #else // HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "--orientation=landscape " ); #endif // HAVE_OLD_GV if (debug_level & 512) { fprintf(stderr,"Rotating\n"); } } else { rotate[0] = '\0'; // Empty string if (debug_level & 512) { fprintf(stderr,"Not Rotating\n"); } } } else { rotate[0] = '\0'; // Empty string if (debug_level & 512) { fprintf(stderr,"Not Rotating\n"); } } // Higher print densities require more memory and time // to process xastir_snprintf(density, sizeof(density), "-density %dx%d", print_resolution, print_resolution ); xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") ); statusline(temp,1); // Converting to Postscript... // Filters: // Point (ok at higher dpi's) // Box (not too bad) // Triangle (no) // Hermite (no) // Hanning (no) // Hamming (no) // Blackman (better but still not good) // Gaussian (no) // Quadratic (no) // Cubic (no) // Catrom (not too bad) // Mitchell (no) // Lanczos (no) // Bessel (no) // Sinc (not too bad) } #ifdef HAVE_CONVERT strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -filter Point "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, mono); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, invert); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, rotate); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, scale); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, density); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command ); } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't convert from XPM to PS!"); return; } #endif // HAVE_CONVERT chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // Delete temporary xpm file if ( !(debug_level & 512) ) { unlink( xpm_filename ); } if ( debug_level & 512 ) { fprintf(stderr,"Printing postscript file %s\n", ps_filename); } // Since we could be running SUID root, we don't want to be // calling "system" anyway. Several problems with it. // Bring up the postscript viewer strcpy(command, previewer_program); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, format); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " &"); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command); } if (previewer_program[0] == '\0') { // fprintf(stderr,"\n\nPrint: No print previewer defined!\n\n\n"); popup_message_always(langcode("POPEM00035"), "No print previewer defined!"); return; } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't bring up the postscript viewer!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't bring up the viewer!"); return; } /* if ( !(debug_level & 512) ) unlink( ps_filename ); */ if ( debug_level & 512 ) { fprintf(stderr," Done printing.\n"); } } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") ); statusline(temp,1); // Finished creating print file. //popup_message( langcode("PRINT0015"), langcode("PRINT0014") ); #endif // NO_XPM } /* * Auto_rotate * */ static void Auto_rotate( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_auto_rotation = atoi(which); print_rotated = 0; XmToggleButtonSetState(rotate_90, FALSE, FALSE); } else { print_auto_rotation = 0; } } /* * Rotate_90 * */ static void Rotate_90( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_rotated = atoi(which); print_auto_rotation = 0; XmToggleButtonSetState(auto_rotate, FALSE, FALSE); } else { print_rotated = 0; } } /* * Auto_scale * */ static void Auto_scale( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_auto_scale = atoi(which); } else { print_auto_scale = 0; } } /* * Monochrome * */ void Monochrome( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_in_monochrome = atoi(which); } else { print_in_monochrome = 0; } } /* * Invert * */ static void Invert( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_invert = atoi(which); } else { print_invert = 0; } } // Print_properties: Prints the drawing area to a PostScript file. // Provides various togglebuttons for configuring the "gv" previewer // only. // // Perhaps later: // 1) Select an area on the screen to print // 2) -label // void Print_properties( Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_cancel, sep, auto_scale, // paper_size, paper_size_data, scale, scale_data, blank_background, // res_label1, res_label2, res_x, res_y, monochrome, invert; Atom delw; // Get rid of the Print dialog Print_postscript_destroy_shell(w, print_postscript_dialog, NULL ); // If we're not using "gv", skip the entire dialog below and go // straight to the actual previewer function. // if ( !strstr(previewer_program,"gv") ) { Print_preview(w, NULL, NULL); return; } if (!print_properties_dialog) { begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" ); print_properties_dialog = XtVaCreatePopupShell(langcode("PRINT0001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Print_properties pane",xmPanedWindowWidgetClass, print_properties_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Print_properties form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); /* paper_size = XtVaCreateManagedWidget(langcode("PRINT0002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(paper_size,FALSE); paper_size_data = XtVaCreateManagedWidget("Print_properties paper_size_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, paper_size, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(paper_size_data,FALSE); */ auto_rotate = XtVaCreateManagedWidget(langcode("PRINT0003"),xmToggleButtonWidgetClass,form, // XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, paper_size_data, // XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(auto_rotate,XmNvalueChangedCallback,Auto_rotate,"1"); rotate_90 = XtVaCreateManagedWidget(langcode("PRINT0004"),xmToggleButtonWidgetClass,form, // XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, paper_size_data, // XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, auto_rotate, XmNleftOffset,10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(rotate_90,XmNvalueChangedCallback,Rotate_90,"1"); auto_scale = XtVaCreateManagedWidget(langcode("PRINT0005"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(auto_scale,XmNvalueChangedCallback,Auto_scale,"1"); /* scale = XtVaCreateManagedWidget(langcode("PRINT0006"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, auto_scale, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(scale,FALSE); scale_data = XtVaCreateManagedWidget("Print_properties scale_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, scale, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(scale_data,FALSE); */ /* blank_background = XtVaCreateManagedWidget(langcode("PRINT0007"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, scale_data, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset ,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(blank_background,FALSE); */ monochrome = XtVaCreateManagedWidget(langcode("PRINT0008"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, blank_background, XmNtopWidget, auto_scale, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(monochrome,XmNvalueChangedCallback,Monochrome,"1"); invert = XtVaCreateManagedWidget(langcode("PRINT0016"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, monochrome, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(invert,XmNvalueChangedCallback,Invert,"1"); /* res_label1 = XtVaCreateManagedWidget(langcode("PRINT0009"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(res_label1,FALSE); res_x = XtVaCreateManagedWidget("Print_properties resx_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_label1, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(res_x,FALSE); res_label2 = XtVaCreateManagedWidget("X",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_x, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(res_label2,FALSE); res_y = XtVaCreateManagedWidget("Print_properties res_y_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_label2, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(res_y,FALSE); */ sep = XtVaCreateManagedWidget("Print_properties sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, // XmNtopWidget, res_y, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button_ok = XtVaCreateManagedWidget(langcode("PRINT0011"),xmPushButtonGadgetClass, form, button_ok = XtVaCreateManagedWidget(langcode("PRINT0010"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Print_preview, NULL ); XtAddCallback(button_cancel, XmNactivateCallback, Print_properties_destroy_shell, print_properties_dialog); XmToggleButtonSetState(rotate_90,FALSE,FALSE); XmToggleButtonSetState(auto_rotate,TRUE,FALSE); if (print_auto_rotation) { XmToggleButtonSetState(auto_rotate, TRUE, TRUE); } else { XmToggleButtonSetState(auto_rotate, FALSE, TRUE); } if (print_rotated) { XmToggleButtonSetState(rotate_90, TRUE, TRUE); } else { XmToggleButtonSetState(rotate_90, FALSE, TRUE); } if (print_in_monochrome) { XmToggleButtonSetState(monochrome, TRUE, FALSE); } else { XmToggleButtonSetState(monochrome, FALSE, FALSE); } if (print_invert) { XmToggleButtonSetState(invert, TRUE, FALSE); } else { XmToggleButtonSetState(invert, FALSE, FALSE); } if (print_auto_scale) { XmToggleButtonSetState(auto_scale, TRUE, TRUE); } else { XmToggleButtonSetState(auto_scale, FALSE, TRUE); } // XmTextFieldSetString(paper_size_data,print_paper_size); end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" ); pos_dialog(print_properties_dialog); delw = XmInternAtom(XtDisplay(print_properties_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(print_properties_dialog, delw, Print_properties_destroy_shell, (XtPointer)print_properties_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, print_properties_dialog); XtPopup(print_properties_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(print_properties_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(print_properties_dialog), XtWindow(print_properties_dialog)); } } // General print dialog. From here we can either print Postscript // files to the device selected in this dialog, or head off to a // print preview program that might allow us a variety of print // options. From here we should be able to set the print device // and the print preview program & path. // void Print_Postscript( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_print, button_cancel, sep, button_preview; Atom delw; if (!print_postscript_dialog) { begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" ); print_postscript_dialog = XtVaCreatePopupShell(langcode("PULDNFI015"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Print_postscript pane",xmPanedWindowWidgetClass, print_postscript_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Print_postscript form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // "Direct to:" button_print = XtVaCreateManagedWidget(langcode("PRINT1001"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); printer_data = XtVaCreateManagedWidget("Print_Postscript printer_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, MAX_FILENAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_print, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // "Via Previewer:" button_preview = XtVaCreateManagedWidget(langcode("PRINT1002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_print, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); previewer_data = XtVaCreateManagedWidget("Print_Postscript previewer_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, MAX_FILENAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, button_print, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_preview, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Print_postscript sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, button_preview, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_preview, XmNactivateCallback, Print_properties, NULL ); XtAddCallback(button_print, XmNactivateCallback, Print_window, NULL ); XtAddCallback(button_cancel, XmNactivateCallback, Print_postscript_destroy_shell, print_postscript_dialog); // Fill in the text fields from persistent variables out of the config file. XmTextFieldSetString(printer_data, printer_program); XmTextFieldSetString(previewer_data, previewer_program); end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" ); pos_dialog(print_postscript_dialog); delw = XmInternAtom(XtDisplay(print_postscript_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(print_postscript_dialog, delw, Print_postscript_destroy_shell, (XtPointer)print_postscript_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, print_postscript_dialog); XtPopup(print_postscript_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(print_postscript_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(print_postscript_dialog), XtWindow(print_postscript_dialog)); } } // Create png image (for use in web browsers??). Requires that "convert" // from the ImageMagick package be installed on the system. At the // point this thread is started, the XPM file has already been // created. We now create a .geo file to go with the .png file. // #ifndef NO_XPM static void* snapshot_thread(void * UNUSED(arg) ) { char xpm_filename[MAX_FILENAME]; char png_filename[MAX_FILENAME]; char geo_filename[MAX_FILENAME]; char kml_filename[MAX_FILENAME]; // filename for kml file that describes the png file in keyhole markup language char timestring[101]; // string representation of the time heard or the current time FILE *f; FILE *fk; // file handle for kml file time_t expire_time; #ifdef HAVE_CONVERT char command[MAX_FILENAME*2]; #endif // HAVE_CONVERT char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); // The pthread_detach() call means we don't care about the // return code and won't use pthread_join() later. Makes // threading more efficient. (void)pthread_detach(pthread_self()); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/snapshot.xpm", temp_base_dir); xastir_snprintf(png_filename, sizeof(png_filename), "%s/snapshot.png", temp_base_dir); // Same for the .geo filename xastir_snprintf(geo_filename, sizeof(geo_filename), "%s/snapshot.geo", temp_base_dir); // Same for the .kml filename xastir_snprintf(kml_filename, sizeof(kml_filename), "%s/snapshot.kml", temp_base_dir); // Create a .geo file to match the new png image // Likewise for a matching .kml file f = fopen(geo_filename,"w"); // Overwrite whatever file // is there. fk = fopen(kml_filename,"w"); if (f == NULL || fk == NULL) { if (f==NULL) { fprintf(stderr,"Couldn't open %s\n",geo_filename); } if (fk==NULL) { fprintf(stderr,"Couldn't open %s\n",kml_filename); } } else { float lat1, long1, lat2, long2; long1 = f_NW_corner_longitude; lat1 = f_NW_corner_latitude; long2 = f_SE_corner_longitude; lat2 = f_SE_corner_latitude; // FILENAME world1.xpm // # x y lon lat // TIEPOINT 0 0 -180 90 // TIEPOINT 639 319 180 -90 // IMAGESIZE 640 320 // REFRESH 250 fprintf(f,"FILENAME snapshot.png\n"); fprintf(f,"# x y lon lat\n"); fprintf(f,"TIEPOINT 0 0 %8.5f %8.5f\n", long1, lat1); fprintf(f,"TIEPOINT %-4d %-4d %8.5f %8.5f\n", (int)screen_width-1, (int)screen_height-1, long2, lat2); fprintf(f,"IMAGESIZE %-4d %-4d\n", (int)screen_width, (int)screen_height); fprintf(f,"REFRESH 250\n"); fclose(f); // Write a matching kml file that describes the location of the snapshot on // the Earth's surface. // Another kml file pointing to the location of this file with a networklinkcontrol element // and an update element loaded into a kml application should be able to reload this file // at regular intervals. // See kml documentation of: // // // // // // // // http://www.example.com/cgi-bin/screenshot.kml // onExpire // // // // // // TODO: Calculate a suitable range and tilt for viewing the snapshot draped on the // underlying terrain. fprintf(fk,"\n"); fprintf(fk,"\n"); // Add an expire time matching the time when the next snapshot should // be produced, so that a network link with an onExpire refresh mode // will check for the next snapshot. expire_time = sec_now() + (time_t)(snapshot_interval * 60); if (get_w3cdtf_datetime(expire_time, timestring, False, False)) { if (strlen(timestring) > 0) { fprintf(fk," \n"); fprintf(fk," %s\n",timestring); fprintf(fk," \n"); } } fprintf(fk," \n"); fprintf(fk," XASTIR Snapshot from %s\n",my_callsign); fprintf(fk," 1\n"); fprintf(fk," \n"); fprintf(fk," Xastir snapshot\n"); fprintf(fk," 1\n"); // timestamp the overlay with the current time if (get_w3cdtf_datetime(sec_now(), timestring, True, True)) { if (strlen(timestring) > 0) { fprintf(fk," %s\n",timestring); fprintf(fk," Overlay shows screen visible for %s in Xastir at %s.\n",my_callsign,timestring); } } else { fprintf(fk," Overlay shows screen visible for %s in Xastir.\n",my_callsign); } fprintf(fk," \n"); fprintf(fk," %8.5f\n",f_center_longitude); fprintf(fk," %8.5f\n",f_center_latitude); fprintf(fk," 0\n"); fprintf(fk," 30350.36838438907\n"); // range in meters from viewer to lookat point fprintf(fk," 0\n"); // 0 is looking straight down fprintf(fk," clampToGround\n"); fprintf(fk," 0\n"); // 0 is north at top, 90 east at top fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," snapshot.png\n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," %8.5f\n",lat1); fprintf(fk," %8.5f\n",lat2); fprintf(fk," %8.5f\n",long2); fprintf(fk," %8.5f\n",long1); fprintf(fk," 0\n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk,"\n"); fclose(fk); chmod( geo_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); chmod( kml_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); } if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, png_filename ); } #ifdef HAVE_CONVERT // Convert it to a png file. This depends upon having the // ImageMagick command "convert" installed. strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -quality 100 -colors 256 "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, png_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( system( command ) != 0 ) { // We _may_ have had an error. Check errno to make // sure. if (errno) { fprintf(stderr, "%s\n", strerror(errno)); fprintf(stderr, "Failed to convert snapshot: %s -> %s\n", xpm_filename, png_filename); } else { fprintf(stderr, "System call return error: convert: %s -> %s\n", xpm_filename, png_filename); } } else { chmod( png_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // // Delete temporary xpm file // unlink( xpm_filename ); if ( debug_level & 512 ) { fprintf(stderr," Done creating png.\n"); } } #endif // HAVE_CONVERT // Signify that we're all done and that another snapshot can // occur. doing_snapshot = 0; return(NULL); } #endif // NO_XPM // Starts a separate thread that creates a png image from the // current displayed image. // void Snapshot(void) { #ifndef NO_XPM pthread_t snapshot_thread_id; char xpm_filename[MAX_FILENAME]; int xpmretval; #endif // NO_XPM char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); // Check whether we're already doing a snapshot if (doing_snapshot) { return; } // Time to take another snapshot? // New snapshot interval based on slider in Configure Timing // dialog (in minutes) if (sec_now() < (last_snapshot + (snapshot_interval * 60)) ) { return; } last_snapshot = sec_now(); // Set up timer for next time #ifndef NO_XPM if (debug_level & 512) { fprintf(stderr,"Taking Snapshot\n"); } doing_snapshot++; // Set up the XPM filename that we'll use xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/snapshot.xpm", temp_base_dir); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } // Create an XPM file from pixmap_final. if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for snapshot\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell), // Display *display "snapshot.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); return; } chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); //----- Start New Thread ----- // // Here we start a new thread. We'll communicate with the main // thread via global variables. Use mutex locks if there might // be a conflict as to when/how we're updating those variables. // if (pthread_create(&snapshot_thread_id, NULL, snapshot_thread, NULL)) { fprintf(stderr,"Error creating snapshot thread\n"); } else { // We're off and running with the new thread! } #endif // NO_XPM } // Function to remove double-quote characters and spaces that occur // outside of the double-quote characters. void clean_string(char *input) { char *i; char *j; //fprintf(stderr,"|%s|\t",input); // Remove any double quote characters i = index(input,'"'); // Find first quote character, if any if (i != NULL) { j = index(i+1,'"'); // Find second quote character, if any if (j != NULL) // Found two quote characters { j[0] = '\0'; // Terminate the string at the 2nd quote // Can't use strcpy here because it can't work with // overlapping strings. strcpy is a dangerous function // anyway and shouldn't be used. memmove(input, i+1, j-i); } else // We only found one quote character. What to do? { // fprintf(stderr,"clean_string: Only one quote found!\n"); } } //fprintf(stderr,"|%s|\n",input); // Remove leading/trailing spaces? } // Test map visibility (on screen) // // Input parameters are in Xastir coordinate system (fastest for us) // check_percentage: // 0 = don't check // 1 = check map size versus viewport scale. Return 0 if map // is too large/small (percentage-wise) to be displayed. // // Returns: MAP_NOT_VIS if map is _not_ visible // MAP_IS_VIS if map _is_ visible // // Xastir Coordinate System: // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Note that we already have map_visible() and map_visible_lat_lon() // routines. // enum map_onscreen_enum map_onscreen(long left, long right, long top, long bottom, int UNUSED(check_percentage) ) { enum map_onscreen_enum in_window = MAP_NOT_VIS; if (map_visible((unsigned long)bottom, (unsigned long)top, (unsigned long)left, (unsigned long)right)) { in_window = MAP_IS_VIS; //fprintf(stderr,"map_onscreen:Map is visible\n"); } #ifdef MAP_SCALE_CHECK // Check whether map is too large/small for our current scale? // Check whether the map extents are < XX% of viewscreen size // (both directions), or viewscreen is > XX% of map extents // (either direction). This will knock out maps that are too // large/small to be displayed at this zoom level. //WE7U if (in_window && check_percentage) { long map_x, map_y, view_x, view_y; float percentage = 0.04; map_x = right - left; if (map_x < 0) { map_x = 0; } map_y = bottom - top; if (map_y < 0) { map_y = 0; } view_x = max_NW_corner_longitude - NW_corner_longitude; if (view_x < 0) { view_x = 0; } view_y = max_NW_corner_latitude - NW_corner_latitude; if (view_y < 0) { view_y = 0; } //fprintf(stderr,"\n map_x: %d\n", map_x); //fprintf(stderr," map_y: %d\n", map_y); //fprintf(stderr,"view_x: %d\n", view_x); //fprintf(stderr,"view_y: %d\n", view_y); if ((map_x < (view_x * percentage )) && (map_y < (view_x * percentage))) { in_window = 0; // Send back "not-visible" flag fprintf(stderr,"map too small for view: %d%%\n",(int)(percentage * 100)); } // if ((view_x < (map_x * percentage)) && (view_y < (map_x * percentage))) { // in_window = 0; // Send back "not-visible" flag //fprintf(stderr,"view too small for map: %d%%\n",(int)(percentage * 100)); // } } #endif // MAP_SCALE_CHECK //fprintf(stderr,"map_onscreen returning %d\n", in_window); return (in_window); } // Function which checks whether a map is onscreen, but does so by // finding the map boundaries from the map index. The only input // parameter is the complete path/filename. // // Returns: MAP_NOT_VIS if map is _not_ visible // MAP_IS_VIS if map _is_ visible // MAP_NOT_INDEXED if the map is not in the index // enum map_onscreen_enum map_onscreen_index(char *filename) { unsigned long top, bottom, left, right; enum map_onscreen_enum onscreen = MAP_NOT_INDEXED; int max_zoom, min_zoom; int map_layer, draw_filled, usgs_drg, auto_maps; // Unused in this function if (index_retrieve(filename, &bottom, &top, &left, &right, &max_zoom, &min_zoom, &map_layer, &draw_filled, &usgs_drg, &auto_maps) ) { //fprintf(stderr, "Map found in index: %s\n", filename); // Map was in the index, check for visibility and scale // Check whether the map extents are < XX% of viewscreen // size (both directions), or viewscreen is > XX% of map // extents (either direction). This will knock out maps // that are too large/small to be displayed at this zoom // level. if (map_onscreen(left, right, top, bottom, 1)) { //fprintf(stderr, "Map found in index and onscreen: %s\n", filename); if (((max_zoom == 0) || ((max_zoom != 0) && (scale_y <= max_zoom))) && ((min_zoom == 0) || ((min_zoom != 0) && (scale_y >= min_zoom)))) { onscreen = MAP_IS_VIS; //fprintf(stderr,"Map in the zoom zone: %s\n",filename); } else { onscreen = MAP_NOT_VIS; //fprintf(stderr,"Map not in the zoom zone: %s\n",filename); } // Check whether the map extents are < XX% of viewscreen size (both // directions), or viewscreen is > XX% of map extents (either // direction). This will knock out maps that are too large/small to // be displayed at this zoom level. } else // Map is not visible { onscreen = MAP_NOT_VIS; //fprintf(stderr,"Map found in index but not onscreen: %s\n",filename); } } else // Map is not in the index { onscreen = MAP_NOT_INDEXED; //fprintf(stderr,"Map not found in index: %s\n",filename); } return(onscreen); } /********************************************************** * draw_map() * * Function which tries to figure out what type of map or * image file we're dealing with, and takes care of getting * it onto the screen. Calls other functions to deal with * .geo/.tif/.shp maps. * * If destination_pixmap == DRAW_NOT, then we'll not draw * the map anywhere, but we'll determine the map extents * and write them to the map index file. **********************************************************/ /* table of map drivers, selected by filename extension */ extern void draw_dos_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_palm_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); #ifdef HAVE_LIBSHP extern void draw_shapefile_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void clear_dbfawk_sigs(void); #endif /* HAVE_LIBSHP */ #ifdef HAVE_LIBGEOTIFF extern void draw_geotiff_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); #endif /* HAVE_LIBGEOTIFF */ extern void draw_geo_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_gnis_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_pop_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); struct { char *ext; enum {none=0, map, tif, geo, gnis, shp, pop} type; void (*func)(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); } map_driver[] = { {"map",map,draw_dos_map}, #ifdef HAVE_LIBGEOTIFF {"tif",tif,draw_geotiff_image_map}, #endif /* HAVE_LIBGEOTIFF */ {"geo",geo,draw_geo_image_map}, {"gnis",gnis,draw_gnis_map}, {"pop",pop,draw_pop_map}, #ifdef HAVE_LIBSHP {"shp",shp,draw_shapefile_map}, #endif /* HAVE_LIBSHP */ {NULL,none,NULL} }, *map_driver_ptr; void draw_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags) { enum map_onscreen_enum onscreen; char *ext; char file[MAX_FILENAME]; if ((ext = get_map_ext(filenm)) == NULL) { return; } if (debug_level & 16) { fprintf(stderr,"draw_map: Searching for map driver\n"); } for (map_driver_ptr = map_driver; map_driver_ptr->ext; map_driver_ptr++) { if (strcasecmp(ext,map_driver_ptr->ext) == 0) { if (debug_level & 16) fprintf(stderr, "draw_map: Found map driver: %s: %d\n", ext, map_driver_ptr->type); break; /* found our map_driver */ } } if (map_driver_ptr->type == none) /* fall thru: unknown map driver */ { // Check whether we're indexing or drawing the map if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { // We're drawing, not indexing. Output a warning // message. fprintf(stderr,"*** draw_map: Unknown map type: %s ***\n", filenm); } else // We're indexing { if (debug_level & 16) { fprintf(stderr,"draw_map: No map driver found\n"); } } return; } onscreen = map_onscreen_index(filenm); // Check map index // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing maps if (onscreen != MAP_NOT_INDEXED) // We already have an index entry for this map. // This is where we pick up a big speed increase: // Refusing to index a map that's already indexed. { return; // Skip it. } } else // We're drawing maps { // See if map is visible. If not, skip it. if (onscreen == MAP_NOT_VIS) // Map is not visible, skip it. { //fprintf(stderr,"map not visible\n"); if (alert) { alert->flags[on_screen] = 'N'; } return; } } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Used for debugging. If we get a segfault on a map, this is // often the only way of finding out which map file we can't // handle. if (debug_level & 16) { fprintf(stderr,"draw_map: %s\n",file); } /* XXX - aren't alerts just shp maps? Why was there special case code? */ if (map_driver_ptr->func) { map_driver_ptr->func(w, dir, filenm, alert, alert_color, destination_pixmap, draw_flags); } XmUpdateDisplay (XtParent (da)); } // End of draw_map() static void index_update_directory(char *directory); static void index_update_accessed(char *filename); ///////////////////////////////////////////////////////////////////// // map_search() // // Function which recurses through map directories, finding map // files. It's called from load_auto_maps and load_alert_maps. If // a map file is found, it is drawn. We can also call this function // in indexing mode rather than draw mode, specified by the // destination_pixmap parameter. // // If alert == NULL, we looking for a regular map file to draw. // If alert != NULL, we have a weather alert to draw. // // For alert maps, we need to do things a bit differently, as there // should be only a few maps that contain all of the alert maps, and we // can compute which map some of them might be in. We need to fill in // the alert structure with the filename that alert is found in. // For alerts we're not drawing the maps, we're just computing the // full filename for the alert and filling that struct field in. // // The "warn" parameter specifies whether to warn the operator about // the alert on the console as well. If it was received locally or // via local RF, then the answer is yes. The severe weather may be // nearby. // // We have the timestamp of the map_index.sys file stored away in // the global: time_t map_index_timestamp; // Use that timestamp to compare the map file or GEO file timestamps // to. Re-index the map if map_index_timestamp is older. // ///////////////////////////////////////////////////////////////////// static void map_search (Widget w, char *dir, alert_entry * alert, int *alert_count,int warn, int destination_pixmap) { struct dirent *dl = NULL; DIR *dm; char fullpath[MAX_FILENAME]; struct stat nfile; // const time_t *ftime; // char this_time[40]; char *ptr; char *map_dir; int map_dir_length; map_draw_flags mdf; // We'll use the weather alert directory if it's an alert map_dir = alert ? ALERT_MAP_DIR : SELECTED_MAP_DIR; map_dir_length = (int)strlen (map_dir); if (alert) // We're doing weather alerts { // First check whether the alert->filename variable is filled // in. If so, we've already found the file and can just display // that shape in the file if (alert->filename[0] == '\0') // No filename in struct, so will have { // to search for the shape in the files. switch (alert->title[3]) { case 'F': // 'F' in 4th char means fire alert // Use fire alert file fz_?????? //fprintf(stderr,"%c:Fire Alert file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "fz"); break; case 'C': // 'C' in 4th char means county // Use County file c_?????? //fprintf(stderr,"%c:County file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "c_"); break; case 'A': // 'A' in 4th char means county warning area // Use County warning area w_????? //fprintf(stderr,"%c:County warning area file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "w_"); break; case 'Z': // Zone, coastal or offshore marine zone file z_????? or mz?????? or oz?????? // oz: ANZ081-086,088,PZZ081-085 // mz: AM,AN,GM,LC,LE,LH,LM,LO,LS,PH,PK,PM,PS,PZ,SL // z_: All others if (strncasecmp(alert->title,"AM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"AN",2) == 0) { // Need to check for Z081-Z086, Z088, if so use // oz??????, else use mz?????? if ( (strncasecmp(&alert->title[3],"Z081",4) == 0) || (strncasecmp(&alert->title[3],"Z082",4) == 0) || (strncasecmp(&alert->title[3],"Z083",4) == 0) || (strncasecmp(&alert->title[3],"Z084",4) == 0) || (strncasecmp(&alert->title[3],"Z085",4) == 0) || (strncasecmp(&alert->title[3],"Z086",4) == 0) || (strncasecmp(&alert->title[3],"Z088",4) == 0) ) { //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "oz"); } else { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } } else if (strncasecmp(alert->title,"GM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LC",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LE",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LH",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LO",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LS",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PH",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PK",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PS",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PZ",2) == 0) { // Need to check for PZZ081-085, if so use oz??????, else use mz?????? if ( (strncasecmp(&alert->title[3],"Z081",4) == 0) || (strncasecmp(&alert->title[3],"Z082",4) == 0) || (strncasecmp(&alert->title[3],"Z083",4) == 0) || (strncasecmp(&alert->title[3],"Z084",4) == 0) || (strncasecmp(&alert->title[3],"Z085",4) == 0) ) { //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "oz"); } else { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } } else if (strncasecmp(alert->title,"SL",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else { // Must be regular zone file instead of coastal // marine zone or offshore marine zone. //fprintf(stderr,"%c:Zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "z_"); } break; default: // VK2XJG // This section could most likely be moved so that it's not called as part of the default, but in order // to get the shapefiles for BOM working this was the best spot at the time... // Australian BOM alerts use the following shapefiles: // PW = Public Warning = gfe_public_weather // MW = Coastal Waters = gfe_coastal_waters // CW = Coastal Waters Warnings = gfe_coastal_waters_warnings // FW = Fire Weather = gfe_fire_weather // ME = Metro Effects = gfe_metro_areas // Note - Need to cater for both 2 and 3 character state designators // Shapefile filenames are static - there is no datestamp in the filename. if ((strncasecmp(&alert->title[4],"MW",2) == 0) || (strncasecmp(&alert->title[3],"MW",2) == 0)) { //fprintf(stderr,"%c:BOM Coastal Waters file\n",alert->title[4]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_coastal_waters.shp"); } else if ((strncasecmp(&alert->title[4],"CW",2) == 0) || (strncasecmp(&alert->title[3],"CW",2) == 0)) { //fprintf(stderr,"%c:BOM Coastal waters warning file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_coastal_waters_warnings.shp"); } else if ((strncasecmp(&alert->title[4],"PW",2) == 0) || (strncasecmp(&alert->title[3],"PW",2) == 0)) { //fprintf(stderr,"%c:BOM Public Weather file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_public_weather.shp"); } else if ((strncasecmp(&alert->title[4],"FW",2) == 0) || (strncasecmp(&alert->title[3],"FW",2) == 0)) { //fprintf(stderr,"%c:BOM Fire Weather file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_fire_weather.shp"); } else if ((strncasecmp(&alert->title[4],"ME",2) == 0) || (strncasecmp(&alert->title[3],"ME",2) == 0)) { //fprintf(stderr,"%c:BOM Metro Areas file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_metro_areas.shp"); } // Unknown type //fprintf(stderr,"%c:Can't match weather warning to a Shapefile:%s\n",alert->title[3],alert->title); break; } // fprintf(stderr,"%s\t%s\t%s\n",alert->activity,alert->alert_status,alert->title); //fprintf(stderr,"File: %s\n",alert->filename); } // NOTE: Need to skip this part if we have a full filename. if (alert->filename[0]) // We have at least a partial filename { int done = 0; if (strlen(alert->filename) > 3) { done++; // We already have a filename } if (!done) // We don't have a filename yet { // Look through the warning directory to find a match for // the first few characters that we already figured out. // This is designed so that we don't need to know the exact // filename, but only the lead three characters in order to // figure out which shapefile to use. dm = opendir (dir); if (!dm) // Couldn't open directory { xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir); // If local alert, warn the operator via the // console as well. if (warn) { perror (fullpath); } } else // We could open the directory just fine { while ( (dl = readdir(dm)) && !done ) { int i; // Check the file/directory name for control // characters for (i = 0; i < (int)strlen(dl->d_name); i++) { // Dump out a warning if control // characters other than LF or CR are // found. if ( (dl->d_name[i] != '\n') && (dl->d_name[i] != '\r') && (dl->d_name[i] < 0x20) ) { fprintf(stderr,"\nmap_search: Found control char 0x%02x in alert file/alert directory name. Line was:\n", dl->d_name[i]); fprintf(stderr,"%s\n",dl->d_name); } /* // This part might not work 'cuz we'd be changing a memory area that // we might have only read access to. Check this. if (dl->d_name[i] < 0x20) { // Terminate string at any control character dl->d_name[i] = '\0'; } */ } xastir_snprintf(fullpath, sizeof(fullpath), "%s%s", dir, dl->d_name); /*fprintf(stderr,"FULL PATH %s\n",fullpath); */ if (stat (fullpath, &nfile) == 0) { // ftime = (time_t *)&nfile.st_ctime; switch (nfile.st_mode & S_IFMT) { case (S_IFDIR): // It's a directory, skip it break; case (S_IFREG): // It's a file, check it /*fprintf(stderr,"FILE %s\n",dl->d_name); */ // Here we look for a match for the // first 2 characters of the filename. // if (strncasecmp(alert->filename,dl->d_name,2) == 0) { // We have a match for the // first few characters. // Check that last three are // "shp" //fprintf(stderr,"%s\n",fullpath); if ( (dl->d_name[strlen(dl->d_name)-3] == 's' || dl->d_name[strlen(dl->d_name)-3] == 'S') && (dl->d_name[strlen(dl->d_name)-2] == 'h' || dl->d_name[strlen(dl->d_name)-2] == 'H') && (dl->d_name[strlen(dl->d_name)-1] == 'p' || dl->d_name[strlen(dl->d_name)-1] == 'P') ) { // We have an exact match. // Save the filename in the alert memcpy(alert->filename, dl->d_name, sizeof(alert->filename)); // Terminate string alert->filename[sizeof(alert->filename)-1] = '\0'; done++; //fprintf(stderr,"%s\n",dl->d_name); } } break; default: // Not dir or file, skip it break; } } } } (void)closedir (dm); } if (done) // We found a filename match for the alert { // Go draw the weather alert (kind'a) //WE7U mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"map_search: calling draw_map for an alert\n"); } draw_map (w, dir, // Alert directory alert->filename, // Shapefile filename alert, -1, // Signifies "DON'T DRAW THE SHAPE" destination_pixmap, &mdf ); if (debug_level & 16) { fprintf(stderr,"map_search: returned from draw_map\n"); } } else // No filename found that matches the first two { // characters that we already computed. // // Need code here // } } else // Still no filename for the weather alert. { // Output an error message? // // Need code here // } } // MAPS, not alerts else // We're doing regular maps, not weather alerts { time_t map_timestamp; dm = opendir (dir); if (!dm) // Couldn't open directory { xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir); if (warn) { perror (fullpath); } } else { int count = 0; while ((dl = readdir (dm))) { int i; // Check the file/directory name for control // characters for (i = 0; i < (int)strlen(dl->d_name); i++) { // Dump out a warning if control characters // other than LF or CR are found. if ( (dl->d_name[i] != '\n') && (dl->d_name[i] != '\r') && (dl->d_name[i] < 0x20) ) { fprintf(stderr,"\nmap_search: Found control char 0x%02x in map file/map directory name. Line was:\n", dl->d_name[i]); fprintf(stderr,"%s\n",dl->d_name); } /* // This part might not work 'cuz we'd be changing a memory area that // we might have only read access to. Check this. if (dl->d_name[i] < 0x20) { // Terminate string at any control character dl->d_name[i] = '\0'; } */ } xastir_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, dl->d_name); //fprintf(stderr,"FULL PATH %s\n",fullpath); if (stat (fullpath, &nfile) == 0) { // ftime = (time_t *)&nfile.st_ctime; switch (nfile.st_mode & S_IFMT) { case (S_IFDIR): // It's a directory, recurse //fprintf(stderr,"file %c letter %c\n",dl->d_name[0],letter); if ((strcmp (dl->d_name, ".") != 0) && (strcmp (dl->d_name, "..") != 0)) { //fprintf(stderr,"FULL PATH %s\n",fullpath); // If we're indexing, throw the // directory into the map index as // well. if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { char temp_dir[MAX_FILENAME]; // Drop off the base part of the // path for the indexing, // usually // "/usr/local/share/xastir/maps". // Add a '/' to the end. xastir_snprintf(temp_dir, sizeof(temp_dir), "%s/", &fullpath[map_dir_length+1]); // Add the directory to the // in-memory map index. index_update_directory(temp_dir); } // xastir_snprintf(this_time, // sizeof(this_time), // "%s", // ctime(ftime)); map_search(w, fullpath, alert, alert_count, warn, destination_pixmap); } break; case (S_IFREG): // It's a file, draw the map /*fprintf(stderr,"FILE %s\n",dl->d_name); */ // Get the last-modified timestamp for the map file //map_timestamp = (time_t)nfile.st_mtime; map_timestamp = (time_t)( (nfile.st_mtime>nfile.st_ctime) ? nfile.st_mtime : nfile.st_ctime ); // Check whether we're doing indexing or // map drawing. If indexing, we only // want to index if the map timestamp is // newer than the index timestamp. if (destination_pixmap == INDEX_CHECK_TIMESTAMPS || destination_pixmap == INDEX_NO_TIMESTAMPS) { // We're doing indexing, not map drawing char temp_dir[MAX_FILENAME]; // Drop off the base part of the // path for the indexing, usually // "/usr/local/share/xastir/maps". xastir_snprintf(temp_dir, sizeof(temp_dir), "%s", &fullpath[map_dir_length+1]); // Update the "accessed" // variable in the record index_update_accessed(temp_dir); // Note: This is not as efficient as it should be, as we're looking // through the in-memory map index here just to update the // "accessed" variable, then in some cases looking through it again // in the next section for updated maps, or if we're ignoring // timestamps while indexing. Looking through a linear linked list // too many times overall. if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) && (map_timestamp < map_index_timestamp) ) { // Map is older than index _and_ // we're supposed to check // timestamps. count++; break; // Skip indexing this file } else // Map is newer or we're ignoring timestamps. { // We'll index the map if (debug_level & 16) { fprintf(stderr,"Indexing map: %s\n",fullpath); } } } // Check whether the file is in a subdirectory if (strncmp (fullpath, map_dir, (size_t)map_dir_length) != 0) { if (debug_level & 16) { fprintf(stderr,"Calling draw_map\n"); } mdf.draw_filled=1; mdf.usgs_drg=0; draw_map (w, dir, dl->d_name, alert ? &alert[*alert_count] : NULL, '\0', destination_pixmap, &mdf ); if (debug_level & 16) { fprintf(stderr,"Returned from draw_map\n"); } if (alert_count && *alert_count) { (*alert_count)--; } } else { // File is in the main map directory // Find the '/' character for (ptr = &fullpath[map_dir_length]; *ptr == '/'; ptr++) ; mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"Calling draw_map\n"); } draw_map (w, map_dir, ptr, alert ? &alert[*alert_count] : NULL, '\0', destination_pixmap, &mdf ); if (alert_count && *alert_count) { (*alert_count)--; } } count++; break; default: break; } } } if (debug_level & 16) { fprintf(stderr,"Number of maps queried: %d\n", count); } (void)closedir (dm); } } } // List pointer for the map index linked list. map_index_record *map_index_head = NULL; // Might wish to have another variable in the index which is used to // record that a file has been indexed recently. This could be used // to prune old entries out of the index if a full indexing didn't // touch a file entry. Could also delete an entry from the index // if/when a file can't be opened? // Function to dissect and free all of the records in a map index // linked list, leaving it totally empty. // static void free_map_index(map_index_record *index_list_head) { map_index_record *current; map_index_record *temp; current = index_list_head; while (current != NULL) { temp = current; if (current->XmStringPtr != NULL) { XmStringFree(current->XmStringPtr); } current = current->next; free(temp); } index_list_head = NULL; } // Function to copy just the properties fields from the backup map // index to the primary index. Must match each record before // copying. Once it's done, it frees the backup map index. // static void map_index_copy_properties(map_index_record *primary_index_head, map_index_record *backup_index_head) { map_index_record *primary; map_index_record *backup; backup = backup_index_head; // Walk the backup list, comparing the filename field with the // primary list. When a match is found, copy just the // Properties fields (map_layer/draw_filled/auto_maps/selected) // across to the primary record. // while (backup != NULL) { int done = 0; primary = primary_index_head; while (!done && primary != NULL) { if (strcmp(primary->filename, backup->filename) == 0) // If match { if (debug_level & 16) { fprintf(stderr,"Match: %s\t%s\n", primary->filename, backup->filename); } // Copy the Properties across primary->max_zoom = backup->max_zoom; primary->min_zoom = backup->min_zoom; primary->map_layer = backup->map_layer; primary->draw_filled = backup->draw_filled; primary->usgs_drg = backup->usgs_drg; primary->auto_maps = backup->auto_maps; primary->selected = backup->selected; // Done copying this backup record. Go on to the // next. Skip the rest of the primary list for this // iteration. done++; } else // No match, walk the primary list looking for one. { primary = primary->next; } } // Walk the backup list backup = backup->next; } // We're done copying. Free the backup list. free_map_index(backup_index_head); } // Function used to add map directories to the in-memory map index. // Causes an update of the index list in memory. Input Records are // inserted in alphanumerical order. We mark directories in the // index with a '/' on the end of the name, and zero entries for // top/bottom/left/right. // The input directory to this routine MUST have a '/' character on // the end of it. This is how we differentiate directories from // files in the list. static void index_update_directory(char *directory) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; int i; //fprintf(stderr,"index_update_directory: %s\n", directory ); // Check for initial bad input if ( (directory == NULL) || (directory[0] == '\0') || (directory[strlen(directory) - 1] != '/') || ( (directory[1] == '/') && (strlen(directory) == 1)) ) { fprintf(stderr,"index_update_directory: Bad input: %s\n",directory); return; } // Make sure there aren't any weird characters in the directory // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(directory); i++ ) { // Change any control characters to '\0' chars if (directory[i] < 0x20) { fprintf(stderr,"\nindex_update_directory: Found control char 0x%02x in map file/map directory name:\n%s\n", directory[i], directory); directory[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if ( (directory[0] == '\0') || (directory[strlen(directory) - 1] != '/') || ( (directory[1] == '/') && (strlen(directory) == 1))) { fprintf(stderr,"index_update_directory: Bad input: %s\n",directory); return; } //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Search for a matching directory name in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n", // current->filename, directory); test = strcmp(current->filename, directory); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",directory); temp_record = current; done++; // Exit loop, "current" points to found record } else if (test > 0) // Found a string past us in the { // alphabet. Insert ahead of this // last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,directory); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",directory); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else // Insert between "previous" and "current" { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory); // Fill in some default values for the new record. temp_record->selected = 0; temp_record->auto_maps = 0; temp_record->XmStringPtr = NULL; //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, add a record to { // the end of the list. "previous" points to // the last record in the list or NULL (empty // list). //fprintf(stderr,"Not Found: Adding an index record for %s\n",directory); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",directory); } //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory); // Fill in some default values for the new record. temp_record->selected = 0; temp_record->auto_maps = 0; temp_record->XmStringPtr = NULL; } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",directory); temp_record->bottom = 0; temp_record->top = 0; temp_record->left = 0; temp_record->right = 0; temp_record->accessed = 1; temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = 0; temp_record->draw_filled = 0; temp_record->usgs_drg = 2; } // Function called by the various draw_* functions when in indexing // mode. Causes an update of the index list in memory. Input // parameters are in the Xastir coordinate system due to speed // considerations. Records are inserted in alphanumerical order. void index_update_xastir(char *filename, unsigned long bottom, unsigned long top, unsigned long left, unsigned long right, int default_map_layer) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') || (filename[strlen(filename) - 1] == '/') ) { fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_xastir: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename); return; } //fprintf(stderr,"index_update_xastir: (%lu,%lu)\t(%lu,%lu)\t%s\n", // bottom, top, left, right, filename ); //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",filename); temp_record = current; done++; // Exit the while loop } else if (test > 0) // Found a string past us in the { // alphabet. Insert ahead of this // last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,filename); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, add a { // record to the end of the list //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); temp_record->bottom = bottom; temp_record->top = top; temp_record->left = left; temp_record->right = right; temp_record->accessed = 1; } // Function called by the various draw_* functions when in indexing // mode. Causes an update of the index list in memory. Input // parameters are in lat/long, which are converted to Xastir // coordinates for storage due to speed considerations. Records are // inserted in alphanumerical order. void index_update_ll(char *filename, double bottom, double top, double left, double right, int default_map_layer) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; unsigned long temp_left, temp_right, temp_top, temp_bottom; int ok; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') || (filename[strlen(filename) - 1] == '/') ) { fprintf(stderr,"index_update_ll: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_ll: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_ll: Bad input: %s\n",filename); return; } //fprintf(stderr,"index_update_ll: (%15.10g,%15.10g)\t(%15.10g,%15.10g)\t%s\n", // bottom, top, left, right, filename ); //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",filename); temp_record = current; done++; // Exit the while loop } else if (test > 0) { // Found a string past us in the alphabet. Insert ahead // of this last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,filename); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, didn't find alpha { // chars after our string either, add record to // the end of the list. //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. // In this case the struct uses MAX_FILENAME for the length of // the field, so the below statement is ok. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); ok = convert_to_xastir_coordinates( &temp_left, &temp_top, (float)left, (float)top); if (!ok) { fprintf(stderr,"%s\n\n",filename); } ok = convert_to_xastir_coordinates( &temp_right, &temp_bottom, (float)right, (float)bottom); if (!ok) { fprintf(stderr,"%s\n\n",filename); } temp_record->bottom = temp_bottom; temp_record->top = temp_top; temp_record->left = temp_left; temp_record->right = temp_right; temp_record->accessed = 1; } // Function which will update the "accessed" variable on either a // directory or a filename in the map index. static void index_update_accessed(char *filename) { map_index_record *current = map_index_head; int done = 0; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') ) { fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_accessed: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename); return; } // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n\n",filename); current->accessed = 1; done++; // Exit the while loop } else // Haven't gotten to the correct insertion point yet { current = current->next; } } } // Function called by map_onscreen_index() // // This function returns: // 0 if the map isn't in the index // 1 if the map is listed in the index // Four parameters listing the extents of the map // // The updated parameters are in the Xastir coordinate system for // speed reasons. // // Note that the index retrieval could be made much faster by // storing the data in a hash instead of a linked list. This is // just an initial implementation to see what speedups are possible. // Hashing might be next. --we7u // // Note that since we've alphanumerically ordered the list, we can // stop when we hit something after this filename in the alphabet. // It speeds things up quite a bit. // // In order to speed this up slightly for the general case, we'll // assume that we'll be fetching indexes in alphabetical order, as // that's how we store them everywhere. We'll save the last map // index pointer away and start searching there each time. That // should make all but the _first_ lookup much faster. // map_index_record *last_index_lookup = NULL; int index_retrieve(char *filename, unsigned long *bottom, unsigned long *top, unsigned long *left, unsigned long *right, int *max_zoom, int *min_zoom, int *map_layer, int *draw_filled, int *usgs_drg, int *auto_maps) { map_index_record *current; int status = 0; if ( (filename == NULL) || (strlen(filename) >= MAX_FILENAME) ) { return(status); } // Attempt to start where we left off last time if (last_index_lookup != NULL) { current = last_index_lookup; } else { current = map_index_head; //fprintf(stderr,"Start at beginning:%s\t", filename); } // Check to see if we're past the correct area. If so, start at // the beginning of the index instead. // if (current && ((current->filename[0] > filename[0]) || (strcmp(current->filename, filename) > 0))) { // // We're past the correct point. Start at the beginning of // the list unless we're already there. // if (current != map_index_head) { current = map_index_head; } //fprintf(stderr,"Start at beginning:%s\t", filename); } // // Search for a matching filename in the linked list. // // Check the first char only. Loop until they match or go past. // This is our high-speed method to get to the correct search // area. // while (current && (current->filename[0] < filename[0])) { // Save the pointer away for next time. There's a reason we // save it before we increment the counter: For "z" weather // alerts, it's nice to have it scan just the very last of // the list before it fails, instead of scanning the entire // list each time and then failing. Need to find out why // weather alerts always fail, and therefore why this // routine gets called every time for them. // last_index_lookup = current; current = current->next; //fprintf(stderr,"1"); } // Stay in this loop while the first char matches. This is our // active search area. // while (current && (current->filename[0] == filename[0])) { int result; // Check the entire string result = strcmp(current->filename, filename); if (result == 0) { // Found a match! status = 1; *bottom = current->bottom; *top = current->top; *left = current->left; *right = current->right; *max_zoom = current->max_zoom; *min_zoom = current->min_zoom; *map_layer = current->map_layer; *draw_filled = current->draw_filled; *usgs_drg = current->usgs_drg; *auto_maps = current->auto_maps; //fprintf(stderr," Found it\n"); return(status); } else if (result > 0) { // We're past it in the index. We didn't find it in the // index. //fprintf(stderr," Did not find1\n"); return(status); } else // Not found yet, look at the next { // Save the pointer away for next time. There's a // reason we save it before we increment the counter: // For "z" weather alerts, it's nice to have it scan // just the very last of the list before it fails, // instead of scanning the entire list each time and // then failing. Need to find out why weather alerts // always fail, and therefore why this routine gets // called every time for them. // last_index_lookup = current; current = current->next; //fprintf(stderr,"2"); } } // We're past the correct search area and didn't find it. //fprintf(stderr," Did not find2\n"); return(status); } // Saves the linked list pointed to by map_index_head to a file. // Keeps the same order as the memory linked list. Delete records // in the in-memory linked list for which the "accessed" variable is // 0 or filename is empty. // void index_save_to_file(void) { FILE *f; map_index_record *current; // map_index_record *last; char out_string[MAX_FILENAME*2]; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); //fprintf(stderr,"Saving map index to file\n"); f = fopen( map_index_path, "w" ); if (f == NULL) { fprintf(stderr,"Couldn't create/update map index file: %s\n", map_index_path ); return; } current = map_index_head; // last = current; while (current != NULL) { int i; // Make sure there aren't any weird characters in the // filename that might cause problems later. Look for // control characters and convert them to string-end // characters. for ( i = 0; i < (int)strlen(current->filename); i++ ) { // Change any control characters to '\0' chars if (current->filename[i] < 0x20) { fprintf(stderr,"\nindex_save_to_file: Found control char 0x%02x in map name:\n%s\n", current->filename[i], current->filename); current->filename[i] = '\0'; // Terminate it here } } // Save to file if filename non-blank and record has the // accessed field set. if ( (current->filename[0] != '\0') && (current->accessed != 0) ) { // Write each object out to the file as one // comma-delimited line xastir_snprintf(out_string, sizeof(out_string), "%010lu,%010lu,%010lu,%010lu,%05d,%01d,%01d,%01d,%05d,%05d,%s\n", current->bottom, current->top, current->left, current->right, current->map_layer, current->draw_filled, current->usgs_drg, current->auto_maps, current->max_zoom, current->min_zoom, current->filename); if (fprintf(f,"%s",out_string) < (int)strlen(out_string)) { // Failed to write fprintf(stderr,"Couldn't write objects to map index file: %s\n", map_index_path ); current = NULL; // All done } // Set up pointers for next loop iteration // last = current; if (current != NULL) { current = current->next; } } else { // last = current; current = current->next; } /* //WE7U else { // Delete this record from our list! It's a record // for a map file that doesn't exist in the // filesystem anymore. if (last == current) { // We're at the head of the list map_index_head = current->next; // Remember to free the XmStringPtr if we use this bit of code // again. free(current); // Set up pointers for next loop iteration current = map_index_head; last = current; } else { // Not the first record in the list map_index_record *gone; gone = current; // Save ptr to record we wish to delete last->next = current->next; // Unlink from list // Remember to free the XmStringPtr if we use this bit of code // again. free(gone); // Set up pointers for next loop iteration // "last" is still ok current = last->next; } } */ } (void)fclose(f); } // This function is currently not used. // // Function used to add map directories/files to the in-memory map // index. Causes an update of the index list in memory. Input // records are inserted in alphanumerical order. This function is // called from the index_restore_from_file() function below. When // this function is called the new record has all of the needed // information in it. // /* static void index_insert_sorted(map_index_record *new_record) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; int done = 0; int i; //fprintf(stderr,"index_insert_sorted: %s\n", new_record->filename ); // Check for bad input. if (new_record == NULL) { fprintf(stderr,"index_insert_sorted: Bad input.\n"); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for any control // characters and convert them to string-end characters. for ( i = 0; i < (int)strlen(new_record->filename); i++ ) { if (new_record->filename[i] < 0x20) { fprintf(stderr,"\nindex_insert_sorted: Found control char 0x%02x in map name:\n%s\n", new_record->filename[i], new_record->filename); new_record->filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (new_record->filename[0] == '\0') { fprintf(stderr,"index_insert_sorted: Bad input.\n"); return; } //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n", // current->filename, new_record->filename); test = strcmp(current->filename, new_record->filename); if (test == 0) { // Found a match! int selected; //fprintf(stderr,"Found a match: Updating entry for %s\n",new_record->filename); // Save this away temporarily. selected = current->selected; // Copy the fields across and then free new_record. We // overwrite the contents of the existing record. xastir_snprintf(current->filename, MAX_FILENAME, "%s", new_record->filename); current->bottom = new_record->bottom; current->top = new_record->top; current->left = new_record->left; current->right = new_record->right; current->accessed = 1; current->max_zoom = new_record->max_zoom; current->min_zoom = new_record->min_zoom; current->map_layer = new_record->map_layer; current->draw_filled = new_record->draw_filled; current->usgs_drg = new_record->usgs_drg; current->selected = selected; // Restore it current->auto_maps = new_record->auto_maps; // Remember to free the XmStringPtr if we use this bit of code // again. free(new_record); // Don't need it anymore done++; // Exit loop, "current" points to found record } else if (test > 0) { // Found a string past us in the // alphabet. Insert ahead of this // last record. //fprintf(stderr,"Not Found, inserting: %s\n", new_record->filename); //fprintf(stderr," Before record: %s\n", current->filename); if (current == map_index_head) { // Start of list! // Insert new record at head of list new_record->next = map_index_head; map_index_head = new_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert between "previous" and "current" // Insert new record before "current" previous->next = new_record; new_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record that // don't exist in the map_index.sys file. new_record->selected = 0; if ( strstr(new_record->filename,".geo") || strstr(new_record->filename,".GEO") || strstr(new_record->filename,".Geo") ) { new_record->auto_maps = 0; } else { new_record->auto_maps = 1; } //current = current->next; done++; } else { // Haven't gotten to the correct insertion point yet previous = current; // Save ptr to last record current = current->next; } } if (!done) { // Matching record not found, add the record to // the end of the list. "previous" points to the last // record in the list or NULL (empty list). //fprintf(stderr,"Not Found: Adding to end: %s\n",new_record->filename); new_record->next = NULL; if (previous == NULL) { // Empty list map_index_head = new_record; //fprintf(stderr,"First record in new list\n"); } else { // Else at end of list previous->next = new_record; //fprintf(stderr,"Adding to end of list: %s\n",new_record->filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(new_record->filename),new_record->filename); // Fill in some default values for the new record. new_record->selected = 0; if ( strstr(new_record->filename,".geo") || strstr(new_record->filename,".GEO") || strstr(new_record->filename,".Geo") ) { new_record->auto_maps = 0; } else { new_record->auto_maps = 1; } } } */ // sort map index // simple bubble sort, since we should be sorted already // static void index_sort(void) { map_index_record *current, *previous, *next; int changed = 1; int loops = 0; // for debug stats previous = map_index_head; next = NULL; // fprintf(stderr, "index_sort: start.\n"); // check if we have any records at all, and at least two if ( (previous != NULL) && (previous->next != NULL) ) { current = previous->next; while ( changed == 1) { changed = 0; if (current->next != NULL) { next = current->next; } if ( strcmp( previous->filename, current->filename) >= 0 ) { // out of order - swap them current->next = previous; previous->next = next; map_index_head = current; current = previous; previous = map_index_head; changed = 1; } while ( next != NULL ) { if ( strcmp( current->filename, next->filename) >= 0 ) { // out of order - swap them current->next = next->next; previous->next = next; next->next = current; // get ready for the next iteration previous = next; // current already moved ahead from the swap next = current->next; changed = 1; } else { previous = current; current = next; next = current->next; } } previous = map_index_head; current = previous->next; next = current->next; loops++; } } // debug stats // fprintf(stderr, "index_sort: ran %d loops.\n", loops); } // Snags the file and creates the linked list pointed to by the // map_index_head pointer. The memory linked list keeps the same // order as the entries in the file. // // NOTE: If we're converting from the old format to the new, we // need to call index_save_to_file() in order to write out the new // format once we're done. // void index_restore_from_file(void) { FILE *f; map_index_record *temp_record; map_index_record *last_record; char in_string[MAX_FILENAME*2]; int doing_migration = 0; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); //fprintf(stderr,"\nRestoring map index from file\n"); if (map_index_head != NULL) { fprintf(stderr,"Warning: index_restore_from_file(): map_index_head was non-null!\n"); } map_index_head = NULL; // Starting with empty list last_record = NULL; f = fopen( map_index_path, "r" ); if (f == NULL) // No map_index file yet { return; } while (!feof (f)) // Loop through entire map_index file { // Read one line from the file if ( get_line (f, in_string, MAX_FILENAME*2) ) { if (strlen(in_string) >= 15) // We have some data. { // Try to process the // line. char scanf_format[50]; char old_scanf_format[50]; char older_scanf_format[50]; int processed; int i, jj; //fprintf(stderr,"%s\n",in_string); // Tweaked the string below so that it will track // along with MAX_FILENAME-1. We're constructing // the string "%lu,%lu,%lu,%lu,%d,%d,%2000c", where // the 2000 example number is from MAX_FILENAME. xastir_snprintf(scanf_format, sizeof(scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%d,%", MAX_FILENAME, "c"); //fprintf(stderr,"%s\n",scanf_format); // index predates addition of usgs_drg flag (26 Jul 2005) xastir_snprintf(old_scanf_format, sizeof(old_scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%", MAX_FILENAME, "c"); // index predates addition of min/max zoom (29 Oct 2003) xastir_snprintf(older_scanf_format, sizeof(older_scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%", MAX_FILENAME, "c"); // Malloc an index record. We'll add it to the list // only if the data looks reasonable. temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); memset(temp_record->filename, 0, sizeof(temp_record->filename)); temp_record->next = NULL; temp_record->bottom = 64800001l;// Too high temp_record->top = 64800001l; // Too high temp_record->left = 129600001l; // Too high temp_record->right = 129600001l;// Too high temp_record->map_layer = -1; // Too low temp_record->draw_filled = -1; // Too low temp_record->usgs_drg = -1; // Too low temp_record->auto_maps = -1; // Too low temp_record->max_zoom = -1; // Too low temp_record->min_zoom = -1; // Too low temp_record->filename[0] = '\0';// Empty processed = sscanf(in_string, scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->usgs_drg, &temp_record->auto_maps, &temp_record->max_zoom, &temp_record->min_zoom, temp_record->filename); if (processed < 11) { // We're upgrading from an old format index file // that doesn't have usgs_drg. Try the // old_scanf_format string instead. doing_migration = 1; processed = sscanf(in_string, old_scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->auto_maps, &temp_record->max_zoom, &temp_record->min_zoom, temp_record->filename); if (processed < 10) { // It's really old, doesn't have min/max zoom either temp_record->max_zoom = -1; // Too low temp_record->min_zoom = -1; // Too low processed = sscanf(in_string, older_scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->auto_maps, temp_record->filename); } // either way, it doesn't have usgs_drg, so add one // defaulting to Auto if it's a tif file, no if not if ( strstr(temp_record->filename,".tif") || strstr(temp_record->filename,".TIF") || strstr(temp_record->filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } temp_record->XmStringPtr = NULL; // Do some reasonableness checking on the parameters // we just parsed. //WE7U: First comparison here is always false // if ( (temp_record->bottom < 0l) // || (temp_record->bottom > 64800000l) ) { if (temp_record->bottom > 64800000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: bottom extent incorrect %lu in map name:\n%s\n", temp_record->bottom, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->top < 0l) // || (temp_record->top > 64800000l) ) { if (temp_record->top > 64800000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: top extent incorrect %lu in map name:\n%s\n", temp_record->top, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->left < 0l) // || (temp_record->left > 129600000l) ) { if (temp_record->left > 129600000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: left extent incorrect %lu in map name:\n%s\n", temp_record->left, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->right < 0l) // || (temp_record->right > 129600000l) ) { if (temp_record->right > 129600000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: right extent incorrect %lu in map name:\n%s\n", temp_record->right, temp_record->filename); } if ( (temp_record->max_zoom < 0) || (temp_record->max_zoom > 99999) ) { // processed = 0; // Reject this record // fprintf(stderr,"\nindex_restore_from_file: max_zoom field incorrect %d in map name:\n%s\n", // temp_record->max_zoom, // temp_record->filename); // Assign a reasonable value temp_record->max_zoom = 0; //fprintf(stderr,"Assigning max_zoom of 0\n"); } if ( (temp_record->min_zoom < 0) || (temp_record->min_zoom > 99999) ) { // processed = 0; // Reject this record // fprintf(stderr,"\nindex_restore_from_file: min_zoom field incorrect %d in map name:\n%s\n", // temp_record->min_zoom, // temp_record->filename); // Assign a reasonable value temp_record->min_zoom = 0; //fprintf(stderr,"Assigning min_zoom of 0\n"); } if ( (temp_record->map_layer < -99999) || (temp_record->map_layer > 99999) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: map_layer field incorrect %d in map name:\n%s\n", temp_record->map_layer, temp_record->filename); } if ( (temp_record->draw_filled < 0) || (temp_record->draw_filled > 2) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: draw_filled field incorrect %d in map name:\n%s\n", temp_record->draw_filled, temp_record->filename); } if ( (temp_record->usgs_drg < 0) || (temp_record->usgs_drg > 2) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: usgs_drg field incorrect %d in map name:\n%s\n", temp_record->usgs_drg, temp_record->filename); } if ( (temp_record->auto_maps < 0) || (temp_record->auto_maps > 1) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: auto_maps field incorrect %d in map name:\n%s\n", temp_record->auto_maps, temp_record->filename); } // Check whether the filename is empty if (strlen(temp_record->filename) == 0) { processed = 0; // Reject this record } // Check for control characters in the filename. // Reject any that have them. jj = (int)strlen(temp_record->filename); for (i = 0; i < jj; i++) { if (temp_record->filename[i] < 0x20) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: Found control char 0x%02x in map name:\n%s\n", temp_record->filename[i], temp_record->filename); } } // Mark the record as accessed at this point. // At the stage where we're writing this list off to // disk, if the record hasn't been accessed by the // re-indexing, it doesn't get written. This has // the effect of flushes deleted files from the // index quickly. temp_record->accessed = 1; // Default is not-selected. Later we read in the // selected_maps.sys file and tweak some of these // fields. temp_record->selected = 0; temp_record->filename[MAX_FILENAME-1] = '\0'; // If correct number of parameters for either old or // new format if (processed == 11 || processed == 10 || processed == 8) { //fprintf(stderr,"Restored: %s\n",temp_record->filename); // Insert the new record into the in-memory map // list in sorted order. // --slow for large lists // index_insert_sorted(temp_record); // -- so we just add it to the end of the list // and sort it at the end tp make sure nobody // messed us up by editting the file by hand if ( last_record == NULL ) // first record { map_index_head = temp_record; } else { last_record->next = temp_record; } last_record = temp_record; // Remember that we may just have attached the // record to our in-memory map list, or we may // have free'ed it in the above function call. // Set the pointer to NULL to make sure we don't // try to do anything else with the memory. temp_record = NULL; } else // sscanf didn't parse the proper number of { // items. Delete the record. // Remember to free the XmString pointer if necessary. free(temp_record); // fprintf(stderr,"index_restore_from_file:sscanf parsing error\n"); } } } } (void)fclose(f); // now that we have read the whole file, make sure it is sorted index_sort(); // probably should check for dup records if (doing_migration) { // Save in new file format if we just did a migration from // old format to new. fprintf(stderr,"Migrating from old map_index.sys format to new format.\n"); index_save_to_file(); } } // map_indexer() // // Recurses through the map directories finding map extents // and recording them in the map index. Once the indexing is // complete, write the current index out to a file. // // It'd be nice to call index_restore_from_file() from main.c:main() // so that an earlier copy of the index is restored before the map // display is created. // // If we set the "accessed" variable in the in-memory index to 0 for // each record and then run the indexer, the save-to-file function // will delete those with a value of 0 when writing to disk. Those // maps no longer exist in the filesystem and should be deleted. We // could either wipe them from the in-memory database at that time // as well, or wipe the whole list and re-read it from disk to get // the current list. // // If parameter is 0, we'll do the smart timestamp-checking // indexing. // If 1, we'll erase the in-memory index and do full indexing. // void map_indexer(int parameter) { struct stat nfile; int check_times = 1; FILE *f; map_index_record *current; map_index_record *backup_list_head = NULL; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); if (debug_level & 16) { fprintf(stderr,"map_indexer() start\n"); } fprintf(stderr,"Indexing maps...\n"); #ifdef HAVE_LIBSHP // get rid of stored dbfawk signatures and force reload. clear_dbfawk_sigs(); #endif // Find the timestamp on the index file first. Save it away so // that the timestamp for each map file can be compared to it. if (stat ( map_index_path, &nfile) != 0) { // File doesn't exist yet. Create it. f = fopen( map_index_path, "w" ); if (f != NULL) { (void)fclose(f); } else fprintf(stderr,"Couldn't create map index file: %s\n", map_index_path ); check_times = 0; // Don't check the timestamps. Do them all. } else // File exists { map_index_timestamp = (time_t)nfile.st_mtime; check_times = 1; } if (parameter == 1) // Full indexing instead of timestamp-check indexing { // Move the in-memory index to a backup pointer backup_list_head = map_index_head; map_index_head = NULL; // // Set the timestamp to 0 so that everything gets indexed // map_index_timestamp = (time_t)0l; check_times = 0; } // Set the "accessed" field to zero for every record in the // index. Note that the list could be empty at this point. current = map_index_head; while (current != NULL) { current->accessed = 0; current = current->next; } if (check_times) { if (debug_level & 16) { fprintf(stderr,"map_indexer: Calling map_search\n"); } map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_CHECK_TIMESTAMPS); if (debug_level & 16) { fprintf(stderr,"map_indexer: Returned from map_search\n"); } } else { if (debug_level & 16) { fprintf(stderr,"map_indexer: Calling map_search\n"); } map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_NO_TIMESTAMPS); if (debug_level & 16) { fprintf(stderr,"map_indexer: Returned from map_search\n"); } } if (debug_level & 16) { fprintf(stderr,"map_indexer() middle\n"); } if (parameter == 1) // Full indexing instead of timestamp-check indexing { // Copy the Properties from the backup list to the new list, // then free the backup list. map_index_copy_properties(map_index_head, backup_list_head); } // Save the updated index to the file index_save_to_file(); fprintf(stderr,"Finished indexing maps\n"); if (debug_level & 16) { fprintf(stderr,"map_indexer() end\n"); } } /* moved these here and made them static so it will function on FREEBSD */ #define MAX_ALERT 7000 // If we comment this out, we link, but get a segfault at runtime. // Take out the "static" and we get a segfault when we zoom out too // far with the lakes or counties shapefile loaded. No idea why // yet. --we7u //static alert_entry alert[MAX_ALERT]; static int alert_count; /******************************************************************* * fill_in_new_alert_entries() * * Fills in the index and filename portions of any alert entries * that are missing them. This function should be called at the * point where we've just received a new weather alert. * //WE7U // Later we should change this so that it doesn't scan the entire // message list, but is passed the important info directly from the // decode routines in db.c, and the message should NOT be added to // the message list. //WE7U * * This function is designed to use ESRI Shapefile map files. The * base directory where the Shapefiles are located is passed to us * in the "dir" variable. * * map_search() fills in the filename field of the alert struct. * draw_shapefile_map() fills in the index field. *******************************************************************/ void fill_in_new_alert_entries() { // int ii; char alert_scan[MAX_FILENAME]; // char *dir_ptr; struct hashtable_itr *iterator = NULL; alert_entry *temp; char dir[MAX_FILENAME]; if (debug_level & 2) { fprintf(stderr,"fill_in_new_alert_entries start\n"); } xastir_snprintf(dir, sizeof(dir), "%s", ALERT_MAP_DIR); alert_count = MAX_ALERT - 1; // Set up our path to the wx alert maps memset(alert_scan, 0, sizeof (alert_scan)); // Zero our alert_scan string xastir_snprintf(alert_scan, // Fetch the base directory sizeof(alert_scan), "%s", dir); strncat(alert_scan, // Complete alert directory is now set up in the string "/", sizeof(alert_scan) - 1 - strlen(alert_scan)); // dir_ptr = &alert_scan[strlen (alert_scan)]; // Point to end of path // Iterate through the weather alerts. It looks like we wish to // just fill in the alert struct and to determine whether the // alert is within our viewport here. We don't wish to draw the // alerts at this stage, that happens in the load_alert_maps() // function below. iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { if (!temp->filename[0]) // Filename is { // empty, we need to fill it in. // fprintf(stderr,"fill_in_new_alert_entries() Title: %s\n",temp->title); // The last parameter denotes loading into // pixmap_alerts instead of pixmap or pixmap_final. // Note that just calling map_search does not get // the alert areas drawn on the screen. The // draw_map() function called by map_search just // fills in the filename field in the struct and // exits. // // The "warn" parameter (next to last) specifies whether // to dump warnings out to the console as well. If the // warning was received on local RF or locally, warn the // operator (the weather must be near). map_search (da, alert_scan, temp, &alert_count, (int)temp->flags[source], DRAW_TO_PIXMAP_ALERTS); // fprintf(stderr,"fill_in_new_alert_entries() Title1:%s\n",temp->title); } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 4\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC if (debug_level & 2) { fprintf(stderr,"fill_in_new_alert_entries end\n"); } } /******************************************************************* * load_alert_maps() * * Used to load weather alert maps, based on NWS weather alerts that * are received. Called from create_image() and refresh_image(). * This function is designed to use ESRI Shapefile map files. The * base directory where the Shapefiles are located is passed to us * in the "dir" variable. * * map_search() fills in the filename field of the alert struct. * draw_shapefile_map() fills in the index field. *******************************************************************/ void load_alert_maps (Widget w, char *dir) { // int ii; int level; unsigned char fill_color[] = { (unsigned char)0x69, // gray86 (unsigned char)0x4a, // red2 (unsigned char)0x63, // yellow2 (unsigned char)0x66, // cyan2 (unsigned char)0x61, // RoyalBlue (unsigned char)0x64, // ForestGreen (unsigned char)0x62 }; // orange3 struct hashtable_itr *iterator = NULL; alert_entry *temp; map_draw_flags mdf; //fprintf(stderr,"load_alert_maps\n"); // TODO: // Figure out how to pass a quantity of zones off to the map drawing // routines, then we can draw them all with one pass through each // map file. Alphanumerically sort the zones to make it easier for // the map drawing functions? Note that the indexing routines fill // in both the filename and the shapefile index for each record. // // Alternative: Call map_draw for each filename listed and have the // draw_shapefile function iterate through the array looking for all // filename matches, pulling non-negative indexes out of each index // field for matches and drawing them. That should be fast and // require no sorting of the array. Downside: The alerts won't be // layered based on alert level unless we modify the above: Drawing // each file once for each alert-level in the proper layering order. // Perhaps we could keep a list of which filenames have been called, // and only call each one once per load_alert_maps() call. // Just for a test //draw_shapefile_map (w, dir, filenm, alert, alert_color, destination_pixmap); //draw_shapefile_map (w, dir, "c_16my01.shp", NULL, '\0', DRAW_TO_PIXMAP_ALERTS); // Are we drawing them in reverse order so that the important // alerts end up drawn on top of the less important alerts? // Actually, since the alert hash isn't ordered, perhaps we need to // order them by priority, then by map file, so that we can draw the // shapes from each map file in the correct order. This might cause // each map file to be drawn up to three times (once for each // priority level), but that's better than calling each map for each // zone as is done now. iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 5\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } if (disable_all_maps) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 6\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } // Check whether the alert slot is filled/empty if (temp->title[0] == '\0') // Empty slot { temp = get_next_wx_alert(iterator); continue; } if ( (level = alert_active(temp, ALERT_ALL) ) ) { if (level >= (int)sizeof (fill_color)) { level = 0; } // The last parameter denotes drawing into pixmap_alert // instead of pixmap or pixmap_final. if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Drawing %s\n",temp->filename); fprintf(stderr,"load_alert_maps() Title4:%s\n",temp->title); } // Attempt to draw alert if ( temp->index != -1 ) // Shape found in shapefile { // Check whether we've ever tried to draw this alert // before. If not, attempt it and get the boundary // limits filled in. // if ( temp->bottom_boundary == 0.0 && temp->top_boundary == 0.0 && temp->left_boundary == 0.0 && temp->right_boundary == 0.0) { if (temp->alert_level != 'C') { draw_map (w, dir, temp->filename, temp, fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf); // draw filled } } if (map_visible_lat_lon(temp->bottom_boundary, // Shape visible temp->top_boundary, temp->left_boundary, temp->right_boundary) ) { if (temp->alert_level != 'C') // Alert not cancelled { mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"load_alert_maps: Calling draw_map\n"); } draw_map (w, dir, temp->filename, temp, fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf); // draw filled } if (temp) { temp->flags[on_screen] = 'Y'; } } else { // Not in our viewport, don't draw it! if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Alert not visible\n"); } //fprintf(stderr,"B:%f T:%f L:%f R:%f\n", temp->bottom_boundary, temp->top_boundary, temp->left_boundary, temp->right_boundary); if (temp) { temp->flags[on_screen] = 'N'; } } } else { // Can't find this shape in the shapefile. if (debug_level & 16) { fprintf(stderr, "load_alert_maps() Shape %s, strlen=%d, not found in %s\n", temp->title, (int)strlen(temp->title), temp->filename ); } } } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 7\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Done drawing all active alerts\n"); } if (alert_display_request()) { alert_redraw_on_update = redraw_on_new_data = 2; } } // Here's the head of our sorted-by-layer maps list static map_index_record *map_sorted_list_head = NULL; static void empty_map_sorted_list(void) { map_index_record *current = map_sorted_list_head; while (map_sorted_list_head != NULL) { current = map_sorted_list_head; map_sorted_list_head = current->next; if (current->XmStringPtr != NULL) { XmStringFree(current->XmStringPtr); } free(current); } } // Insert a map into the list at the end of the maps with the same // layer number. We'll need to look up the parameters for it from // the master map_index list and then attach a new record to our new // sorted list in the proper place. // // This function should be called when we're first starting up // Xastir and anytime that selected_maps.sys is changed. // static void insert_map_sorted(char *filename) { map_index_record *current; map_index_record *last; map_index_record *temp_record; unsigned long bottom; unsigned long top; unsigned long left; unsigned long right; int max_zoom; int min_zoom; int map_layer; int draw_filled; int usgs_drg; int auto_maps; int done; if (index_retrieve(filename, &bottom, &top, &left, &right, &max_zoom, &min_zoom, &map_layer, &draw_filled, &usgs_drg, &auto_maps)) // Found a match { // Allocate a new record temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); // Fill in the values xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); temp_record->bottom = bottom; temp_record->top = top; temp_record->left = left; temp_record->right = right; temp_record->max_zoom = max_zoom; temp_record->min_zoom = min_zoom; temp_record->map_layer = map_layer; temp_record->draw_filled = draw_filled; temp_record->usgs_drg = usgs_drg; temp_record->auto_maps = auto_maps; temp_record->selected = 1; // Always, we already know this! temp_record->accessed = 0; temp_record->next = NULL; temp_record->XmStringPtr = NULL; // Now find the proper place for it and insert it in // layer-order into the list. current = map_sorted_list_head; last = map_sorted_list_head; done = 0; // Possible cases: // Empty list // insert at beginning of list // insert at end of list // insert between other entries if (map_sorted_list_head == NULL) { // Empty list. Insert record. map_sorted_list_head = temp_record; done++; } else if (map_layer < current->map_layer) { // Insert at beginning of list temp_record->next = current; map_sorted_list_head = temp_record; done++; } else // Need to insert between records or at end of list { while (!done && (current != NULL) ) { if (map_layer >= current->map_layer) // Not to our layer yet { last = current; current = current->next; // May point to NULL now } else if (map_layer < current->map_layer) { temp_record->next = current; last->next = temp_record; done++; } } } // Handle running off the end of the list if (!done && (current == NULL) ) { last->next = temp_record; } } else { // We failed to find it in the map index } } /********************************************************** * load_auto_maps() * * NEW: Uses the in-memory map_index to scan through the * maps. * * OLD: Recurses through the map directories looking for * maps to load. **********************************************************/ void load_auto_maps (Widget w, char * UNUSED(dir) ) { map_index_record *current = map_index_head; map_draw_flags mdf; HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // Skip the sorting of the maps if we don't need to do it if (re_sort_maps) { //fprintf(stderr,"*** Sorting the selected maps by layer...\n"); // Empty the sorted list first. We'll create a new one. empty_map_sorted_list(); // Run through the entire map_index linked list while (current != NULL) { if (auto_maps_skip_raster && ( strstr(current->filename,".geo") || strstr(current->filename,".GEO") || strstr(current->filename,".Geo") || strstr(current->filename,".tif") || strstr(current->filename,".TIF") || strstr(current->filename,".Tif"))) { // Skip this map } else // Draw this map { //fprintf(stderr,"Loading: %s/%s\n",SELECTED_MAP_DIR,current->filename); //WE7U insert_map_sorted(current->filename); /* draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP); */ } current = current->next; } // All done sorting until something is changed in the Map // Chooser. re_sort_maps = 0; //fprintf(stderr,"*** DONE sorting the selected maps.\n"); } // We have the maps in sorted order. Run through the list and // draw them. Only include those that have the auto_maps field // set to 1. current = map_sorted_list_head; while (current != NULL) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (disable_all_maps) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Debug // fprintf(stderr,"Drawing level:%05d, file:%s\n", // current->map_layer, // current->filename); // Draw the maps in sorted-by-layer order if (current->auto_maps) { mdf.draw_filled = current->draw_filled; mdf.usgs_drg = current->usgs_drg; if (debug_level & 16) { fprintf(stderr,"load_auto_maps: Calling draw_map\n"); } draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP, &mdf); } current = current->next; } } /******************************************************************* * load_maps() * * Loads maps, draws grid, updates the display. * * We now create a linked list of maps in layer-order and use this * list to draw the maps. This preserves the correct ordering in * all cases. The layer to draw each map is specified in the * map_index.sys file (fifth parameter). Eventually code will be * added to the Map Chooser in order to change the layer each map is * drawn at. *******************************************************************/ void load_maps (Widget w) { FILE *f; char mapname[MAX_FILENAME]; int i; char selected_dir[MAX_FILENAME]; map_index_record *current; map_draw_flags mdf; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // int dummy; if (debug_level & 16) { fprintf(stderr,"Load maps start\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Skip the sorting of the maps if we don't need to do it if (re_sort_maps) { //fprintf(stderr,"*** Sorting the selected maps by layer...\n"); // Empty the sorted list first. We'll create a new one. empty_map_sorted_list(); // Make sure the string is empty before we start selected_dir[0] = '\0'; // Create empty file if it doesn't exist (void)filecreate( selected_map_path ); f = fopen ( selected_map_path, "r" ); if (f != NULL) { if (debug_level & 16) { fprintf(stderr,"Load maps Open map file\n"); } while (!feof (f)) { // Grab one line from the file if ( fgets( mapname, MAX_FILENAME-1, f ) != NULL ) { // Forced termination (just in case) mapname[MAX_FILENAME-1] = '\0'; // Get rid of the newline at the end for (i = strlen(mapname); i > 0; i--) { if (mapname[i] == '\n') { mapname[i] = '\0'; } } if (debug_level & 16) { fprintf(stderr,"Found mapname: %s\n", mapname); } // Test for comment if (mapname[0] != '#') { // Check whether it's a directory that was // selected. If so, save it in a special // variable and use that to match all the files // inside the directory. Note that with the way // we have things ordered in the list, the // directories appear before their member files. if (mapname[strlen(mapname)-1] == '/') { int len; // Found a directory. Save the name. xastir_snprintf(selected_dir, sizeof(selected_dir), "%s", mapname); len = strlen(mapname); //fprintf(stderr,"Selected %s directory\n",selected_dir); // Here we need to run through the map_index // list to find all maps that match the // currently selected directory. Attempt to // load all of those maps as well. //fprintf(stderr,"Load all maps under this directory: %s\n",selected_dir); // Point to the start of the map_index list current = map_index_head; while (current != NULL) { if (strncmp(current->filename,selected_dir,len) == 0) { if (current->filename[strlen(current->filename)-1] != '/') { //fprintf(stderr,"Loading: %s\n",current->filename); //WE7U insert_map_sorted(current->filename); /* draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP); */ } } current = current->next; } } // Else must be a regular map file else { //fprintf(stderr,"%s\n",mapname); //start_timer(); //WE7U insert_map_sorted(mapname); /* draw_map (w, SELECTED_MAP_DIR, mapname, NULL, '\0', DRAW_TO_PIXMAP); */ //stop_timer(); //print_timer_results(); if (debug_level & 16) { fprintf(stderr,"Load maps -%s\n", mapname); } XmUpdateDisplay (da); } } } else // We've hit EOF { break; } } (void)fclose (f); statusline(" ",1); // delete status line } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } // All done sorting until something is changed in the Map // Chooser. re_sort_maps = 0; //fprintf(stderr,"*** DONE sorting the selected maps.\n"); } // We have the maps in sorted order. Run through the list and // draw them. current = map_sorted_list_head; while (current != NULL) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { statusline(" ",1); // delete status line // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (disable_all_maps) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Debug // fprintf(stderr,"Drawing level:%05d, file:%s\n", // current->map_layer, // current->filename); // Draw the maps in sorted-by-layer order mdf.draw_filled = current->draw_filled; mdf.usgs_drg = current->usgs_drg; if (debug_level & 16) { fprintf(stderr,"load_maps: Calling draw_map\n"); } // Map profiling, set up for 800x600 window at "Map Profile Test // Site" bookmark. // // Loading "rd011802.shp" 500 times takes // 302->256->264->269->115->116 seconds. // // 100 times on PP200 takes 192->183 seconds. // //start_timer(); //fprintf(stderr,"Calling draw_map() 500 times...\n"); //for (dummy = 0; dummy < 500; dummy++) { draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP, &mdf); //} //stop_timer(); print_timer_results(); current = current->next; } if (debug_level & 16) { fprintf(stderr,"Load maps stop\n"); } } Xastir-Release-2.2.2/src/maps.h000066400000000000000000000206451501463444000162550ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_MAPS_H #define __XASTIR_MAPS_H #include #include #define MAX_OUTBOUND 900 #define MAX_MAP_POINTS 100000 #define MAX_FILENAME 2000 #define DRAW_TO_PIXMAP 0 #define DRAW_TO_PIXMAP_FINAL 1 #define DRAW_TO_PIXMAP_ALERTS 2 #define INDEX_CHECK_TIMESTAMPS 9998 #define INDEX_NO_TIMESTAMPS 9999 /* memory structs */ typedef struct { unsigned char vector_start_color; unsigned char object_behavior; unsigned long longitude; unsigned long latitude; } map_vectors; typedef struct { unsigned long longitude; unsigned long latitude; unsigned int mag; char label_text[33]; unsigned char text_color_quad; } text_label; typedef struct { unsigned long longitude; unsigned long latitude; unsigned int mag; unsigned char symbol; unsigned char aprs_symbol; unsigned char text_color; char label_text[30]; } symbol_label; typedef struct _map_index_record { char filename[MAX_FILENAME]; XmString XmStringPtr; unsigned long bottom; unsigned long top; unsigned long left; unsigned long right; int accessed; int max_zoom; // Specify maximum zoom at which this layer is drawn. int min_zoom; // Specify minimum zoom at which this layer is drawn. int map_layer; // Specify which layer to draw the map on. int draw_filled; // Specify whether to fill polygons when drawing. // 0 = Global No-Fill (Vector) // 1 = Global Fill // 2 = Auto (dbfawk controls it if present) int usgs_drg; // Specify whether the map has USGS DRG colormap // and should have color configuration applied // 0 = No // 1 = Yes // 2 = Auto (detect from TIFFTAG_IMAGEDESCRIPTION) int selected; // Specifies if map is currently selected int temp_select; // Temporary selection used in map properties dialog int auto_maps; // Specifies if map included in automaps function struct _map_index_record *next; } map_index_record; extern map_index_record *map_index_head; typedef struct { int img_x; int img_y; unsigned long x_long; unsigned long y_lat; } tiepoint; void draw_point(Widget w, unsigned long x1, unsigned long y1, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_point_ll(Widget w, float y1, float x1, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_vector(Widget w, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_vector_ll(Widget w, float y1, float x1, float y2, float x2, GC gc, Pixmap which_pixmap, int skip_duplicates); char *get_map_ext (char *filename); char *get_map_dir (char *fullpath); void load_auto_maps(Widget w, char *dir); void load_maps(Widget w); void fill_in_new_alert_entries(void); void load_alert_maps(Widget w, char *dir); void index_update_xastir(char *filename, unsigned long bottom, unsigned long top, unsigned long left, unsigned long right, int default_map_layer); void index_update_ll(char *filename, double bottom, double top, double left, double right, int default_map_layer); extern void get_horizontal_datum(char *datum, int sizeof_datum); void draw_grid (Widget w); void Snapshot(void); extern int index_retrieve(char *filename, unsigned long *bottom, unsigned long *top, unsigned long *left, unsigned long *right, int *max_zoom, int *min_zoom, int *map_layer, int *draw_filled, int *usgs_drg, int *automaps); extern void index_restore_from_file(void); extern void index_save_to_file(void); extern void map_indexer(int parameter); extern void get_viewport_lat_lon(double *xmin, double *ymin, double *xmax, double *ymax); extern int map_visible (unsigned long bottom_map_boundary, unsigned long top_map_boundary, unsigned long left_map_boundary, unsigned long right_map_boundary); extern int map_visible_lat_lon (double f_bottom_map_boundary, double f_top_map_boundary, double f_left_map_boundary, double f_right_map_boundary); extern int map_inside_viewport_lat_lon(double map_min_y, double map_max_y, double map_min_x, double map_max_x); extern void draw_label_text (Widget w, int x, int y, int label_length, int color, char *label_text); extern void draw_rotated_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize); extern int get_rotated_label_text_length_pixels(Widget w, char *label_text, int fontsize); extern void draw_centered_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize); extern void Monochrome( Widget widget, XtPointer clientData, XtPointer callData); extern void Snapshot(void); extern void clean_string(char *input); extern int print_rotated; extern int print_auto_rotation; extern int print_auto_scale; extern int print_in_monochrome; extern int print_invert; extern char printer_program[MAX_FILENAME+1]; extern char previewer_program[MAX_FILENAME+1]; extern int gnis_locate_place(Widget w, char *name, char *state, char *county, char *quad, char* type, char *filename, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50]); extern int pop_locate_place(Widget w, char *name, char *state, char *county, char *quad, char* type, char *filename, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50]); extern void maps_init(void); enum map_onscreen_enum {MAP_NOT_VIS=0,MAP_IS_VIS,MAP_NOT_INDEXED}; extern enum map_onscreen_enum map_onscreen(long left, long right, long top, long bottom, int checkpercentage); extern enum map_onscreen_enum map_onscreen_index(char *filename); extern time_t last_snapshot; extern time_t last_kmlsnapshot; extern int snapshot_interval; extern int grid_size; #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) extern float imagemagick_gamma_adjust; #endif // HAVE_MAGICK #endif // NO_GRAPHICS extern float raster_map_intensity; extern void Print_Postscript(Widget widget, XtPointer clientData, XtPointer callData); extern void map_plot (Widget w, long max_x, long max_y, long x_long_cord, long y_lat_cord, unsigned char color, long object_behavior, int destination_pixmap, int draw_filled); // A struct to pass down in to map driver functions so they can have // driver-specific flags. Most drivers won't care about any (or even all) // of the flags, but this way we can just pass a single pointer rather than // adding new arguments to the generic interface each time we want new flags typedef struct { int draw_filled; int usgs_drg; } map_draw_flags; #endif /* __XASTIR_MAPS_H */ Xastir-Release-2.2.2/src/messages.c000066400000000000000000001261711501463444000171200ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "main.h" #include "messages.h" #include "util.h" #include "interface.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" char group_data_file[400]; char *group_data_list = NULL; // Need this NULL for Solaris! int group_data_count = 0; int group_data_max = 0; char message_counter[5+1]; int auto_reply; char auto_reply_message[100]; Message_Window mw[MAX_MESSAGE_WINDOWS+1]; // Send Message widgets Message_transmit message_pool[MAX_OUTGOING_MESSAGES+1]; // Transmit message queue void clear_message_windows(void) { int i; begin_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" ); for (i = 0; i < MAX_MESSAGE_WINDOWS; i++) { if (mw[i].send_message_dialog) { XtDestroyWidget(mw[i].send_message_dialog); } mw[i].send_message_dialog = (Widget)NULL; mw[i].to_call_sign[0] = '\0'; mw[i].send_message_call_data = (Widget)NULL; mw[i].D700_mode = (Widget)NULL; mw[i].D7_mode = (Widget)NULL; mw[i].HamHUD_mode = (Widget)NULL; mw[i].message_data_line1 = (Widget)NULL; mw[i].message_data_line2 = (Widget)NULL; mw[i].message_data_line3 = (Widget)NULL; mw[i].message_data_line4 = (Widget)NULL; mw[i].send_message_text = (Widget)NULL; } end_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" ); } static int group_comp(const void *a, const void *b) { if (!*(char *)a) { return ((int)(*(char *)b != '\0')); } return strcasecmp(a, b); } void group_build_list(char *filename) { char *ptr; FILE *f; struct stat group_stat; int i; if (group_data_count == group_data_max) { ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10); if (ptr) { group_data_list = ptr; group_data_max += 10; //fprintf(stderr, "group_data_max: %d\n", group_data_max); } else { fprintf(stderr, "Unable to allocate more memory for group_data_list (1)\n"); } } // Make sure we always listen for ourself, XASTIR, & our Version groups xastir_snprintf(&group_data_list[0],10,"%s",my_callsign); xastir_snprintf(&group_data_list[10],10,"XASTIR"); xastir_snprintf(&group_data_list[20],10,"%s",XASTIR_TOCALL); group_data_count = 3; // If we are in special group look for messages. if (altnet) { xastir_snprintf(&group_data_list[group_data_count*10],10,"%s",altnet_call); group_data_count++; } // if (! stat(filename, &group_stat) ) { f = fopen(filename, "r"); // File exists } else { f = fopen(filename, "w+"); // No file. Create it and open it. } if (f == NULL) { fprintf(stderr,"Couldn't open file for reading -or- appending: %s\n", filename); return; } while (!feof(f)) { if (group_data_count == group_data_max) { ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10); if (ptr) { group_data_list = ptr; group_data_max += 10; //fprintf(stderr, "group_data_max(2): %d\n", group_data_max); } else { fprintf(stderr, "Unable to allocate more memory for group_data_list (2)\n"); } } if (group_data_count < group_data_max) { group_data_list[group_data_count*10] = '\0'; if (fgets(&group_data_list[group_data_count*10], 10, f) == NULL) { // Error reading file or end-of-file. Continue processing // the (partial?) string we just read, in the code below. } if ((ptr = strchr(&group_data_list[group_data_count*10], '\n'))) { *ptr = '\0'; } else while ((i = fgetc(f)) != EOF && i != '\n'); // clean-up after long group name // check for DOS EOL markup! if ((ptr = strchr(&group_data_list[group_data_count*10], '\r'))) { *ptr = '\0'; } if (group_data_list[group_data_count*10]) { group_data_count++; } } } (void)fclose(f); qsort(group_data_list, (size_t)group_data_count, 10, group_comp); if (debug_level & 2) { for (i = 0; i < group_data_count; i++) { fprintf(stderr,"Group %2d: %s\n", i, &group_data_list[i*10]); } } } int group_active(char *from) { static struct stat current_group_stat; struct stat group_stat; static char altgroup[10]; char group_data_path[MAX_VALUE]; get_user_base_dir(group_data_file, group_data_path, sizeof(group_data_path)); (void)remove_trailing_spaces(from); // If we cycle to/from special group or file changes, rebuild group list. if ((!stat( group_data_path, &group_stat ) && (current_group_stat.st_size != group_stat.st_size || current_group_stat.st_mtime != group_stat.st_mtime || current_group_stat.st_ctime != group_stat.st_ctime))) { // altgroup equates to "address of altgroup" which always evaluates // as true. Commenting it out of the conditional. --we7u. // || (altgroup && strcasecmp(altgroup, VERSIONFRM))) { group_build_list( group_data_path ); current_group_stat = group_stat; xastir_snprintf(altgroup,sizeof(altgroup),"%s",VERSIONFRM); } if (group_data_list != NULL) // Causes segfault on Solaris 2.5 without this! { return (int)(bsearch(from, group_data_list, (size_t)group_data_count, (size_t)10, group_comp) != NULL); } else { return(0); } } int look_for_open_group_data(char *to) { int i,found; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; begin_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" ); found = FALSE; for(i = 0; i < MAX_MESSAGE_WINDOWS; i++) { /* find station */ if(mw[i].send_message_dialog != NULL) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,to);*/ if(strcmp(temp1,to)==0) { found=(int)TRUE; break; } } } end_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" ); return(found); } // What we wish to do here: Check for an active Send Message dialog // that contains the callsign of interest. If one doesn't exist, // create one and pop it up. We don't want to do this for duplicate // message lines or duplicate acks for any particular QSO. To do so // would cause the Send Message dialog to pop up on every such // received message, which is VERY annoying (that was the default in // Xastir for years, and nobody liked it!). // int check_popup_window(char *from_call_sign, int group) { int i,found,j,ret; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; //fprintf(stderr,"\tcheck_popup_window()\n"); ret = -1; found = -1; begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" ); // Check for an already-created dialog for talking to this // particular call_sign. // for (i = 0; i < MAX_MESSAGE_WINDOWS; i++) { if (mw[i].send_message_dialog != NULL) // If dialog created { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,from_call_sign);*/ if (strcasecmp(temp1, from_call_sign) == 0) { // Found a call_sign match in a Send Message dialog! //fprintf(stderr,"\tFound a Send_message dialog match\n"); found = i; break; } } } end_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" ); // If found == -1 at this point, we haven't found a Send Message // dialog that contains the call_sign of interest. // if (found == -1 && (group == 2 || group_active(from_call_sign))) { /* no window found Open one! */ //fprintf(stderr,"\tNo Send Message dialog found, creating one\n"); begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window2" ); i= -1; for (j=0; j to <%s>\n",from,to); } // Repeat until we process the entire message. We'll process it // a chunk at a time, size of chunk to correspond to max APRS // message line length. // while (!error && (message_ptr < (int)strlen(message))) { ok=0; space_loc=0; // Break a long message into smaller chunks that can be // processed into APRS messages. Break at a space character // if possible. // for (j=0; j %d %d\n",message_out,message_ptr,last_space); } if (j >= MAX_MESSAGE_OUTPUT_LENGTH) { message_ptr = MAX_MESSAGE_OUTPUT_LENGTH; } else { message_ptr=last_space; } /* check for others in the queue */ wait_on_first_ack=0; for (i=0; iRF // QSO's if we're sending to the internet too, but that's a bug in // the igate software, and not something that Xastir should try to // correct itself. // void transmit_message_data(char *to, char *message, char *path) { DataRow *p_station; if (debug_level & 2) { fprintf(stderr,"Transmitting data to %s : %s\n",to,message); } p_station = NULL; if (strcmp(to, my_callsign) == 0) // My station message { // Send out all active ports if (debug_level & 2) { fprintf(stderr,"My call VIA any way\n"); } output_my_data(message,-1,0,0,0,path); // All done return; } if (!search_station_name(&p_station,to,1)) { // No data record found for this station. Send to all // active ports. if (debug_level & 2) { fprintf(stderr,"VIA any way\n"); } output_my_data(message,-1,0,0,0,path); // All done return; } if (debug_level & 2) { fprintf(stderr,"found station %s\n",p_station->call_sign); } // It's not being sent to my callsign but to somebody else // "out there". Because the truth is... if ( ((p_station->flag & ST_VIATNC) != 0) && (heard_via_tnc_in_past_hour(to)) ) { int port_num; // Station was heard via a TNC port within the previous // hour. Send to TNC port it was heard on. // output_my_data(message,p_station->heard_via_tnc_port,0,0,0,path); // Send to all internet ports. Iterate through the port // definitions looking for internet ports, send the message // out once to each. // for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++) { // If it's an internet port, send the message. if (port_data[port_num].device_type == DEVICE_NET_STREAM) { output_my_data(message,port_num,0,0,0,path); } } // All done return; } else if (p_station->data_via==DATA_VIA_NET) { int port_num; int active_internet_ports_found = 0; // Station was heard over an internet interface. Check // whether we have any internet interfaces available with TX // enabled. If so, send out those ports. Else drop through // and hit the TRANSMIT-ALL clause at the end of this // function. // Iterate through the port definitions looking for internet // ports with transmit enabled. Send the message out once // to each. // for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++) { // If it's an internet port and transmit is enabled, // send the message and set the flag. if ( (port_data[port_num].device_type == DEVICE_NET_STREAM) && (port_data[port_num].active == DEVICE_IN_USE) && (port_data[port_num].status == DEVICE_UP) && (devices[port_num].transmit_data == 1) ) { // Found a tx-enabled internet port that was up and // running. Send the message out this port. output_my_data(message,port_num,0,0,0,path); active_internet_ports_found++; } } if (active_internet_ports_found) { // We found at least one tx-enabled internet interface // that was up and running. // All done. return; } else // No active tx-enabled internet ports were found. { // Drop through to the TRANSMIT-ALL clause below. } } // We've NOT heard this station on a TNC port within the // last hour and have no active tx-enabled internet ports to // send to. Send to ALL active ports. if (debug_level & 2) { fprintf(stderr,"VIA any way\n"); } output_my_data(message,-1,0,0,0,path); } // The below variables and functions implement the capability to // schedule ACK's some number of seconds out from the current time. // We use it to schedule duplicate ACK's at 30/60/120 seconds out, // but only if we see duplicate message lines from remote stations. // // Create a struct to hold the delayed ack's. typedef struct _delayed_ack_record { char to_call_sign[MAX_CALLSIGN+1]; char message_line[MAX_MESSAGE_OUTPUT_LENGTH+1+5+1]; char path[200]; time_t active_time; struct _delayed_ack_record *next; } delayed_ack_record, *delayed_ack_record_p; // And a pointer to a list of them. delayed_ack_record_p delayed_ack_list_head = NULL; void transmit_message_data_delayed(char *to, char *message, char *path, time_t when) { delayed_ack_record_p ptr = delayed_ack_list_head; // We need to run down the current list looking for any records // that are identical and within 30 seconds time-wise of this // one. If so, don't allocate a new record. This keeps the // dupes down on transmit so that at the most we transmit one // ack per 30 seconds per QSO, except of course for real-time // ack's which don't go through this function. // Run through the queue and check each record while (ptr != NULL) { if ( strcmp(ptr->to_call_sign,to) == 0 && strcmp(ptr->message_line,message) == 0 ) { // // We have matches on call_sign and message. Check the // time next. // if (labs(when - ptr->active_time) < 30) { // // We're within 30 seconds of an identical ack. // Drop this new one (don't add it). // //fprintf(stderr,"Dropping delayed ack: Too close timewise to another: %s, %s\n", // to, message); return; // Don't allocate new record on queue } } ptr = ptr->next; } // If we made it to here, there aren't any queued ACK's that are // close enough in time to drop this new one. Add it to the // queue. //fprintf(stderr, "Queuing ACK for delayed transmit: %s, %s\n", // to, message); // Allocate a record to hold it ptr = (delayed_ack_record_p)malloc(sizeof(delayed_ack_record)); // Fill in the record xastir_snprintf(ptr->to_call_sign, sizeof(ptr->to_call_sign), "%s", to); xastir_snprintf(ptr->message_line, sizeof(ptr->message_line), "%s", message); if (path == NULL) { ptr->path[0] = '\0'; } else { xastir_snprintf(ptr->path, sizeof(ptr->path), "%s", path); } ptr->active_time = when; // Add the record to the head of the list ptr->next = delayed_ack_list_head; delayed_ack_list_head = ptr; } time_t delayed_transmit_last_check = (time_t)0; void check_delayed_transmit_queue(int curr_sec) { delayed_ack_record_p ptr = delayed_ack_list_head; int active_records = 0; // Skip this function if we did it during this second already. if (delayed_transmit_last_check == curr_sec) { return; } delayed_transmit_last_check = curr_sec; //fprintf(stderr, "Checking delayed TX queue for something to transmit.\n"); //fprintf(stderr, "."); // Run down the linked list checking every record. while (ptr != NULL) { if (ptr->active_time != 0) // Active record { char new_path[MAX_LINE_SIZE+1]; //fprintf(stderr, "Found active record\n"); active_records++; // Check for a custom path having been set in the Send // Message dialog. If so, use this for our outgoing // path instead and reset all of the queued message // paths to this station to this new path. // get_send_message_path(ptr->to_call_sign, new_path, sizeof(new_path)); if (new_path[0] != '\0' && strcmp(new_path, ptr->path) != 0) { // We have a custom path set which is different than // the path saved with the outgoing message. Change // the path to match the new path. // //fprintf(stderr, // "Changing queued ack's to new path: %s\n", // new_path); memcpy(ptr->path, new_path, sizeof(ptr->path)); ptr->path[sizeof(ptr->path)-1] = '\0'; // Terminate string } if (ptr->active_time <= sec_now()) { // Transmit it //fprintf(stderr,"Found something delayed to transmit! %ld\n",sec_now()); if (ptr->path[0] == '\0') { transmit_message_data(ptr->to_call_sign, ptr->message_line, NULL); } else { transmit_message_data(ptr->to_call_sign, ptr->message_line, ptr->path); } ptr->active_time = (time_t)0; } } ptr = ptr->next; } // Check if entire list contains inactive records. If so, // delete the list. // if (!active_records && (delayed_ack_list_head != NULL)) { // No active records, but the list isn't empty. Reclaim the // records in the list. while (delayed_ack_list_head != NULL) { ptr = delayed_ack_list_head->next; free(delayed_ack_list_head); //fprintf(stderr,"Free'ing delayed_ack record\n"); delayed_ack_list_head = ptr; } } } void check_and_transmit_messages(time_t time) { int i; char temp[200]; char to_call[40]; // Skip this function if we did it during this second already. if (last_check_and_transmit == time) { return; } last_check_and_transmit = time; for (i=0; i from <%s>:%s-%s\n", message_pool[i].tries, message_pool[i].to_call_sign, message_pool[i].from_call_sign, message_pool[i].message_line, message_pool[i].seq); pad_callsign(to_call,message_pool[i].to_call_sign); // Add Leading ":" as per APRS Spec. // Add trailing '}' to signify that we're // Reply/Ack protocol capable. last_ack_ptr = get_most_recent_ack(to_call); if (last_ack_ptr != NULL) xastir_snprintf(last_ack, sizeof(last_ack), "%s", last_ack_ptr); else { last_ack[0] = '\0'; } xastir_snprintf(temp, sizeof(temp), ":%s:%s{%s}%s", to_call, message_pool[i].message_line, message_pool[i].seq, last_ack); if (debug_level & 2) { fprintf(stderr,"MESSAGE OUT>%s<\n",temp); } // Check for a custom path having been set // in the Send Message dialog. If so, use // this for our outgoing path instead and // reset all of the queued message paths to // this station to this new path. // get_send_message_path(to_call, new_path, sizeof(new_path)); //fprintf(stderr,"get_send_message_path(%s) returned: %s\n",to_call,new_path); if (new_path[0] != '\0' && strcmp(new_path,message_pool[i].path) != 0) { // We have a custom path set which is // different than the path saved with // the outgoing message. // // Change all messages to that callsign // to match the new path. // change_path_outgoing_messages_to(to_call,new_path); } // Transmit the message transmit_message_data(message_pool[i].to_call_sign, temp, message_pool[i].path); message_pool[i].active_time = time + message_pool[i].next_time; //fprintf(stderr,"%d\n",(int)message_pool[i].next_time); } /* fprintf(stderr, "Msg Interval = %3ld seconds or %4.1f minutes\n", message_pool[i].next_time, message_pool[i].next_time / 60.0); */ // Record the interval we're using. Put it with // the message in the general message pool, so // that the Send Message dialog can display it. // It will only display it if the message is // actively being transmitted. If it has been // cancelled, timed out, or hasn't made it to // the transmit position yet, it won't be shown. // msg_record_interval_tries(message_pool[i].to_call_sign, message_pool[i].from_call_sign, message_pool[i].seq, message_pool[i].next_time, // Interval message_pool[i].tries); // Tries // Start at 7 seconds for the interval. We set // it to 7 seconds in output_message() above. // Double the interval each retry until we hit // 10 minutes. Keep transmitting at 10 minute // intervals until we hit MAX_TRIES. // Double the interval between messages message_pool[i].next_time = message_pool[i].next_time * 2; // Limit the max interval to 10 minutes if (message_pool[i].next_time > (time_t)600L) { message_pool[i].next_time = (time_t)600L; } message_pool[i].tries++; // Expire it if we hit the limit if (message_pool[i].tries > MAX_TRIES) { char temp[150]; char temp_to[20]; xastir_snprintf(temp,sizeof(temp),"To: %s, Msg: %s", message_pool[i].to_call_sign, message_pool[i].message_line); //popup_message(langcode("POPEM00004"),langcode("POPEM00017")); popup_message( "Retries Exceeded!", temp ); // Fake the system out: We're pretending // that we got an ACK back from it so that // we can either release the next message to // go out, or at least make the send button // sensitive again. // We need to copy the to_call_sign into // another variable because the // clear_acked_message() function clears out // the message then needs this parameter to // do another compare (to enable the Send Msg // button again). xastir_snprintf(temp_to, sizeof(temp_to), "%s", message_pool[i].to_call_sign); // Record a fake ack and add "*TIMEOUT*" to // the message. This will be displayed in // the Send Message dialog. msg_record_ack(temp_to, message_pool[i].from_call_sign, message_pool[i].seq, 1, // "1" specifies a timeout 0); // Not a cancel clear_acked_message(temp_to, message_pool[i].from_call_sign, message_pool[i].seq); // if (mw[i].send_message_dialog!=NULL) /* clear submit */ // XtSetSensitive(mw[i].button_ok,TRUE); } } } else { if (debug_level & 2) { fprintf(stderr,"Message #%s is waiting to have a previous one cleared\n",message_pool[i].seq); } } } } } // Function which marks a message as ack'ed in the transmit queue // and releases the next message to allow it to be transmitted. // Handles REPLY-ACK format or normal ACK format just fine. // void clear_acked_message(char *from, char *to, char *seq) { int i,ii; int found; char lowest[3]; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; char msg_id[5+1]; // Copy seq into local variable xastir_snprintf(msg_id, sizeof(msg_id), "%s", seq); // Check for REPLY-ACK protocol. If found, terminate at the end // of the first ack. temp_ptr = strchr(msg_id, '}'); if (temp_ptr) { *temp_ptr = '\0'; } (void)remove_trailing_spaces(msg_id); // This is IMPORTANT here!!! //lowest=100000; // Highest Base-90 2-char string xastir_snprintf(lowest,sizeof(lowest),"zz"); found= -1; for (i=0; i <%s> from <%s> <%s> seq <%s> <%s>\n", to, message_pool[i].to_call_sign, from, message_pool[i].from_call_sign, msg_id, message_pool[i].seq); if (strcmp(message_pool[i].to_call_sign,from)==0) { if (debug_level & 1) { fprintf(stderr,"Matched message to_call_sign\n"); } if (strcmp(message_pool[i].from_call_sign,to)==0) { if (debug_level & 1) { fprintf(stderr,"Matched message from_call_sign\n"); } if (strcmp(message_pool[i].seq,msg_id)==0) { if (debug_level & 2) { fprintf(stderr,"Found and cleared\n"); } clear_outgoing_message(i); // now find and release next message, look for the lowest sequence? // What about when the sequence rolls over? for (i=0; i #include // printf #include #include #include "xastir.h" #include "main.h" #include "lang.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #if defined(__LSB__) || defined(LESSTIF_VERSION) #define NO_DYNAMIC_WIDGETS 1 #endif #define MAX_PATH 200 Widget auto_msg_on, auto_msg_off; Widget auto_msg_dialog = (Widget)NULL; Widget auto_msg_set_data = (Widget)NULL; static xastir_mutex auto_msg_dialog_lock; xastir_mutex send_message_dialog_lock; void select_station_type(int ii); void messages_gui_init(void) { init_critical_section( &auto_msg_dialog_lock ); init_critical_section( &send_message_dialog_lock ); } /**** Send Message ******/ // This function chops off the first callsign, then returns a string // containing the same string in reversed callsign order. Note that // if RELAY was used by the sending station and that RELAY did _not_ // do callsign substitution, that part of the path will be chopped // heading back. If the sending station really needed that relay // station in order to receive the reply, he/she should have put in // a callsign instead of RELAY. We can't in good conscience use // RELAY on the end of the return path. // // We also chop off anything after comma "q" two letters, and a // comma. This is the injection-ID called the Q-construct, which // lets us know how a signal was injected into the NET and by whom. // void reverse_path(char *input_string) { char reverse_path[200]; int indexes[20]; int i, j, len; char temp[MAX_CALLSIGN+1]; // Check for NULL pointer if (input_string == NULL) { return; } // Check for zero-length string len = strlen(input_string); if (len == 0) { return; } // Initialize reverse_path[0] = '\0'; for (i = 0; i < 20; i++) { indexes[i] = -1; } // Add a comma onto the end (makes later code easier) input_string[len++] = ','; input_string[len] = '\0'; // Terminate it // Find each comma j = 0; for (i = 0; i < (int)strlen(input_string); i++) { if (input_string[i] == ',') { indexes[j++] = i; //fprintf(stderr,"%d\n",i); // Debug code } } // Get rid of asterisks and commas in the original string: for (i = 0; i < len; i++) { if (input_string[i] == '*' || input_string[i] == ',') { input_string[i] = '\0'; } } // Go left to right looking for a 3-letter callsign starting // with 'q'. If found readjust 'j' to skip that callsign and // everything after it. // for ( i = 0; i < j; i++) { char *c = &input_string[indexes[i] + 1]; //fprintf(stderr,"'%s'\t", c ); if (c[0] == 'q') { if ( strlen(c) == 3 ) // "qAR" { //fprintf(stderr,"Found:%s\n", c); j = i; } } } // Convert used "WIDEn-N"/"TRACEn-N" paths back to their // original glory. Convert "TRACE" to "WIDE" as well. We could // also choose to change "WIDEn-N" to a slimmer version based on // how many digi's were used, for instance "WIDE7-6" could // change to "WIDE1-1" or "WIDE7-1", and "WIDE5-2" could change // to "WIDE3-3" or "WIDE5-3". // for () // j now tells us how many were found. Now go in the reverse // order and concatenate the substrings together. Get rid of // "RELAY" and "TCPIP" calls as we're doing it. input_string[0] = '\0'; // Clear out the old string first for ( i = j - 1; i >= 0; i-- ) { if ( (input_string[indexes[i]+1] != '\0') && (strncasecmp(&input_string[indexes[i]+1],"RELAY",5) != 0) && (strncasecmp(&input_string[indexes[i]+1],"TCPIP",5) != 0) ) { // Snag each callsign into temp: xastir_snprintf(temp, sizeof(temp), "%s", &input_string[indexes[i]+1]); // Massage temp until it resembles something we want to // use. // "WIDEn" -> "WIDEn-N," // "TRACEn" -> "WIDEn-N," // "TRACE" -> "WIDE," if (strncasecmp(temp,"WIDE",4) == 0) { if ( (temp[4] != ',') && is_num_chr(temp[4]) ) { //fprintf(stderr,"Found a WIDEn-N\n"); xastir_snprintf(temp, sizeof(temp), "WIDE%c-%c", temp[4], temp[4]); } else { //fprintf(stderr,"Found a WIDE\n"); // Leave temp alone, it's just a WIDE } } else if (strncasecmp(temp,"TRACE",5) == 0) { if ( (temp[5] != ',') && is_num_chr(temp[5]) ) { //fprintf(stderr,"Found a TRACEn-N\n"); xastir_snprintf(temp, sizeof(temp), "WIDE%c-%c", temp[5], temp[5]); } else { //fprintf(stderr,"Found a TRACE\n"); // Convert it from TRACE to WIDE xastir_snprintf(temp, sizeof(temp), "WIDE"); } } // Add temp to the end of our path: strncat(reverse_path,temp,sizeof(reverse_path)-strlen(reverse_path)-1); strncat(reverse_path,",",sizeof(reverse_path)-strlen(reverse_path)-1); } } // Remove the ending comma reverse_path[strlen(reverse_path) - 1] = '\0'; // Save the new path back into the string we were given. strncat(input_string, reverse_path, len); } void get_path_data(char *callsign, char *path, int max_length) { DataRow *p_station; if (search_station_name(&p_station,callsign,1)) // Found callsign { char new_path[200]; if (p_station->node_path_ptr) { xastir_snprintf(new_path,sizeof(new_path), "%s", p_station->node_path_ptr); if(debug_level & 2) fprintf(stderr,"\nPath from %s: %s\n", callsign, new_path); // We need to chop off the first call, remove asterisks // and injection ID's, and reverse the order of the // callsigns. We need to do the same thing in the // callback for button_submit_call, so that we get a new // path whenever the callsign is changed. Create a new // TextFieldWidget to hold the path info, which gets // filled in here (and the callback) but can be changed by // the user. Must find a nice way to use this path from // output_my_data() as well. reverse_path(new_path); if (debug_level & 2) fprintf(stderr," Path to %s: %s\n", callsign, new_path); xastir_snprintf(path, max_length, "%s", new_path); } else { if (debug_level & 2) { fprintf(stderr," Path from %s is (null)\n",callsign); } path[0]='\0'; } } else // Couldn't find callsign. It's { // not in our station database. if(debug_level & 2) { fprintf(stderr,"Path from %s: No Path Known\n",callsign); } path[0] = '\0'; } } static Widget change_path_dialog = NULL; static Widget current_path = NULL; void Send_message_change_path_destroy_shell(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (change_path_dialog) { XtPopdown(change_path_dialog); XtDestroyWidget(change_path_dialog); } change_path_dialog = (Widget)NULL; } // Apply button // Fetch the text from the "current_path" widget and place it into // the mw[ii].send_message_path widget. // void Send_message_change_path_apply(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char path[MAX_PATH+1]; char *temp_ptr; if (current_path != NULL && clientData != NULL) { temp_ptr = XmTextFieldGetString(current_path); xastir_snprintf(path, sizeof(path), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(path); (void)to_upper(path); // Check here for "DIRECT PATH" or "DEFAULT PATH". If one of them, // do some special processing if need be so that lower layers will // interpret it correctly. XmTextFieldSetString(clientData, path); Send_message_change_path_destroy_shell(NULL, NULL, NULL); } } // "Direct Path" button // // Put "DIRECT PATH" in the widgets. We pass "DIRECT PATH" all the // way to the transmit routines, then change it to an empty path // when the transmit actually goes out. // void Send_message_change_path_direct(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { if (current_path == NULL || clientData == NULL) { Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Change current_path widget XmTextFieldSetString(current_path, "DIRECT PATH"); Send_message_change_path_apply(NULL, clientData, NULL); } // "Default Path(s)" button // // Blank out the path so the default paths get used. We pass // "DEFAULT PATH" all the way to the transmit routines, then change // it there to be a blank. // void Send_message_change_path_default(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { if (current_path == NULL || clientData == NULL) { Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Change current_path widget XmTextFieldSetString(current_path, "DEFAULT PATH"); Send_message_change_path_apply(NULL, clientData, NULL); } // TODO: Change the "Path:" box so that clicking or double-clicking // on it will bring up a "Change Path" dialog. Could also use a // "Change" or "Change Path" button if easier. This new dialog // should have the current path (editable), the reverse path (not // editable), and these buttons: // // "DIRECT path" // "DEFAULT path(s)" // "Apply" // "Cancel" // // Of course the underlying code will have to tweaked to be able to // pass an EMPTY path all the way down through the layers. We can't // currently do that. We'll have to define a specific string for // that. Insert the text "--DEFAULT--", "--BLANK--", or the actual // path in the editable box and in the "Path:" box on the Send // Message dialog so that the user knows which one is in effect. // // Remember to close the Change Path dialog if we close the Send // Message dialog which corresponds to it. // // Adding this new CHANGE PATH dialog will allow us to get rid of // three bugs on the active bug-list: #1499820, #1326975, and // #1326973. // void Send_message_change_path( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { int ii; //Atom delw; Widget pane, form, current_path_label, reverse_path_label, reverse_path, button_default, button_direct, button_apply, button_cancel; Widget button_wide11, button_wide21, button_wide22, button_nogate; char *temp_ptr; char temp1[MAX_LINE_SIZE+1]; char path[MAX_PATH+1]; //begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_change_path" ); if (clientData == NULL) { return; } if (change_path_dialog) { // Destroy the old one before creating a new one Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Fetch Send Message dialog number from clientData, store in // "ii". // ii = atoi(clientData); // "Change Path" change_path_dialog = XtVaCreatePopupShell(langcode("WPUPMSB019"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNtitleString,"Change Path", XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Send_message_change_path pane", xmPanedWindowWidgetClass, change_path_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Send_message_change_path form", xmFormWidgetClass, pane, XmNfractionBase, 4, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Path:" current_path_label = XtVaCreateManagedWidget(langcode("WPUPMSB010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); current_path = XtVaCreateManagedWidget("Send_message_change_path path", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 26, XmNwidth, ((26*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, current_path_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // "Reverse Path:" reverse_path_label = XtVaCreateManagedWidget(langcode("WPUPMSB022"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, current_path, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); reverse_path = XtVaCreateManagedWidget("Send_message_change_path reverse path", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 26, XmNwidth, ((26*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, reverse_path_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide11 = XtVaCreateManagedWidget("WIDE1-1", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide21 = XtVaCreateManagedWidget("WIDE2-1", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide22 = XtVaCreateManagedWidget("WIDE2-2", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_nogate = XtVaCreateManagedWidget("NOGATE", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtSetSensitive(button_wide11, FALSE); XtSetSensitive(button_wide21, FALSE); XtSetSensitive(button_wide22, FALSE); XtSetSensitive(button_nogate, FALSE); // "Use Default Path(s)" button_default = XtVaCreateManagedWidget(langcode("WPUPMSB020"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Direct (No path)" button_direct = XtVaCreateManagedWidget(langcode("WPUPMSB021"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Apply" button_apply = XtVaCreateManagedWidget(langcode("UNIOP00032"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Close" button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_default, XmNactivateCallback, Send_message_change_path_default, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_direct, XmNactivateCallback, Send_message_change_path_direct, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_apply, XmNactivateCallback, Send_message_change_path_apply, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_cancel, XmNactivateCallback, Send_message_change_path_destroy_shell,(XtPointer)mw[ii].win); // Fill in the fields if(mw[ii].send_message_dialog != NULL) { char call_sign[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); XmTextFieldSetString(current_path, temp1); // Go get the reverse path. Start with the callsign. temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(call_sign, sizeof(call_sign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_dash_zero(call_sign); // Try lowercase get_path_data(call_sign, path, MAX_PATH); if (strlen(path) == 0) { // Try uppercase (void)to_upper(call_sign); get_path_data(call_sign, path, MAX_PATH); } XmTextFieldSetString(reverse_path, path); } pos_dialog(change_path_dialog); //delw (void)XmInternAtom(XtDisplay(change_path_dialog),"WM_DELETE_WINDOW", FALSE); // XmAddWMProtocolCallback(change_path_dialog, delw, Send_message_destroy_shell, (XtPointer)mw[ii].win); XtManageChild(form); XtManageChild(pane); XtPopup(change_path_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(change_path_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); //end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_change_path" ); } // Find a custom path set in a Send Message dialog, using the remote // callsign as the key. If no custom path, sets path to '\0'. // void get_send_message_path(char *callsign, char *path, int path_size) { int ii; int found = -1; char *temp_ptr; char temp1[MAX_LINE_SIZE+1]; char my_callsign[20]; xastir_snprintf(my_callsign,sizeof(my_callsign),"%s",callsign); remove_trailing_spaces(my_callsign); //fprintf(stderr,"Looking for %s\n", my_callsign); for(ii = 0; ii < MAX_MESSAGE_WINDOWS; ii++) { // find matching callsign if(mw[ii].send_message_dialog != NULL) { temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_dash_zero(temp1); (void)to_upper(temp1); if(strcmp(temp1,my_callsign)==0) { found = ii; break; } } } if (found == -1) { //fprintf(stderr,"Didn't find dialog\n"); path[0] = '\0'; return; } // We have the correct Send Message dialog. Snag the path. // temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); (void)remove_leading_spaces(temp1); (void)remove_trailing_spaces(temp1); // Path empty? if (temp1[0] == '\0') { //fprintf(stderr,"Didn't find custom path\n"); path[0] = '\0'; return; } // We have a real path! Stuff it into the path variable. xastir_snprintf(path, path_size, "%s", temp1); //fprintf(stderr,"Found custom path: %s\n", path); } void Send_message_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData)) { int ii; // char *temp_ptr; // char temp1[MAX_LINE_SIZE+1]; //fprintf(stderr,"3Send_message_destroy_shell() start\n"); ii=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_destroy_shell" ); if (mw[ii].send_message_dialog) { /* // Check whether the send_message_call_data field has a // custom path entered. temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(temp1); (void)remove_trailing_spaces(temp1); (void)remove_trailing_dash_zero(temp1); if(temp1[0] != '\0') { // Yep, we have a custom path. Warn the user that // they're going to lose this path by destroying the // dialog. popup_message_always(langcode("POPEM00036"), langcode("POPEM00040")); } */ XtPopdown(mw[ii].send_message_dialog); XtDestroyWidget(mw[ii].send_message_dialog); } mw[ii].send_message_dialog = (Widget)NULL; mw[ii].to_call_sign[0] = '\0'; mw[ii].send_message_call_data = (Widget)NULL; mw[ii].D700_mode = (Widget)NULL; mw[ii].D7_mode = (Widget)NULL; mw[ii].HamHUD_mode = (Widget)NULL; mw[ii].message_data_line1 = (Widget)NULL; mw[ii].message_data_line2 = (Widget)NULL; mw[ii].message_data_line3 = (Widget)NULL; mw[ii].message_data_line4 = (Widget)NULL; mw[ii].send_message_text = (Widget)NULL; Send_message_change_path_destroy_shell(NULL, NULL, NULL); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_destroy_shell" ); //fprintf(stderr,"3Send_message_destroy_shell() finished\n"); } void Check_new_call_messages( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int pos; intptr_t i; i=(intptr_t)clientData; /* clear window*/ pos=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Check_new_call_messages" ); if (mw[i].send_message_dialog) { // If we have a dialog already, clear out the message area // from 0 to the last text position. // Known to have memory leaks with some versions of Motif: //XmTextSetString(mw[i].send_message_text,""); XmTextReplace(mw[i].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[i].send_message_text), ""); // Set the cursor position to 0 XtVaSetValues(mw[i].send_message_text,XmNcursorPosition,pos,NULL); } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Check_new_call_messages" ); update_messages(1); // Force an immediate update if (mw[i].send_message_dialog) { // Re-arrange the outgoing message boxes based on the type of device we're talking to. select_station_type(i); } } void Clear_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { clear_outgoing_messages(); } void Send_message_now( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; char temp2[121]; char temp_line1[68] = ""; #ifndef NO_DYNAMIC_WIDGETS char temp_line2[23] = ""; char temp_line3[23] = ""; char temp_line4[10] = ""; #endif // NO_DYNAMIC_WIDGETS char path[200]; int ii, jj; char *temp_ptr; int substitution_made = 0; int d700; int d7; int hamhud; char temp_file_path[MAX_VALUE]; ii=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_now" ); if (mw[ii].send_message_dialog) { d700 = XmToggleButtonGetState(mw[ii].D700_mode); d7 = XmToggleButtonGetState(mw[ii].D7_mode); hamhud = XmToggleButtonGetState(mw[ii].HamHUD_mode); temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); // Fetch message_data_line1 in all cases temp_ptr = XmTextFieldGetString(mw[ii].message_data_line1); xastir_snprintf(temp_line1, sizeof(temp_line1), "%s", temp_ptr); XtFree(temp_ptr); #ifndef NO_DYNAMIC_WIDGETS // If D700/D7 mode, fetch message_data_line2 if (d700 || d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line2); xastir_snprintf(temp_line2, sizeof(temp_line2), "%s", temp_ptr); XtFree(temp_ptr); } // If D700/D7 mode, fetch message_data_line3 if (d700 || d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line3); xastir_snprintf(temp_line3, sizeof(temp_line3), "%s", temp_ptr); XtFree(temp_ptr); } // If D7 mode, fetch message_data_line4 if (d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line4); xastir_snprintf(temp_line4, sizeof(temp_line4), "%s", temp_ptr); XtFree(temp_ptr); } // Construct the entire message now if (hamhud) // Combine two lines together { xastir_snprintf(temp2, sizeof(temp2), "%-20s%-47s", temp_line1, temp_line2); } else if (d700) // Combine three lines together { xastir_snprintf(temp2, sizeof(temp2), "%-22s%-22s%-20s", temp_line1, temp_line2, temp_line3); } else if (d7) // Combine four lines together { xastir_snprintf(temp2, sizeof(temp2), "%-12s%-12s%-12s%-9s", temp_line1, temp_line2, temp_line3, temp_line4); } else #endif // NO_DYNAMIC_WIDGETS { // Use line1 only xastir_snprintf(temp2, sizeof(temp2), "%s", temp_line1); } // We have the message text now. Check it for illegal // characters, remove them and substitute '.' if found. // Illegal characters are '|', '{', and '~' for messaging. for (jj = 0; jj < (int)strlen(temp2); jj++) { if ( temp2[jj] == '|' || temp2[jj] == '{' || temp2[jj] == '~' ) { temp2[jj] = '.'; // Replace with a dot substitution_made++; } } if (substitution_made) { popup_message_always(langcode("POPEM00022"), langcode("POPEM00039")); } (void)remove_trailing_spaces(temp2); temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(path, sizeof(path), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(path); (void)to_upper(path); if(debug_level & 2) fprintf(stderr, "Send message to <%s> from <%s> :%s\n", temp1, mw[ii].to_call_sign, temp2); if ( (strlen(temp1) != 0) // Callsign field is not blank && (strlen(temp2) != 0) // Message field is not blank && (strcmp(temp1,my_callsign) ) ) // And not my own callsign { /* if you're sending a message you must be at the keyboard */ auto_reply=0; XmToggleButtonSetState(auto_msg_toggle,FALSE,FALSE); statusline(langcode("BBARSTA011"),0); // Auto Reply Messages OFF output_message(mw[ii].to_call_sign,temp1,temp2,path); //fprintf(stderr," 1111111111222222222233333333334444444444555555555566666666\n"); //fprintf(stderr,"1234567890123456789012345678901234567890123456789012345678901234567\n"); //fprintf(stderr,"%s\n",temp2); XmTextFieldSetString(mw[ii].message_data_line1,""); if (mw[ii].message_data_line2) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line2,""); } if (mw[ii].message_data_line3) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line3,""); } if (mw[ii].message_data_line4) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line4,""); } // if (mw[ii].message_group!=1) // XtSetSensitive(mw[ii].button_ok,FALSE); // Do message logging if that feature is enabled. if (log_message_data) { char temp_msg[MAX_MESSAGE_LENGTH+1]; strcpy(temp_msg, mw[ii].to_call_sign);// To temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ">"); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, temp1); // From temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ","); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, path); // Path temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ":"); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, temp2); // Message temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_MESSAGE, temp_file_path, sizeof(temp_file_path)), temp_msg ); } } else { if ( strcmp(temp1,my_callsign) == 0 ) // It's my own callsign { popup_message_always(langcode("POPEM00022"), langcode("POPEM00054")); // We're trying to talk to ourselves! } else if ( strlen(temp1) == 0 ) // Callsign field is blank { popup_message_always(langcode("POPEM00022"), langcode("POPEM00052")); // Callsign is EMPTY! } else if ( strlen(temp2) == 0 ) // Message field is blank { popup_message_always(langcode("POPEM00022"), langcode("POPEM00053")); // Message is EMPTY! } } } // Move focus to the first message box to make typing the next // message easier. XmProcessTraversal(mw[ii].message_data_line1, XmTRAVERSE_CURRENT); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_now" ); } void Clear_message_from( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; int i; char *temp_ptr; /* int pos;*/ i=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_from" ); if (mw[i].send_message_dialog) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); /*fprintf(stderr,"Clear message from <%s> to <%s>\n",temp1,my_callsign);*/ mdelete_messages_from(temp1); new_message_data=1; } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_from" ); } void Clear_message_to( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; int i; char *temp_ptr; i=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to" ); if (mw[i].send_message_dialog) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); /*fprintf(stderr,"Clear message to <%s>\n",temp1);*/ mdelete_messages_to(temp1); new_message_data=1; } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to" ); } void Clear_message_to_from( Widget w, XtPointer clientData, XtPointer callData) { int i, pos; Clear_message_to(w, clientData, callData); Clear_message_from(w, clientData, callData); i=atoi((char *)clientData); /* clear window*/ pos=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); if (mw[i].send_message_dialog) { // Known to have memory leaks with some versions of Motif: //XmTextSetString(mw[i].send_message_text,""); // Clear out the message window XmTextReplace(mw[i].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[i].send_message_text), ""); // Set the cursor position to 0 XtVaSetValues(mw[i].send_message_text,XmNcursorPosition,pos,NULL); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); update_messages(1); // Force an update to clear the window begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); } void Kick_timer( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp_ptr; char temp1[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[atoi(clientData)].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); kick_outgoing_timer(temp1); } void Clear_messages_to( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp_ptr; char temp1[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[atoi(clientData)].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); clear_outgoing_messages_to(temp1); update_messages(1); // Force an update to the window } void Send_message_call( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char call[20]; if(clientData != NULL) { xastir_snprintf(call, sizeof(call), "%s", (char *)clientData); Send_message(appshell, call, NULL); } } // These are used for callbacks below so that we have a unique // identifier for the XtRemoveCallback() function to work with. The // last two parameters of an XtAddCallback() or XtRemoveCallback() // must be unique. // void Send_message_now_1( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_2( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_3( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_4( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void build_send_message_input_boxes(int i, int hamhud, int d700, int d7) { //fprintf(stderr, "\n build: i:%d hamhud:%d d700:%d d7:%d\n", i, hamhud, d700, d7); // Skip most of these sections and go to the default section if // using LSB. We have problems with Lesstif segfaulting on us // otherwise. #ifndef NO_DYNAMIC_WIDGETS // HamHUD mode (Here we're assuming the 4x20 LCD in the HamHUD-II) if (hamhud) { // Draw a textfield widget of size 20 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // HamHUD will display all 67 chars, but only stores the first 20, // therefore if you want the recipient to be able to look at it // later, only send them 20 chars per message. /* // Draw another textfield widget of size 47 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 43, XmNwidth, ((43*7)), XmNmaxLength, 47, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); */ } // D700A mode else if (d700) { // Draw a textfield widget of size 22 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 22, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw another textfield widget of size 22 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 22, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw another textfield widget of size 20 mw[i].message_data_line3 = XtVaCreateManagedWidget("Send_message line3", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 21, XmNwidth, ((21*7)), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line2, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } // D7A/D7E Mode else if (d7) { // Draw a textfield widget of size 12 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw a textfield widget of size 12 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Separate the next two from the previous two for a bit, to help // indicate that the first two are one screen on a TH-D7, the next // two are another screen. // Draw a textfield widget of size 12 mw[i].message_data_line3 = XtVaCreateManagedWidget("Send_message line3", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line2, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw a textfield widget of size 9 mw[i].message_data_line4 = XtVaCreateManagedWidget("Send_message line4", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNwidth, ((10*7)+0), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line3, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } // Standard APRS Mode else // Standard APRS message box size (67) #endif // NO_DYNAMIC_WIDGETS { mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 67, XmNwidth, ((65*7)+2), XmNmaxLength, 67, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } //fprintf(stderr,"Starting to add callbacks\n"); if (mw[i].message_data_line1) // If exists, add another callback { XtAddCallback(mw[i].message_data_line1, XmNactivateCallback, Send_message_now_1, (XtPointer)mw[i].win); } if (mw[i].message_data_line2) // If exists, add another callback { XtAddCallback(mw[i].message_data_line2, XmNactivateCallback, Send_message_now_2, (XtPointer)mw[i].win); } if (mw[i].message_data_line3) // If exists, add another callback { XtAddCallback(mw[i].message_data_line3, XmNactivateCallback, Send_message_now_3, (XtPointer)mw[i].win); } if (mw[i].message_data_line4) // If exists, add another callback { XtAddCallback(mw[i].message_data_line4, XmNactivateCallback, Send_message_now_4, (XtPointer)mw[i].win); } //fprintf(stderr,"Exiting build_send_message_input_boxes()\n"); } void rebuild_send_message_input_boxes(int ii, int hamhud, int d700, int d7) { //fprintf(stderr, "\nrebuild: ii:%d hamhud:%d d700:%d d7:%d\n", ii, hamhud, d700, d7); // Lesstif appears to have a problem with removing/adding widgets to // a dialog that's already been created and will segfault in this // case. In order to make LSB-Xastir more reliable we disable the // dynamically-created widget code here and stick with the default // setup (one long TextField widget for input). // // Perhaps we need to do a Lesstif detect and do the same thing // anytime Lesstif is used as well? #ifndef NO_DYNAMIC_WIDGETS // Remove the current message widgets if (mw[ii].message_data_line4) { XtDestroyWidget(mw[ii].message_data_line4); } if (mw[ii].message_data_line3) { XtDestroyWidget(mw[ii].message_data_line3); } if (mw[ii].message_data_line2) { XtDestroyWidget(mw[ii].message_data_line2); } if (mw[ii].message_data_line1) { XtDestroyWidget(mw[ii].message_data_line1); } mw[ii].message_data_line1 = (Widget)NULL; mw[ii].message_data_line2 = (Widget)NULL; mw[ii].message_data_line3 = (Widget)NULL; mw[ii].message_data_line4 = (Widget)NULL; // Build the new boxes build_send_message_input_boxes(ii, hamhud, d700, d7); #endif // NO_DYNAMIC_WIDGETS } void HamHUD_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii =(intptr_t)clientData; int hamhud; hamhud = XmToggleButtonGetState(mw[ii].HamHUD_mode); if (hamhud) { XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, hamhud, 0, 0); } void D700_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii = (intptr_t)clientData; int d700; d700 = XmToggleButtonGetState(mw[ii].D700_mode); if (d700) { XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, 0, d700, 0); } void D7_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii = (intptr_t)clientData; int d7; d7 = XmToggleButtonGetState(mw[ii].D7_mode); if (d7) { XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, 0, 0, d7); } // Select HamHUD/D7/D700/Normal APRS messaging based on info // available in the station record. Change the Send Message dialog // to match. // // Only call this when the Send Message dialog is first constructed // or when we hit the New/Refresh Call button. We don't want to // have the user fighting against this function every sent or // received packet if this function happens to guess wrong. // void select_station_type(int ii) { DataRow *p_station; char call_sign[MAX_CALLSIGN+1]; char *temp_ptr; if (mw[ii].send_message_call_data == NULL) { fprintf(stderr,"messages_gui.c:select_station_type():mw[ii].send_message_call_data is NULL\n"); return; } temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(call_sign, sizeof(call_sign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(call_sign); (void)to_upper(call_sign); // We have the callsign. See if we have the station name in our // database. if (call_sign[0] != '\0' && search_station_name(&p_station, call_sign, 1) ) // Exact match { int hamhud = 0; int d700 = 0; int d7 = 0; // int tx_only = 0; //fprintf(stderr,"Found callsign: %s\n", call_sign); // check if station appears to be a transmit only station such as the TinyTrak and OpenTrak trackers. // ********* wrong test ********** //if (p_station->aprs_symbol != NULL) { // if (p_station->aprs_symbol.aprs_type != NULL) { // fprintf(stderr,"Has Type: %s\n", p_station->aprs_symbol.aprs_type); // if is_tx_only(p_station) { // tx_only++; // } // } //} // Check first two comment records, if they exist if (p_station->comment_data != NULL) { // Check first comment record if (strstr(p_station->comment_data->text_ptr,"TM-D700")) { d700++; } else if (strstr(p_station->comment_data->text_ptr,"TH-D7")) { d7++; } else if (p_station->comment_data->next) { // Check second comment record if (strstr(p_station->comment_data->next->text_ptr,"TM-D700")) { d700++; } else if (strstr(p_station->comment_data->next->text_ptr,"TH-D7")) { d7++; } } } // If not D700 or D7, check for HamHUD in the TOCALL. // APHH2/APRHH2. We'll skip the version number so-as to // catch future versions as well. // if (!d700 && !d7) { if (p_station->node_path_ptr) { if (strncmp(p_station->node_path_ptr,"APRHH",5) == 0 || strncmp(p_station->node_path_ptr,"APHH",4) == 0) { hamhud++; } } } if (hamhud) { // fprintf(stderr,"HamHUD found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,TRUE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, hamhud, 0, 0); } else if (d700) { // fprintf(stderr,"D700 found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,TRUE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, 0, d700, 0); } else if (d7) { // fprintf(stderr,"D7 found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,TRUE,FALSE); rebuild_send_message_input_boxes(ii, 0, 0, d7); } else { // fprintf(stderr,"Standard APRS found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, 0, 0, d7); } } } // The main Send Message dialog. db.c:update_messages() is the // function which fills in the message history information. // // The underlying code has been tweaked so that we can pass an EMPTY // path all the way down through the layers. We defined special // strings for that and for setting default paths, and display these // to the user in this and the Change Path dialogs: // // "DEFAULT PATH" // "DIRECT PATH" // // A note from Jim Fuller, N7VR: // // "I just set a test setup to my TH-D7GA. First Display shows // two lines 12 characters each, with the a third line of 12 // character and fourth line of 9 characters on the second display // by pressing ok. This means 45 characters for max message. // // On my D-700, main first display is like the TH-D7GA. But when // I go to the message display it displays three lines. The first // two are 22 characters and the last is 20 characters. This // means 64 characters total. // // I would only send a 24 character message to field troops, based // on first read capability." // // void Send_message( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { Arg args[50]; char temp[60]; unsigned int n; int j; intptr_t i; char group[MAX_CALLSIGN+1]; int groupon; int box_len; Atom delw; //fprintf(stderr,"\n1Send_message\n"); groupon=0; box_len=105; i=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message" ); for(j=0; j key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(mw[i].send_message_dialog); XmProcessTraversal(mw[i].button_cancel, XmTRAVERSE_CURRENT); } //fprintf(stderr,"2calling select_station_type()\n"); // Re-arrange the outgoing message boxes based on the type of // device we're talking to. select_station_type(i); //fprintf(stderr,"2returned from select_station_type()\n"); //fprintf(stderr,"1end of Send_message()\n"); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message" ); } // Bring up a Send Message dialog for each QSO that has pending // outbound messages. // void Show_pending_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { intptr_t ii; int msgs_found = 0; // Look through the outgoing message queue. Find all callsigns // that we're currently trying to send messages to. // for (ii = 0; ii < MAX_OUTGOING_MESSAGES; ii++) { // If it matches the callsign we're talking to if (message_pool[ii].active==MESSAGE_ACTIVE) { msgs_found++; // Bring up a Send Message box for each callsign found. Send_message_call(NULL, message_pool[ii].to_call_sign, NULL); // Fill in the old data in case it doesn't auto-fill Check_new_call_messages(NULL, (XtPointer)ii, NULL); } } if (msgs_found == 0) { fprintf(stderr, "No Pending Messages.\n"); } } /************************* Auto msg **************************************/ /*************************************************************************/ void Auto_msg_option( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int item_no = XTPOINTER_TO_INT(clientData); if (item_no) { auto_reply = 1; } else { auto_reply = 0; } } void Auto_msg_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_destroy_shell" ); XtDestroyWidget(shell); auto_msg_dialog = (Widget)NULL; end_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_destroy_shell" ); } void Auto_msg_set_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[110]; char *temp_ptr; temp_ptr = XmTextFieldGetString(auto_msg_set_data); substr(temp, temp_ptr, 99); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); memcpy(auto_reply_message, temp, sizeof(auto_reply_message)); auto_reply_message[sizeof(auto_reply_message)-1] = '\0'; // Terminate string Auto_msg_destroy_shell(w, clientData, callData); } void Auto_msg_set( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, reply; Atom delw; begin_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_set" ); if(!auto_msg_dialog) { auto_msg_dialog = XtVaCreatePopupShell(langcode("WPUPARM001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Auto_msg_set pane", xmPanedWindowWidgetClass, auto_msg_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Auto_msg_set my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); reply = XtVaCreateManagedWidget(langcode("WPUPARM002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); auto_msg_set_data = XtVaCreateManagedWidget("Auto_msg_set auto_msg_set_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 100, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, reply, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_msg_set_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_msg_set_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Auto_msg_set_now, auto_msg_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Auto_msg_destroy_shell, auto_msg_dialog); pos_dialog(auto_msg_dialog); delw = XmInternAtom(XtDisplay(auto_msg_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(auto_msg_dialog, delw, Auto_msg_destroy_shell, (XtPointer)auto_msg_dialog); XmTextFieldSetString(auto_msg_set_data,auto_reply_message); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, auto_msg_dialog); XtPopup(auto_msg_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(auto_msg_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(auto_msg_dialog), XtWindow(auto_msg_dialog)); } end_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_set" ); } Xastir-Release-2.2.2/src/objects.c000066400000000000000000015311731501463444000167450ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "draw_symbols.h" #include "main.h" #include "xa_config.h" #include "maps.h" #include "interface.h" #include "objects.h" void move_station_time(DataRow *p_curr, DataRow *p_time); #include #include // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX // ---------------------------- object ------------------------------- Widget object_dialog = (Widget)NULL; Widget df_object_dialog = (Widget)NULL; Widget object_name_data, object_lat_data_deg, object_lat_data_min, object_lat_data_ns, object_lon_data_deg, object_lon_data_min, object_lon_data_ew, object_group_data, object_symbol_data, object_icon, object_comment_data, ob_frame, ob_group, ob_symbol, ob_option_frame, signpost_frame, area_frame, area_toggle, signpost_toggle, df_bearing_toggle, map_view_toggle, probabilities_toggle, ob_bearing_data, frameomni, framebeam, ob_speed, ob_speed_data, ob_course, ob_course_data, ob_comment, ob_altitude, ob_altitude_data, signpost_data, probability_data_min, probability_data_max, open_filled_toggle, ob_lat_offset_data, ob_lon_offset_data, ob_corridor, ob_corridor_data, ob_corridor_miles, omni_antenna_toggle, beam_antenna_toggle; Pixmap Ob_icon0, Ob_icon; void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata); // Array to hold predefined objects to display on Create/Move popup menu. predefinedObject predefinedObjects[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; void Populate_predefined_objects(predefinedObject *predefinedObjects); int number_of_predefined_objects; char predefined_object_definition_filename[256] = "predefined_SAR.sys"; int predefined_menu_from_file = 0; int Area_object_enabled = 0; int Map_View_object_enabled = 0; int Area_type = 0; char Area_color[3] = "/0"; int Area_bright = 0; int Area_filled = 0; int Signpost_object_enabled = 0; int Probability_circles_enabled = 0; int DF_object_enabled = 0; int Omni_antenna_enabled = 0; int Beam_antenna_enabled = 0; char object_shgd[5] = "0000\0"; char object_NRQ[4] = "960\0"; XtPointer global_parameter1 = (XtPointer)NULL; XtPointer global_parameter2 = (XtPointer)NULL; int polygon_last_x = -1; // Draw CAD Objects functions int polygon_last_y = -1; // Draw CAD Objects functions int doing_move_operation = 0; Widget draw_CAD_objects_dialog = (Widget)NULL; Widget cad_dialog = (Widget)NULL; Widget cad_label_data, cad_comment_data, cad_probability_data, cad_line_style_data; // Values entered in the cad_dialog int draw_CAD_objects_flag = 0; void Draw_All_CAD_Objects(Widget w); void Save_CAD_Objects_to_file(void); Widget cad_erase_dialog; Widget list_of_existing_CAD_objects = (Widget)NULL; Widget cad_list_dialog = (Widget)NULL; Widget list_of_existing_CAD_objects_edit = (Widget)NULL; void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description); void Update_CAD_objects_list_dialog(void); void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent); int CAD_draw_objects = TRUE; int CAD_show_label = TRUE; int CAD_show_raw_probability = TRUE; int CAD_show_comment = TRUE; int CAD_show_area = TRUE; void Draw_CAD_Objects_erase_dialog_close(Widget w, XtPointer clientData, XtPointer callData); void Draw_CAD_Objects_list_dialog_close(Widget w, XtPointer clientData, XtPointer callData); #ifndef USE_COMBO_BOX int clsd_value; // replacement value for cad line type combo box #endif // !USE_COMBO_BOX //////////////////////////////////////////////////////////////////////////////////////////////////// // Init values for Objects dialog char last_object[9+1]; char last_obj_grp; char last_obj_sym; char last_obj_overlay; char last_obj_comment[34+1]; ///////////////////////////////////////////////////////////////////////// /* * Check for a valid object name */ int valid_object(char *name) { int len, i; // max 9 printable ASCII characters, case sensitive [APRS // Reference] len = (int)strlen(name); if (len > 9 || len == 0) { return(0); // wrong size } for (i=0; i 9 || len < 3) { return(0); // Wrong size } for (i=0; icall_sign); //(void)to_upper(p_station->call_sign); Not per spec. Don't //use this. if ((p_station->flag & ST_OBJECT) != 0) // We have an object { if (!valid_object(p_station->call_sign)) { line[0] = '\0'; return(0); } } else if ((p_station->flag & ST_ITEM) != 0) // We have an item { xastir_snprintf(tempstr, sizeof(tempstr), "%s", p_station->call_sign); if (strlen(tempstr) == 1) // Add two spaces (to make 3 minimum chars) { strcpy(p_station->call_sign, tempstr); p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0'; // Terminate string strcat(p_station->call_sign, " "); p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0'; // Terminate string } else if (strlen(tempstr) == 2) // Add one space (to make 3 minimum chars) { strcpy(p_station->call_sign, tempstr); p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0'; // Terminate string strcat(p_station->call_sign, " "); p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0'; // Terminate string } if (!valid_item(p_station->call_sign)) { line[0] = '\0'; return(0); } } else // Not an item or an object, what are we doing here! { line[0] = '\0'; return(0); } // Lat/lon are in Xastir coordinates, so we need to convert // them to APRS string format here. convert_lat_l2s(p_station->coord_lat, lat_str, sizeof(lat_str), CONVERT_LP_NOSP); convert_lon_l2s(p_station->coord_lon, lon_str, sizeof(lon_str), CONVERT_LP_NOSP); // Check for an overlay character. Replace the group character // (table char) with the overlay if present. if (p_station->aprs_symbol.special_overlay != '\0') { // Overlay character found object_group = p_station->aprs_symbol.special_overlay; if ( (object_group >= '0' && object_group <= '9') || (object_group >= 'A' && object_group <= 'Z') ) { // Valid overlay character, use what we have } else { // Bad overlay character, throw it away object_group = '\\'; } } else // No overlay character { object_group = p_station->aprs_symbol.aprs_type; } object_symbol = p_station->aprs_symbol.aprs_symbol; // In this case we grab only the first comment field (if it // exists) for the object/item if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { xastir_snprintf(comment, sizeof(comment), "%s", p_station->comment_data->text_ptr); } else { comment[0] = '\0'; // Empty string } if ( (p_station->probability_min[0] != '\0') || (p_station->probability_max[0] != '\0') ) { if (p_station->probability_max[0] == '\0') { // Only have probability_min strcpy(comment2, "Pmin"); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, p_station->probability_min); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, ","); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, comment); comment2[sizeof(comment2)-1] = '\0'; // Terminate string } else if (p_station->probability_min[0] == '\0') { // Only have probability_max strcpy(comment2, "Pmax"); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, p_station->probability_max); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, ","); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, comment); comment2[sizeof(comment2)-1] = '\0'; // Terminate string } else // Have both { strcpy(comment2, "Pmin"); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, p_station->probability_min); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, ",Pmax"); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, p_station->probability_max); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, ","); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, comment); comment2[sizeof(comment2)-1] = '\0'; // Terminate string } xastir_snprintf(comment,sizeof(comment), "%s", comment2); } // Put RNG or PHG at the beginning of the comment strcpy(comment2, p_station->power_gain); comment2[sizeof(comment2)-1] = '\0'; // Terminate string strcat(comment2, comment); comment2[sizeof(comment2)-1] = '\0'; // Terminate string xastir_snprintf(comment, sizeof(comment), "%s", comment2); (void)remove_trailing_spaces(comment); // This is for objects only, not items. Uses current time but // should use the transmitted time from the DataRow struct. // Which time field in the struct would that be? Have to find // out // from the extract_?? code. if ((p_station->flag & ST_OBJECT) != 0) { sec = sec_now(); day_time = gmtime(&sec); xastir_snprintf(time, sizeof(time), "%02d%02d%02dz", day_time->tm_mday, day_time->tm_hour, day_time->tm_min); } // Handle Generic Options // Speed/Course Fields xastir_snprintf(speed_course, sizeof(speed_course), ".../"); // Start with invalid-data string course = 0; if (strlen(p_station->course) != 0) // Course was entered { // Need to check for 1 to three digits only, and 001-360 // degrees) temp = atoi(p_station->course); if ( (temp >= 1) && (temp <= 360) ) { xastir_snprintf(speed_course, sizeof(speed_course), "%03d/",temp); course = temp; } else if (temp == 0) // Spec says 001 to 360 degrees... { xastir_snprintf(speed_course, sizeof(speed_course), "360/"); } } speed = 0; if (strlen(p_station->speed) != 0) // Speed was entered (we only handle knots currently) { // Need to check for 1 to three digits, no alpha characters temp = atoi(p_station->speed); if ( (temp >= 0) && (temp <= 999) ) { long x_long, y_lat; xastir_snprintf(tempstr, sizeof(tempstr), "%03d",temp); strncat(speed_course, tempstr, sizeof(speed_course) - 1 - strlen(speed_course)); speed = temp; // Speed is non-zero. Compute the current dead-reckoned // position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); // Lat/lon are in Xastir coordinates, so we need to // convert them to APRS string format here. // convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_LP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_LP_NOSP); //fprintf(stderr,"\t%s %s\n", lat_str, lon_str); } else { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } } else // No speed entered, blank it out { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } if ( (speed_course[0] == '.') && (speed_course[4] == '.') ) { speed_course[0] = '\0'; // No speed or course entered, so blank it } if (p_station->aprs_symbol.area_object.type != AREA_NONE) // It's an area object { speed_course[0] = '\0'; // Course/Speed not allowed if Area Object } // Altitude Field altitude[0] = '\0'; // Start with empty string if (strlen(p_station->altitude) != 0) // Altitude was entered (we only handle feet currently) { // Need to check for all digits, and 1 to 6 digits if (isdigit((int)p_station->altitude[0])) { // Must convert from meters to feet before transmitting temp2 = (int)( (atof(p_station->altitude) / 0.3048) + 0.5); if ( (temp2 >= 0) && (temp2 <= 99999l) ) { char temp_alt[20]; xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld",temp2); memcpy(altitude, temp_alt, sizeof(altitude) - 1); altitude[sizeof(altitude)-1] = '\0'; // Terminate string } } } // Handle Specific Options // Area Objects if (p_station->aprs_symbol.area_object.type != AREA_NONE) // It's an area object { // Note that transmitted color consists of two characters, // from "/0" to "15" xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02d", p_station->aprs_symbol.area_object.color); if (complete_area_color[0] == '0') { complete_area_color[0] = '/'; } complete_area_type = p_station->aprs_symbol.area_object.type; lat_offset = p_station->aprs_symbol.area_object.sqrt_lat_off; lon_offset = p_station->aprs_symbol.area_object.sqrt_lon_off; // Corridor complete_corridor[0] = '\0'; if ( (complete_area_type == 1) || (complete_area_type == 6)) { if (p_station->aprs_symbol.area_object.corridor_width > 0) { char temp_corridor[10]; xastir_snprintf(temp_corridor, sizeof(temp_corridor), "{%d}", p_station->aprs_symbol.area_object.corridor_width); memcpy(complete_corridor, temp_corridor, sizeof(complete_corridor) - 1); complete_corridor[sizeof(complete_corridor)-1] = '\0'; // Terminate string } } if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ";%-9s*%s%s%1d%02d%2s%02d%s%s%s", p_station->call_sign, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); } else // Non-compressed posit object { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%1d%02d%2s%02d%s%s%s", p_station->call_sign, time, lat_str, object_group, lon_str, object_symbol, complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); } } else // It's an item { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ")%s!%s%1d%02d%2s%02d%s%s%s", p_station->call_sign, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); } else // Non-compressed item { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%1d%02d%2s%02d%s%s%s", p_station->call_sign, lat_str, object_group, lon_str, object_symbol, complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); } } } else if ( (p_station->aprs_symbol.aprs_type == '\\') // We have a signpost object && (p_station->aprs_symbol.aprs_symbol == 'm' ) ) { if (strlen(p_station->signpost) > 0) { char temp_sign[10]; xastir_snprintf(temp_sign, sizeof(temp_sign), "{%s}", p_station->signpost); memcpy(signpost, temp_sign, sizeof(signpost)); signpost[sizeof(signpost)-1] = '\0'; // Terminate string } else // No signpost data entered, blank it out { signpost[0] = '\0'; } if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ";%-9s*%s%s%s%s", p_station->call_sign, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude, signpost); } else // Non-compressed posit object { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s%s", p_station->call_sign, time, lat_str, object_group, lon_str, object_symbol, speed_course, altitude, signpost); } } else // It's an item { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ")%s!%s%s%s", p_station->call_sign, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude, signpost); } else // Non-compressed item { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s%s", p_station->call_sign, lat_str, object_group, lon_str, object_symbol, speed_course, altitude, signpost); } } } else if (p_station->signal_gain[0] != '\0') // Must be an Omni-DF object/item { if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ";%-9s*%s%s%s/%s%s", p_station->call_sign, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank p_station->signal_gain, speed_course, altitude); } else // Non-compressed posit object { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%s%s", p_station->call_sign, time, lat_str, object_group, lon_str, object_symbol, p_station->signal_gain, speed_course, altitude); } } else // It's an item { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ")%s!%s%s/%s%s", p_station->call_sign, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank p_station->signal_gain, speed_course, altitude); } else // Non-compressed item { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%s%s", p_station->call_sign, lat_str, object_group, lon_str, object_symbol, p_station->signal_gain, speed_course, altitude); } } } else if (p_station->NRQ[0] != 0) // It's a Beam Heading DFS object/item { if (strlen(speed_course) != 7) xastir_snprintf(speed_course, sizeof(speed_course), "000/000"); bearing = atoi(p_station->bearing); if ( (bearing < 1) || (bearing > 360) ) { bearing = 360; } if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ";%-9s*%s%s/%03i/%s%s", p_station->call_sign, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank bearing, p_station->NRQ, altitude); } else // Non-compressed posit object { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%03i/%s%s", p_station->call_sign, time, lat_str, object_group, lon_str, object_symbol, speed_course, bearing, p_station->NRQ, altitude); } } else // It's an item { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ")%s!%s/%03i/%s%s", p_station->call_sign, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank bearing, p_station->NRQ, altitude); } else // Non-compressed item { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%03i/%s%s", p_station->call_sign, lat_str, object_group, lon_str, object_symbol, speed_course, bearing, p_station->NRQ, altitude); } } } else // Else it's a normal object/item { if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ";%-9s*%s%s%s", p_station->call_sign, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude); } else // Non-compressed posit object { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s", p_station->call_sign, time, lat_str, object_group, lon_str, object_symbol, speed_course, altitude); } } else // It's an item { if (transmit_compressed_objects_items) { char temp_group = object_group; long x_long, y_lat; // If we have a numeric overlay, we need to convert // it to 'a-j' for compressed objects. if (temp_group >= '0' && temp_group <= '9') { temp_group = temp_group + 'a'; } if (speed == 0) { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } else { // Speed is non-zero. Compute the current // dead-reckoned position and use that instead. compute_current_DR_position(p_station, &x_long, &y_lat); } // We need higher precision lat/lon strings than // those created above. convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); xastir_snprintf(line, line_length, ")%s!%s%s", p_station->call_sign, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude); } else // Non-compressed item { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s", p_station->call_sign, lat_str, object_group, lon_str, object_symbol, speed_course, altitude); } } } // If it's a "killed" object, change '*' to an '_' if ((p_station->flag & ST_OBJECT) != 0) // It's an object { if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE) // It's been killed { line[10] = '_'; killed++; } } // If it's a "killed" item, change '!' to an '_' else // It's an item { if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE) // It's been killed { killed++; done = 0; i = 0; while ( (!done) && (i < 11) ) { if (line[i] == '!') { line[i] = '_'; // mark as deleted object done++; // Exit from loop } i++; } } } // Check whether we need to stop transmitting particular killed // object/items now. if (killed) { // Check whether we should decrement the object_retransmit // counter so that we will eventually stop sending this // object/item. if (p_station->object_retransmit == 0) { // We shouldn't be transmitting this killed object/item // anymore. We're already done transmitting it. //fprintf(stderr, "Done transmitting this object: %s, %d\n", //p_station->call_sign, //p_station->object_retransmit); return(0); } // Check whether the timeout has been set yet on this killed // object/item. If not, change it from -1 (continuous // transmit of non-killed objects) to // MAX_KILLED_OBJECT_RETRANSMIT. if (p_station->object_retransmit <= -1) { //fprintf(stderr, "Killed object %s, setting retries, %d -> %d\n", //p_station->call_sign, //p_station->object_retransmit, //MAX_KILLED_OBJECT_RETRANSMIT - 1); if ((MAX_KILLED_OBJECT_RETRANSMIT - 1) < 0) { p_station->object_retransmit = 0; return(0); // No retransmits desired } else { p_station->object_retransmit = MAX_KILLED_OBJECT_RETRANSMIT - 1; } } else { // Decrement the timeout if it is a positive number. if (p_station->object_retransmit > 0) { //fprintf(stderr, "Killed object %s, decrementing retries, %d -> //%d\n", //p_station->call_sign, //p_station->object_retransmit, //p_station->object_retransmit - 1); p_station->object_retransmit--; } } } // We need to tack the comment on the end, but need to make // sure we don't go over the maximum length for an object/item. if (strlen(comment) != 0) { temp = 0; if ((p_station->flag & ST_OBJECT) != 0) { while ( (strlen(line) < 80) && (temp < (int)strlen(comment)) ) { //fprintf(stderr,"temp: %d->%d\t%c\n", temp, //strlen(line), comment[temp]); line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; } } else // It's an item { while ( (strlen(line) < (64 + strlen(p_station->call_sign))) && (temp < (int)strlen(comment)) ) { //fprintf(stderr,"temp: %d->%d\t%c\n", temp, //strlen(line), comment[temp]); line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; } } } //fprintf(stderr,"line: %s\n",line); // NOTE: Compressed mode will be shorter still. Account // for that when compressed mode is implemented for objects/items. return(1); } // check_and_transmit_objects_items // // This function checks the last_transmit_time for each // locally-owned object/item. If it has been at least the // transmit_time_increment since the last transmit, the increment is // doubled and the object/item transmitted. // // Killed objects/items are transmitted for // MAX_KILLED_OBJECT_RETRANSMIT times and then transmitting of those // objects ceases. // // This would be a good place to implement auto-expiration of // objects that's been discussed on the mailing lists. // // This function depends on the local loopback that is in // interface.c. If we don't hear & decode our own packets, we won't // have our own objects/items in our list. // // We need to check DataRow objects for ST_OBJECT or ST_ITEM types // that were transmitted by our callsign & SSID. We might also need // to modify the remove_time() and check_station_remove functions in // order not to delete our own objects/items too quickly. // // insert_time/remove_time/next_station_time/prev_station_time // // It would be nice if the create/modify object dialog and this // routine went // through the same functions to create the transmitted packets: // objects.c:Setup_object_data // objects.c:Setup_item_data // Unfortunately those routines snag their data directly from the // dialog. // In order to make them use the same code we'd have to separate out // the // fetch-from-dialog code from the create-transmit-packet code. // // This is what aprsDOS does, from Bob's APRS.TXT file: "a // fundamental precept is that old data is less important than new // data." "Each new packet is transmitted immediately, then 20 // seconds later. After every transmission, the period is doubled. // After 20 minutes only six packets have been transmitted. From // then on the rate remains at 10 minutes times the number of // digipeater hops you are using." // Actually, talking to Bob, he's used a period of 15 seconds as his // base unit. We now do the same using the OBJECT_CHECK_RATE define // to set the initial timing. // // Added these to database.h:DataRow struct: // time_t last_transmit_time; // Time we last transmitted // an object/item. Used to // // implement decaying // transmit time algorithm // short transmit_time_increment; // Seconds to add to transmit // next time around. Used // // to implement decaying // transmit time algorithm // // The earlier code here transmitted objects/items at a specified // rate. This can cause large transmissions every OBJECT_rate // seconds, as all objects/items are transmitted at once. With the // new code, the objects/items may be spaced a bit from each other // time-wise, plus they are transmitted less and less often with // each transmission until they hit the max interval specified by // the "Object/Item TX Interval" slider. When they hit that max // interval, they are transmitted at the constant interval until // killed. When they are killed, they are transmitted for // MAX_KILLED_OBJECT_RETRANSMIT iterations using the decaying // algorithm, then transmissions cease. // void check_and_transmit_objects_items(time_t time) { DataRow *p_station; // pointer to station data char line[256]; int first = 1; // Used to output debug message only once int increment; // Time to re-transmit objects/items? // Check every OBJECT_CHECK_RATE seconds - 20%. No faster else // we'll be running through the station list too often and // wasting cycles. if (time < (last_object_check + (int)(4.0 * OBJECT_CHECK_RATE/5.0 + 1.0) ) ) { return; } //fprintf(stderr,"check_and_transmit_objects_items\n"); // Set up timer for next go-around last_object_check = time; if (debug_level & 1) { fprintf(stderr,"Checking whether to retransmit any objects/items\n"); } // We could speed things up quite a bit here by either keeping a // separate list of our own objects/items, or going through the list // of stations by time instead of by name (If by time, only check // backwards from the current time by the max transmit interval plus // some increment. Watch out for the user changing the slider). for (p_station = n_first; p_station != NULL; p_station = p_station->n_next) { //fprintf(stderr,"%s\t%s\n",p_station->call_sign,p_station->origin); // If station is owned by me (Exact match includes SSID) // if (is_my_call(p_station->origin,1)) { // and it's an object or item if ((p_station->flag & (ST_OBJECT|ST_ITEM)) && is_my_object_item(p_station)) { long x_long_save, y_lat_save; // If dead-reckoning, we need to send out a new // position for this object instead of just // overwriting the old position, which will cause // the track to skip. Here we save the old position // away so we can save it back to the record later. // x_long_save = p_station->coord_lon; y_lat_save = p_station->coord_lat; if (debug_level & 1) { fprintf(stderr, "Found a locally-owned object or item: %s\n", p_station->call_sign); } // Call the DR function to compute a new lat/long // and change the object's lat/long to match so that // we move the object along each time we transmit // it. // // WE7U // Here we should log the new position to file if it's not done // automatically. // if (p_station->speed[0] != '\0') { long x_long, y_lat; compute_current_DR_position(p_station, &x_long, &y_lat); // Put the new position into the record // temporarily so that we can p_station->coord_lon = x_long; p_station->coord_lat = y_lat; } // Keep the timestamp current on my own // objects/items so they don't expire. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // Implementing sped-up transmission of new objects, regular // transmission of old objects (decaying algorithm). We'll do this // by keeping a last_transmit_time variable and a // transmit_time_increment with each DataRow struct. If the // last_transmit_time is older than the transmit_time_increment, we // transmit the object and double the increment variable, until we // hit the OBJECT_rate limit for the increment. This will make // newer objects/items transmit more often, and will also space out // the transmissions of old objects so they're not transmitted all // at once in a group. Each time a new object/item is created that // is owned by us, it needs to have it's timer set to 20 (seconds). // If an object/item is touched, it needs to again be set to 20 // seconds. /////////////////////////////////// // Run through the station list. // Transmit any objects/items that have equalled or gone past // (last_transmit_time + transmit_time_increment). Update the // last_transmit_time to current time. // // Double the transmit_time_increment. If it has gone beyond // OBJECT_rate, set it to OBJECT_rate instead. // /////////////////////////////////// // Check for the case where the timing slider has // been reduced and the expire time is too long. // Reset it to the current max expire time so that // it'll get transmitted more quickly. if (p_station->transmit_time_increment > OBJECT_rate) { p_station->transmit_time_increment = OBJECT_rate; } increment = p_station->transmit_time_increment; if ( ( p_station->last_transmit_time + increment) <= time ) { // We should transmit this object/item as it has // hit its transmit interval. float randomize; int one_fifth_increment; int new_increment; if (first && !object_tx_disable) // "Transmitting objects/items" { statusline(langcode("BBARSTA042"),1); first = 0; } // Set up the new doubling increment increment = increment * 2; if (increment > OBJECT_rate) { increment = OBJECT_rate; } // Randomize the distribution a bit, so that all // objects are not transmitted at the same time. // Allow the random number to vary over 20% // (one-fifth) of the newly computed increment. one_fifth_increment = (int)((increment / 5) + 0.5); //fprintf(stderr,"one_fifth_increment: %d\n", one_fifth_increment); // Scale the random number from 0.0 to 1.0. // Must convert at least one of the numbers to a // float else randomize will be zero every time. randomize = rand() / (float)RAND_MAX; //fprintf(stderr,"randomize: %f\n", randomize); // Scale it to the range we want (0% to 20% of // the interval) randomize = randomize * one_fifth_increment; //fprintf(stderr,"scaled randomize: %f\n", randomize); // Subtract it from the increment, use // poor-man's rounding to turn the random number // into an int (so we get the full range). new_increment = increment - (int)(randomize + 0.5); p_station->transmit_time_increment = (short)new_increment; //fprintf(stderr,"check_and_transmit_objects_items():Setting //tx_increment to %d:%s\n", // new_increment, // p_station->call_sign); // Set the last transmit time into the object. // Keep this based off the time the object was // last created/modified/deleted, so that we // don't end up with a bunch of them transmitted // together. p_station->last_transmit_time = p_station->last_transmit_time + new_increment; // Here we need to re-assemble and re-transmit // the object or item // Check whether it is a "live" or "killed" // object and vary the // number of retransmits accordingly. Actually // we should be able // to keep retransmitting "killed" objects until // they expire out of // our station queue with no problems. If // someone wants to ressurect // the object we'll get new info into our struct // and this function will // ignore that object from then on, unless we // again snatch control of // the object. // if signpost, area object, df object, or // generic object // check p_station->APRS_Symbol->aprs_type: // APRS_OBJECT // APRS_ITEM // APRS_DF (looks like I didn't use this one // when I implemented DF objects) // Whether area, df, signpost. // Check ->signpost for signpost data. Check // ->df_color also. // call_sign, sec_heard, coord_lon, coord_lat, // packet_time, origin, // aprs_symbol, pos_time, altitude, speed, // course, bearing, NRQ, // power_gain, signal_gain, signpost, // station_time, station_time_type, // comments, df_color if (Create_object_item_tx_string(p_station, line, sizeof(line)) ) { // Restore the original lat/long before we // transmit the (possibly) new position. // p_station->coord_lon = x_long_save; p_station->coord_lat = y_lat_save; //fprintf(stderr,"Transmitting: %s\n",line); // Attempt to transmit the object/item again if (object_tx_disable || transmit_disable) // Send to loopback only { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else // Send to all active tx-enabled interfaces { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } else { //fprintf(stderr,"Create_object_item_tx_string returned a 0\n"); // Don't transmit it. } } else // Not time to transmit it yet { //fprintf(stderr,"Not time to TX yet: //%s\t%s\t",p_station->call_sign,p_station->origin); //fprintf(stderr, "%ld secs to go\n", p_station->last_transmit_time //+ increment - time ); } } } //fprintf(stderr,"Exiting check_and_transmit_objects_items\n"); } //////////////////// Draw CAD Objects Functions //////////////////// //#define CAD_DEBUG // Allocate a new vertice along the polygon. If the vertice is very // close to the first vertice, ask the operator if they wish to // close the polygon. If closing, ask for a raw probability? // // As each vertice is allocated, write it out to file? We'd then // need to edit the file and comment vertices out if we're deleting // vertices in memory. We could also write out an entire object // when we select "Close Polygon". // void CAD_vertice_allocate(long latitude, long longitude) { #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new vertice\n"); #endif // Check whether a line segment will cross another? // We use the CAD_list_head variable, as it will be pointing to // the top of the list, where the current object we're working // on will be placed. Check whether that pointer is NULL // though, just in case. if (CAD_list_head) // We have at least one object defined { VerticeRow *p_new; // Allocate area to hold the vertice p_new = (VerticeRow *)malloc(sizeof(VerticeRow)); if (!p_new) { fprintf(stderr,"Couldn't allocate memory in CAD_vertice_allocate()\n"); return; } p_new->latitude = latitude; p_new->longitude = longitude; // Link it in at the top of the vertice chain. p_new->next = CAD_list_head->start; CAD_list_head->start = p_new; } // Call redraw_symbols outside this function, as // verticies may be allocated both when loading lots of them from a file // and when the user is drawing objects in the user interface // Reload symbols/tracks/CAD objects //redraw_symbols(da); } // Allocate a struct for a new object and add one vertice to it. // When do we name it and place the label? Assign probability to // it? We should keep a pointer to the current polygon we're // working on, so that we can modify it easily as we draw. // Actually, it'll be pointed to by CAD_list_head, so we already // have it! // // As each object is allocated, write it out to file? // // Compute a default label of date/time? // void CAD_object_allocate(long latitude, long longitude) { CADRow *p_new; #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new CAD object\n"); #endif // Allocate memory and link it to the top of the singly-linked // list of CADRow objects. p_new = (CADRow *)malloc(sizeof(CADRow)); if (!p_new) { fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate()\n"); return; } // Fill in default values p_new->creation_time = sec_now(); p_new->start = NULL; p_new->line_color = colors[0x27]; p_new->line_type = 2; // LineOnOffDash; p_new->line_width = 4; p_new->computed_area = 0; CAD_object_set_raw_probability(p_new,0.0,FALSE); p_new->label_latitude = 0l; p_new->label_longitude = 0l; p_new->label[0] = '\0'; p_new->comment[0] = '\0'; // Allocate area to hold the first vertice #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new vertice\n"); #endif p_new->start = (VerticeRow *)malloc(sizeof(VerticeRow)); if (!p_new->start) { fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate(2)\n"); free(p_new); return; } p_new->start->next = NULL; p_new->start->latitude = latitude; p_new->start->longitude = longitude; // Hook it into the linked list of objects p_new->next = CAD_list_head; CAD_list_head = p_new; /* // // Note: It was too confusing to have these two dialogs close and // get redrawn when we click on the first vertice. The net result // is that we may have two dialogs move on top of the drawing area // to the spot we're trying to draw. Commented out this section due // to that. We'll get the two dialogs updated when we click on // either the DONE or CANCEL button on the Close Polygon dialog. // // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(da, NULL, NULL); Draw_CAD_Objects_erase_dialog(da, NULL, NULL); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(da, NULL, NULL); Draw_CAD_Objects_list_dialog(da, NULL, NULL); } */ } // Delete all vertices associated with a CAD object and free the // memory. We really should pass a pointer to the object here // instead of a vertice, and set the start pointer to NULL when // done. // void CAD_vertice_delete_all(VerticeRow *v) { VerticeRow *tmp; // Call CAD_vertice_delete() for each vertice, then unlink this // CAD object from the linked list and free its memory. // Iterate through each vertice, deleting as we go while (v != NULL) { tmp = v; v = v->next; free(tmp); #ifdef CAD_DEBUG fprintf(stderr,"Free'ing a vertice\n"); #endif } } // Delete _all_ CAD objects and all associated vertices. Loop // through the entire list of CAD objects, calling // CAD_vertice_delete_all() and then free'ing the CAD object. When // done, set the start pointer to NULL. // // We also need to wipe the persistent CAD object file. // void CAD_object_delete_all(void) { CADRow *p = CAD_list_head; CADRow *tmp; while (p != NULL) { VerticeRow *v = p->start; // Remove all of the vertices if (v != NULL) { // Delete/free the vertices CAD_vertice_delete_all(v); } // Remove the object and free its memory tmp = p; p = p->next; free(tmp); #ifdef CAD_DEBUG fprintf(stderr,"Free'ing an object\n"); #endif } // Zero the CAD linked list head CAD_list_head = NULL; } // Remove a vertice, thereby joining two segments into one? // // Recompute the raw probability if need be, or make it an invalid // value so that we know we need to recompute it. // //void CAD_vertice_delete(CADrow *object) { // VerticeRow *v = object->start; // Unlink the vertice from the linked list and free its memory. // Allow removing a vertice in the middle or end of a chain. If // removing the vertice turns the polygon into an open polygon, // alert the user of that fact and ask if they wish to close it. //} /* Test to see if a CAD object of the name (label) provided exists. Parameter: label, the label text to be checked. Returns 0 if no CAD object with a name matching the provided name is found. Returns 1 if a CAD object with a name matching the provided name is found. */ int exists_CAD_object_by_label(char *label) { CADRow *object_pointer = CAD_list_head; int result = 0; // function return value int done = 0; // flag to stop loop when a match is found while (object_pointer != NULL && done==0) { if (strcmp(object_pointer->label,label)==0) { // a matching name was found result = 1; done = 1; } object_pointer = object_pointer->next; } return result; } /* Counts to see how many CAD objects of the name (label) provided exist. Parameter: label, the label text to be checked. Returns 0 if no CAD object with a name matching the provided name is found. Returns count of the number of CAD objects with a matching label if one or more is found. */ int count_CAD_object_with_matching_label(char *label) { CADRow *object_pointer = CAD_list_head; int result = 0; while (object_pointer != NULL) { // iterate through all CAD objects if (strcmp(object_pointer->label,label)==0) { // a matching name was found result++; object_pointer = object_pointer->next; } } return result; } /* Delete one CAD object and all of its vertices. */ void CAD_object_delete(CADRow *object) { CADRow *all_objects_ptr = CAD_list_head; CADRow *previous_object_ptr = CAD_list_head; VerticeRow *v = object->start; int done = 0; #ifdef CAD_DEBUG fprintf(stderr,"Deleting CAD object %s\n",object->label); #endif // check to see if the object we were given was the first object if (object==all_objects_ptr) { #ifdef CAD_DEBUG fprintf(stderr,"Deleting first CAD object %s\n",object->label); #endif CAD_vertice_delete_all(v); // Frees the memory also // Unlink the object from the chain and free the memory. CAD_list_head = object->next; // Unlink free(object); // Free the object memory } else { #ifdef CAD_DEBUG fprintf(stderr,"Deleting other than first CAD object %s\n",object->label); #endif // walk through the list and delete the object when found while (all_objects_ptr != NULL && done==0) { if (object==all_objects_ptr) { v = object->start; CAD_vertice_delete_all(v); previous_object_ptr->next = object->next; free(object); done = 1; } else { all_objects_ptr = all_objects_ptr->next; } } } } // Split an existing CAD object into two objects. Can we trigger // this by drawing a line across a closed polygon? void CAD_object_split_existing(void) { } // Join two existing polygons into one larger polygon. void CAD_object_join_two(void) { } // Move an entire CAD object, with all it's vertices, somewhere // else. Move the label along with it as well. void CAD_object_move(void) { } // Determine if a CAD object is a closed polygon. // // Takes a pointer to a CAD object as an argument. // Returns 1 if the object is closed. // Returns 0 if the object is not closed. // int is_CAD_object_open(CADRow *cad_object) { VerticeRow *vertex_pointer; int vertex_count = 0; int result = 1; int atleast_one_different = 0; long start_lat, start_long; long stop_lat, stop_long; vertex_pointer = cad_object->start; if (vertex_pointer!=NULL) { // greater than zero points, get first point. start_lat = vertex_pointer->latitude; start_long = vertex_pointer->longitude; stop_lat = vertex_pointer->latitude; stop_long = vertex_pointer->longitude; vertex_pointer = vertex_pointer->next; while (vertex_pointer != NULL) { //greater than one point, get current point. stop_lat = vertex_pointer->latitude; stop_long = vertex_pointer->longitude; if (stop_lat!=start_lat || stop_long!=start_long) { atleast_one_different = 1; } vertex_pointer = vertex_pointer->next; vertex_count++; } if (vertex_count>2 && start_lat==stop_lat && start_long==stop_long && atleast_one_different > 0) { // more than two points, and they aren't in the same place result = 0; } } return result; } // Compute the area enclosed by a CAD object. Check that it is a // closed, non-intersecting polygon first. // double CAD_object_compute_area(CADRow *CAD_list_head) { VerticeRow *tmp; double area; char temp_course[20]; // Walk the linked list, computing the area of the // polygon. Greene's Theorem is how we can compute the area of // a polygon using the vertices. We could also compute whether // we're going clockwise or counter-clockwise around the polygon // using Greene's Theorem. In fact I think we do that for // Shapefile hole polygons. Remember that here we're walking // around the vertices backwards due to the ordering of the // list. Shouldn't matter for our purposes though. // area = 0.0; tmp = CAD_list_head->start; if (is_CAD_object_open(CAD_list_head)==0) { // Only compute the area if CAD object is a closed polygon, // that is, not an open polygon. while (tmp->next != NULL) { double dx0, dy0, dx1, dy1; // Because lat/long units can vary drastically w.r.t. real // units, we need to multiply the terms by the real units in // order to get real area. // Compute real distances from a fixed point. Convert to // the current measurement units. We'll use the starting // vertice as our fixed point. // dx0 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, CAD_list_head->start->latitude, tmp->longitude, temp_course, sizeof(temp_course)); if (tmp->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } dy0 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, tmp->latitude, CAD_list_head->start->longitude, temp_course, sizeof(temp_course)); if (tmp->latitude < CAD_list_head->start->latitude) { dx0 = -dx0; } dx1 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, CAD_list_head->start->latitude, tmp->next->longitude, temp_course, sizeof(temp_course)); if (tmp->next->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } dy1 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, tmp->next->latitude, CAD_list_head->start->longitude, temp_course, sizeof(temp_course)); // Add the minus signs back in, if any if (tmp->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } if (tmp->latitude < CAD_list_head->start->latitude) { dy0 = -dy0; } if (tmp->next->longitude < CAD_list_head->start->longitude) { dx1 = -dx1; } if (tmp->next->latitude < CAD_list_head->start->latitude) { dy1 = -dy1; } // Greene's Theorem: Summation of the following, then // divide by two: // // A = X Y - X Y // i i i+1 i+1 i // area += (dx0 * dy1) - (dx1 * dy0); tmp = tmp->next; } area = 0.5 * area; } if (area < 0.0) { area = -area; } //fprintf(stderr,"Square nautical miles: %f\n", area); return area; } // Allocate a label for an object, and place it according to the // user's requests. Keep track of where from the origin to place // the label, font to use, color, etc. void CAD_object_allocate_label(void) { } // Set the probability for an object. We should probably allocate // the raw probability to small "buckets" within the closed polygon. // This will allow us to split/join polygons later without messing // up the probablity assigned to each area originally. Check that // it is a closed polygon first. // if as_percent==TRUE, then probability is treated as a percent // (expected to be a value between 0 and 100). // otherwise, then probability is treated as a probability // (expected to be a value between 0 and 1). // void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent) { // initial implementation just assigns a single raw probability to the whole polygon. // internal storage is as a probability between 0 and 1 // users will usually want to manipulate this as a percent (between 0 and 100) // thus the get and set functions are aware of both internal storage and // the user's request and return an appropriately scaled value. if (as_percent==TRUE) { // convert from a percent to a probability between 0 and 1 object_ptr->raw_probability = (probability/100.00); } else { // treat as in internal storage form object_ptr->raw_probability = probability; } } // Get the raw probability for an object. Sum up the raw // probability "buckets" contained within the closed polygon. Check // that it _is_ a closed polygon first. // float CAD_object_get_raw_probability(CADRow *object_ptr, int as_percent) { float result = 0.0; // not checking yet for closure if (object_ptr != NULL) { // initial implementation returns just the single raw probability result = object_ptr->raw_probability; if (as_percent > 0) { // raw probability is a probability between 0 an 1, // this may be desired as a percent. result = result * 100; } } #ifdef CAD_DEBUG fprintf(stderr,"Getting Probability: %01.5f\n",result); #endif return result; } void CAD_object_set_line_width(void) { } void CAD_object_set_color(void) { } void CAD_object_set_linetype(void) { } // Used to break a line segment into two. Can then move the vertice // if needed. Recompute the raw probability if need be, or make it // an invalid value so that we know we need to recompute it. void CAD_vertice_insert_new(void) { // Check whether a line segment will cross another? } // Move an existing vertice. Recompute the raw probability if need // be, or make it an invalid value so that we know we need to // recompute it. void CAD_vertice_move(void) { // Check whether a line segment will cross another? } // Set the location for drawing the label of an area to the center // of the area. Takes a pointer to a CAD object as a parameter. // Sets the label_latitude and label_longitude attributes of the CAD // object to the center of the region described by the vertices of // the object. // void CAD_object_set_label_at_centroid(CADRow *CAD_object) { // *** current implementation approximates the center as the // average of the largest and smallest of each of latitude // and longitude rather than correctly computing the centroid, // that is, it places the label at the centroid of a bounding // box for the area. *** // We can't use a simple x=sum(x)/n, y=sum(y)/n as the // points on the outline shouldn't be weighted equally. // Ideal would be to place the label at the central point within // the area itslef, apparently this is a hard prbolem. // alternative would be to use the centroid, which like the // average of maximum and minimum values may lie outside of // the area. VerticeRow *vertex_pointer; long min_lat, min_long; long max_lat, max_long; // Walk the linked list and compute the centroid of the bounding box. vertex_pointer = CAD_object->start; min_lat = 0.0; min_long = 0.0; // Set the latitude and longitude of the label to the // centroid of the bounding box. // Start by setting lat and long of label to first point. CAD_object->label_latitude = vertex_pointer->latitude; CAD_object->label_longitude = vertex_pointer->longitude; if (vertex_pointer != NULL) { // Iterate through the vertices and calculate the center x and y position // based on an average of the largest and smallest latitudes and longitudes. min_lat = vertex_pointer->latitude; min_long = vertex_pointer->longitude; max_lat = vertex_pointer->latitude; max_long = vertex_pointer->longitude; while (vertex_pointer != NULL) { if (vertex_pointer->next != NULL) { if (vertex_pointer->longitude < min_long ) { min_long = vertex_pointer->longitude; } if (vertex_pointer->latitude < min_lat ) { min_lat = vertex_pointer->latitude; } if (vertex_pointer->longitude > max_long ) { max_long = vertex_pointer->longitude; } if (vertex_pointer->latitude > max_lat ) { max_lat = vertex_pointer->latitude; } } vertex_pointer = vertex_pointer->next; } CAD_object->label_latitude = (max_lat + min_lat)/2.0; CAD_object->label_longitude = (max_long + min_long)/2.0; } } // This is the callback for the CAD objects parameters dialog. It // takes the values entered in the dialog and stores them in the // most recently created object. // void Set_CAD_object_parameters (Widget widget, XtPointer clientData, XtPointer calldata) { float probability = 0.0; CADRow *target_object = NULL; int cb_selected; // need to find out object to edit from clientData rather than // using the first object in list as the one to edit. //target_object = CAD_list_head; target_object = (CADRow *)clientData; // set label, comment, and probability for area xastir_snprintf(target_object->label, sizeof(target_object->label), "%s", XmTextGetString(cad_label_data) ); xastir_snprintf(target_object->comment, sizeof(target_object->comment), "%s", XmTextGetString(cad_comment_data) ); // Is more error checking needed? atof appears to correctly handle // empty input, reasonable probability values, and text (0.00). // User side probabilities are expressed as percent. probability = atof(XmTextGetString(cad_probability_data)); CAD_object_set_raw_probability(target_object, probability, TRUE); // Use the selected line type, default is dashed cb_selected = FALSE; #ifdef USE_COMBO_BOX XtVaGetValues(cad_line_style_data, XmNselectedPosition, &cb_selected, NULL); #else cb_selected = clsd_value; #endif // USE_COMBO_BOX if (cb_selected) { target_object->line_type = cb_selected; } else { target_object->line_type = 2; // LineOnOffDash } if (cad_list_dialog) { Update_CAD_objects_list_dialog(); } // close object_parameters dialog XtPopdown(cad_dialog); XtDestroyWidget(cad_dialog); cad_dialog = (Widget)NULL; Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects so that object name will show on map. redraw_symbols(da); // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata); Draw_CAD_Objects_erase_dialog(widget,clientData,calldata); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata); Draw_CAD_Objects_list_dialog(widget, clientData, calldata); } } // Update the list of existing CAD objects on the cad list dialog to // reflect the current list of objects. // void Update_CAD_objects_list_dialog() { CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (list_of_existing_CAD_objects_edit!=NULL && cad_list_dialog) { XmListDeleteAllItems(list_of_existing_CAD_objects_edit); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects_edit, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } } } void close_object_params_dialog(Widget widget, XtPointer clientData, XtPointer calldata) { XtPopdown(cad_dialog); XtDestroyWidget(cad_dialog); cad_dialog = (Widget)NULL; // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata); Draw_CAD_Objects_erase_dialog(widget,clientData,calldata); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata); Draw_CAD_Objects_list_dialog(widget, clientData, calldata); } } #ifndef USE_COMBO_BOX void clsd_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { //XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)callData; XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //clsd_menu is zero based, cad_line_style_data constants are one based. clsd_value = (int)userData + 1; if (debug_level & 1) { fprintf(stderr,"Selected value on cad line type pulldown: %d\n",clsd_value); } } #endif // !USE_COMBO_BOX // Create a dialog to obtain information about a newly created CAD // object from the user. Values of probability, name, and comment // are initially blank. Takes as a parameter a string describing // the area of the object. There is a single button with a callback // to Set_CAD_object_parameters, which stores values from the dialog // in the object's struct. Should be generalized to allow editing // of a pre-existing CAD object (except for the name). Parameter // should be a pointer to the object. // void Set_CAD_object_parameters_dialog(char *area_description, CADRow *CAD_object) { Widget cad_pane, cad_form, cad_label, cad_comment, cad_probability, cad_line_style, button_done, button_cancel; char probability_string[5]; int i; // loop counters //XmString cb_item; // used to create picklist of line styles XmString cb_items[3]; #ifndef USE_COMBO_BOX Widget clsd_menuPane; Widget clsd_button; Widget clsd_buttons[3]; Widget clsd_menu; char buf[18]; int x; Arg args[12]; // available for XtSetArguments #endif // !USE_COMBO_BOX Widget clsd_widget; if (cad_dialog) { (void)XRaiseWindow(XtDisplay(cad_dialog), XtWindow(cad_dialog)); } else { // Area Object" cad_dialog = XtVaCreatePopupShell(langcode("CADPUD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_pane = XtVaCreateWidget("Set_Del_Object pane", xmPanedWindowWidgetClass, cad_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); cad_form = XtVaCreateWidget("Set_Del_Object ob_form", xmFormWidgetClass, cad_pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Area of polygon, already scaled and internationalized. cad_label = XtVaCreateManagedWidget(area_description, xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Area Label:" cad_label = XtVaCreateManagedWidget(langcode("CADPUD002"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 50, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // label text field cad_label_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, CAD_LABEL_MAX_SIZE - 1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 50, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_label, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "Comment" cad_comment = XtVaCreateManagedWidget(langcode("CADPUD003"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 90, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // comment text field cad_comment_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNmaxLength, CAD_COMMENT_MAX_SIZE - 1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 90, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_comment, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "Probability (as %)" cad_probability = XtVaCreateManagedWidget(langcode("CADPUD004"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 130, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // probability field cad_probability_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 130, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_probability, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // Boundary Line Type cad_line_style = XtVaCreateManagedWidget("Line Type:", xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_probability_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lesstif as of 0.95 in 2008 doesn't fully support combo boxes // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. //cb_items = (XmString *) XtMalloc ( sizeof (XmString) * 4 ); // Solid cb_items[0] = XmStringCreateLtoR( langcode("CADPUD012"), XmFONTLIST_DEFAULT_TAG); // Dashed cb_items[1] = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); // Double Dash cb_items[2] = XmStringCreateLtoR( langcode("CADPUD014"), XmFONTLIST_DEFAULT_TAG); clsd_widget = cad_line_style_data; #ifdef USE_COMBO_BOX // Combo box to pick line style cad_line_style_data = XtVaCreateManagedWidget("select line style", xmComboBoxWidgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_probability_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_line_style, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmComboBoxAddItem(cad_line_style_data,cb_items[0],1,1); XmComboBoxAddItem(cad_line_style_data,cb_items[1],2,1); XmComboBoxAddItem(cad_line_style_data,cb_items[2],3,1); clsd_widget = cad_line_style_data; #else // menu replacement for combo box when using lesstif x = 0; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNfontList, fontlist1); ++x; clsd_menuPane = XmCreatePulldownMenu(cad_form,"sddd_menuPane", args, x); //sddd_menu is zero based, constants for database types are one based. //sddd_value is set to match constants in callback. for (i=0; i<3; i++) { x = 0; XtSetArg(args[x], XmNlabelString, cb_items[i]); x++; XtSetArg(args[x], XmNuserData, (XtPointer)i); x++; XtSetArg(args[x], XmNfontList, fontlist1); ++x; sprintf(buf,"button%d",i); clsd_button = XmCreatePushButton(clsd_menuPane, buf, args, x); XtManageChild(clsd_button); XtAddCallback(clsd_button, XmNactivateCallback, clsd_menuCallback, Set_CAD_object_parameters_dialog); clsd_buttons[i] = clsd_button; } x = 0; XtSetArg(args[x], XmNleftAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNleftWidget, cad_line_style); ++x; XtSetArg(args[x], XmNtopAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNtopWidget, cad_probability_data); ++x; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNtopOffset, 5); ++x; XtSetArg(args[x], XmNleftOffset, 10); ++x; XtSetArg(args[x], XmNsubMenuId, clsd_menuPane); ++x; XtSetArg(args[x], XmNfontList, fontlist1); ++x; clsd_menu = XmCreateOptionMenu(cad_form, "sddd_Menu", args, x); XtManageChild(clsd_menu); clsd_value = 2; // set a default value (line on off dash) clsd_widget = clsd_menu; #endif // USE_COMBO_BOX // free up space from combo box strings for (i=0; i<3; i++) { XmStringFree(cb_items[i]); } // "OK" button_done = XtVaCreateManagedWidget(langcode("CADPUD005"), xmPushButtonGadgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, clsd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Cancel" button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, clsd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // callback depends on whether this is a new or old object //XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, Set_CAD_object_parameters_dialog); if (CAD_object!=NULL) { XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, (XtPointer *)CAD_object); } else { // called to get information for a newly created cad object // pass pointer to the head of the list, which contains // the most recently created cad object. XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, CAD_list_head); } XtAddCallback(button_cancel, XmNactivateCallback, close_object_params_dialog, NULL); pos_dialog(cad_dialog); XmInternAtom(XtDisplay(cad_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_form); XtManageChild(cad_pane); XtPopup(cad_dialog,XtGrabNone); } // end if ! caddialog if (CAD_object!=NULL) { XmString tempSelection; // given an existing object, fill form with its information XmTextFieldSetString(cad_label_data,CAD_object->label); XmTextFieldSetString(cad_comment_data,CAD_object->comment); xastir_snprintf(probability_string, sizeof(probability_string), "%01.2f", CAD_object_get_raw_probability(CAD_object,1)); XmTextFieldSetString(cad_probability_data,probability_string); switch(CAD_object->line_type) { case 1: // Solid #ifndef USE_COMBO_BOX i = 0; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD012"), XmFONTLIST_DEFAULT_TAG); break; case 2: // Dashed #ifndef USE_COMBO_BOX i = 1; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); break; case 3: // Double Dash #ifndef USE_COMBO_BOX i = 2; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD014"), XmFONTLIST_DEFAULT_TAG); break; default: #ifndef USE_COMBO_BOX i = 1; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); break; } #ifdef USE_COMBO_BOX XmComboBoxSelectItem(cad_line_style_data, tempSelection); #else clsd_value = i+1; //clsd_menu is zero based, line types are one based. //clsd_value matches line types (1-3). XtVaSetValues(clsd_menu, XmNmenuHistory, clsd_buttons[i], NULL); #endif // USE_COMBO_BOX XmStringFree(tempSelection); } } static Cursor cs_CAD = (Cursor)NULL; void free_cs_CAD(void) { XFreeCursor(XtDisplay(da), cs_CAD); cs_CAD = (Cursor)NULL; } // This is the callback for the Draw togglebutton // void Draw_CAD_Objects_mode( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { draw_CAD_objects_flag = 1; // Create the "pencil" cursor so we know what mode we're in. // if(!cs_CAD) { cs_CAD=XCreateFontCursor(XtDisplay(da),XC_pencil); atexit(free_cs_CAD); } // enable the close polygon button on an open CAD menu if (CAD_close_polygon_menu_item) { XtSetSensitive(CAD_close_polygon_menu_item,TRUE); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_CAD); (void)XFlush(XtDisplay(da)); draw_CAD_objects_flag = 1; polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position } else { draw_CAD_objects_flag = 0; polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position Save_CAD_Objects_to_file(); // Remove the special "pencil" cursor. (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); // disable the close polygon button on an open CAD menu. if (CAD_close_polygon_menu_item) { XtSetSensitive(CAD_close_polygon_menu_item,FALSE); } } } // Called when we complete a new CAD object. Save the object to // disk so that we can recover in the case of a crash or power // failure. Save any old file to a backup file. Perhaps write them // to numbered backup files so that we keep several on-hand? // void Save_CAD_Objects_to_file(void) { FILE *f; char *file; CADRow *object_ptr = CAD_list_head; char temp_file_path[MAX_VALUE]; fprintf(stderr,"Saving CAD objects to file\n"); // Save in ~/.xastir/config/CAD_object.log file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path)); f = fopen(file,"w+"); if (f == NULL) { fprintf(stderr, "Couldn't open config/CAD_object.log file for writing!\n"); return; } while (object_ptr != NULL) { VerticeRow *vertice = object_ptr->start; // Write out the main object info: fprintf(f,"\nCAD_Object\n"); fprintf(f,"creation_time: %lu\n",(unsigned long)object_ptr->creation_time); fprintf(f,"line_color: %d\n",object_ptr->line_color); fprintf(f,"line_type: %d\n",object_ptr->line_type); fprintf(f,"line_width: %d\n",object_ptr->line_width); fprintf(f,"computed_area: %f\n",object_ptr->computed_area); fprintf(f,"raw_probability: %f\n",CAD_object_get_raw_probability(object_ptr,TRUE)); fprintf(f,"label_latitude: %lu\n",object_ptr->label_latitude); fprintf(f,"label_longitude: %lu\n",object_ptr->label_longitude); fprintf(f,"label: %s\n",object_ptr->label); if (strlen(object_ptr->comment)>1) { fprintf(f,"comment: %s\n",object_ptr->comment); } else { fprintf(f,"comment: NULL\n"); } // Iterate through the vertices: while (vertice != NULL) { fprintf(f,"Vertice: %lu %lu\n", vertice->latitude, vertice->longitude); vertice = vertice->next; } object_ptr = object_ptr->next; } (void)fclose(f); } // Called by main() when we start Xastir. Restores CAD objects // created in earlier Xastir sessions. // void Restore_CAD_Objects_from_file(void) { FILE *f; char *file; char line[MAX_FILENAME]; char temp_file_path[MAX_VALUE]; #ifdef CAD_DEBUG fprintf(stderr,"Restoring CAD objects from file\n"); #endif // Restore from ~/.xastir/config/CAD_object.log file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path)); f = fopen(file,"r"); if (f == NULL) { #ifdef CAD_DEBUG fprintf(stderr, "Couldn't open config/CAD_object.log file for reading!\n"); #endif return; } while (!feof (f)) { (void)get_line(f, line, MAX_FILENAME); if (strncasecmp(line,"CAD_Object",10) == 0) { // Found a new CAD Object declaration! //fprintf(stderr,"Found CAD_Object\n"); // Malloc a new object, add it to the linked list, start // filling in the fields. // // This gives us a default object with one vertice. We // can replace all of the fields in it as we parse them. CAD_object_allocate(0l, 0l); // Remove the one vertice from the newly allocated // object so that we don't end up with one too many // vertices when all done. CAD_vertice_delete_all(CAD_list_head->start); CAD_list_head->start = NULL; } else if (strncasecmp(line,"creation_time:",14) == 0) { //fprintf(stderr,"Found creation_time:\n"); unsigned long temp_time; if (1 != sscanf(line+15, "%lu",&temp_time)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [creation_time]\n"); } CAD_list_head->creation_time=(time_t)temp_time; } else if (strncasecmp(line,"line_color:",11) == 0) { //fprintf(stderr,"Found line_color:\n"); if (1 != sscanf(line+12,"%d", &CAD_list_head->line_color)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_color]\n"); } } else if (strncasecmp(line,"line_type:",10) == 0) { //fprintf(stderr,"Found line_type:\n"); if (1 != sscanf(line+11,"%d", &CAD_list_head->line_type)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_type]\n"); } } else if (strncasecmp(line,"line_width:",11) == 0) { //fprintf(stderr,"Found line_width:\n"); if (1 != sscanf(line+12,"%d", &CAD_list_head->line_width)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_width]\n"); } } else if (strncasecmp(line,"computed_area:",14) == 0) { //fprintf(stderr,"Found computed_area:\n"); if (1 != sscanf(line+15,"%f", &CAD_list_head->computed_area)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [computed_area]\n"); } } else if (strncasecmp(line,"raw_probability:",16) == 0) { //fprintf(stderr,"Found raw_probability:\n"); if (1 != sscanf(line+17,"%f", &CAD_list_head->raw_probability)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [raw_probability]\n"); } else { // External storage is as percent, need to make sure that this // fits the expected internal storage format. // Thus take given value and store using method that knows // how to handle percents CAD_object_set_raw_probability(CAD_list_head,CAD_list_head->raw_probability,TRUE); } } else if (strncasecmp(line,"label_latitude:",15) == 0) { //fprintf(stderr,"Found label_latitude:\n"); if (1 != sscanf(line+16,"%lu", (unsigned long *)&CAD_list_head->label_latitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_latitude]\n"); } } else if (strncasecmp(line,"label_longitude:",16) == 0) { //fprintf(stderr,"Found label_longitude:\n"); if (1 != sscanf(line+17,"%lu", (unsigned long *)&CAD_list_head->label_longitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_longitude]\n"); } } else if (strncasecmp(line,"label:",6) == 0) { //fprintf(stderr,"Found label:\n"); xastir_snprintf(CAD_list_head->label, sizeof(CAD_list_head->label), "%s", line+7); } else if (strncasecmp(line,"comment:",8) == 0) { //fprintf(stderr,"Found comment:\n"); xastir_snprintf(CAD_list_head->comment, sizeof(CAD_list_head->comment), "%s", line+9); if (strcmp(CAD_list_head->comment,"NULL")==0) { xastir_snprintf(CAD_list_head->comment, sizeof(CAD_list_head->comment), "%c", '\0' ); } } else if (strncasecmp(line,"Vertice:",8) == 0) { long latitude, longitude; //fprintf(stderr,"Found Vertice:\n"); if (2 != sscanf(line+9,"%lu %lu", (unsigned long *)&latitude, (unsigned long *)&longitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [vertex]\n"); } CAD_vertice_allocate(latitude,longitude); } else { // Else not recognized, do nothing with it! //fprintf(stderr,"Found unrecognized line\n"); } } (void)fclose(f); // Reload symbols/tracks/CAD objects to draw the loaded objects redraw_symbols(da); } // popdown and destroy the cad_erase_dialog. // void Draw_CAD_Objects_erase_dialog_close ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (cad_erase_dialog!=NULL) { // close cad_erase_dialog XtPopdown(cad_erase_dialog); XtDestroyWidget(cad_erase_dialog); cad_erase_dialog = (Widget)NULL; } } // Call back for delete selected button on // Draw_CAD_Objects_erase_dialog. Iterates through the list of // selected CAD objects and deletes them. // void Draw_CAD_Objects_erase_selected ( Widget w, XtPointer clientData, XtPointer callData) { int itemCount; // number of items in list of CAD objects. XmString *listItems; // names of CAD objects on list char *cadName; // the text name of a CAD object Position x; // position on list char *selectedName; // the text name of a selected CAD object CADRow *object_ptr = CAD_list_head; // pointer to the linked list of CAD objects int done = 0; // has a cad object with a name matching the current selection been found // For more than a few objects this loop/save/redraw will need to move // off to a separate thread. XtVaGetValues(list_of_existing_CAD_objects, XmNitemCount,&itemCount, XmNitems,&listItems, NULL); // iterate through list and delete each first object with a name matching // those that are selected on the list. // // *** Note: If names are not unique the results may not be what the user expects. // The first match to a selection will be deleted, not necessarily the selection. // for (x=1; x<=itemCount; x++) { if (done) { break; } if (XmListPosSelected(list_of_existing_CAD_objects,x)) { int no_label = 0; XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName); // Check for our own definition of no label for the CAD // objects, which is "" if (strcmp(selectedName,"") == 0) { no_label++; } object_ptr = CAD_list_head; done = 0; while (object_ptr != NULL && done == 0) { cadName = object_ptr->label; if (strcmp(cadName,selectedName)==0 || ( (cadName == NULL || cadName[0] == '\0') && no_label) ) { // delete CAD object matching the selected name CAD_object_delete(object_ptr); done = 1; } else { object_ptr = object_ptr->next; } } } } Draw_CAD_Objects_erase_dialog_close(w,clientData,callData); // Save the altered list to file. Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects redraw_symbols(da); // Here we update the edit cad objects dialog by getting rid of it and // then re-establishing it if it is active when we start. This will // usually make the dialog move, but it's better than having it be // out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(w, clientData, callData); Draw_CAD_Objects_list_dialog(w, clientData, callData); } } // Callback for delete CAD objects menu option. Dialog to allow // users to delete all CAD objects or select individual CAD objects // to delete. // void Draw_CAD_Objects_erase_dialog( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget cad_erase_pane, cad_erase_form, cad_erase_label, button_delete_all, button_delete_selected, button_cancel; Arg al[100]; /* Arg List */ unsigned int ac; /* Arg Count */ CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (cad_erase_dialog) { (void)XRaiseWindow(XtDisplay(cad_erase_dialog), XtWindow(cad_erase_dialog)); } else { // Delete CAD Objects cad_erase_dialog = XtVaCreatePopupShell("Delete CAD Objects", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_erase_pane = XtVaCreateWidget("CAD erase Object pane", xmPanedWindowWidgetClass, cad_erase_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); cad_erase_form = XtVaCreateWidget("Cad erase Object form", xmFormWidgetClass, cad_erase_pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // heading: Delete CAD Objects cad_erase_label = XtVaCreateManagedWidget(langcode("CADPUD009"), xmLabelWidgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to handle the special case of no CAD objects ? *** // scrolled pick list to allow selection of current objects /*set args for list */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmEXTENDED_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, cad_erase_label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; list_of_existing_CAD_objects = XmCreateScrolledList(cad_erase_form, "CAD objects for deletion scrolled list", al, ac); // make sure list is empty XmListDeleteAllItems(list_of_existing_CAD_objects); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } // "Delete All" button_delete_all = XtVaCreateManagedWidget(langcode("CADPUD010"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_delete_all, XmNactivateCallback, Draw_CAD_Objects_erase, Draw_CAD_Objects_erase_dialog); // "Delete Selected" button_delete_selected = XtVaCreateManagedWidget(langcode("CADPUD011"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_delete_all, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_delete_selected, XmNactivateCallback, Draw_CAD_Objects_erase_selected, Draw_CAD_Objects_erase_dialog); // "Cancel" button_cancel = XtVaCreateManagedWidget(langcode("CADPUD008"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_delete_selected, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Draw_CAD_Objects_erase_dialog_close, Draw_CAD_Objects_erase_dialog); pos_dialog(cad_erase_dialog); XmInternAtom(XtDisplay(cad_erase_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_erase_form); XtManageChild(list_of_existing_CAD_objects); XtManageChild(cad_erase_pane); XtPopup(cad_erase_dialog,XtGrabNone); } } // popdown and destroy the cad_list_dialog // void Draw_CAD_Objects_list_dialog_close ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (cad_list_dialog!=NULL) { // close cad_list_dialog XtPopdown(cad_list_dialog); XtDestroyWidget(cad_list_dialog); cad_list_dialog = (Widget)NULL; } } // Show details for selected CAD object. Callback for the show/edit // details button on the Draw_CAD_Objects_list dialog. // void Show_selected_CAD_object_details ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static int sizeof_area_description = 200; int itemCount; // number of items in list of CAD objects. XmString *listItems; // names of CAD objects on list char *cadName; // the text name of a CAD object Position x; // position on list char *selectedName; // the text name of a selected CAD object CADRow *object_ptr = CAD_list_head; // pointer to the linked list of CAD objects int done = 0; // has a cad object with a name matching the current selection been found double area; char area_description[sizeof_area_description]; xastir_snprintf(area_description, sizeof_area_description, "Area"); if (cad_list_dialog!=NULL) { // get the selected object XtVaGetValues(list_of_existing_CAD_objects_edit, XmNitemCount,&itemCount, XmNitems,&listItems, NULL); // iterate through list and find each object with a name // matching one selected on the list. // // *** Note: If names are not unique the results may not be what the user expects. // The first match to a selection will be used, not necessarily the selection. // for (x=1; x<=itemCount; x++) { if (XmListPosSelected(list_of_existing_CAD_objects_edit,x)) { int no_label = 0; XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName); // Check for our own definition of no label for the CAD // objects, which is "" if (strcmp(selectedName,"") == 0) { no_label++; } object_ptr = CAD_list_head; done = 0; while (object_ptr != NULL && done == 0) { cadName = object_ptr->label; if (strcmp(cadName,selectedName)==0 || ( (cadName == NULL || cadName[0] == '\0') && no_label) ) { // get the area for the CAD object matching the selected name // and format it as a localized string. area = object_ptr->computed_area; Format_area_for_output(&area, area_description,sizeof_area_description); // open the CAD object details dialog for the matching CAD object Set_CAD_object_parameters_dialog(area_description,object_ptr); done = 1; } else { object_ptr = object_ptr->next; } } } } // leave the list dialog open } } // Callback for edit CAD objects menu option. Dialog to allow users // to select individual CAD objects in order to edit their metadata. // void Draw_CAD_Objects_list_dialog( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget cad_list_pane, cad_list_form, cad_list_label, button_list_selected, button_close; Arg al[100]; /* Arg List */ unsigned int ac; /* Arg Count */ CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (cad_list_dialog) { (void)XRaiseWindow(XtDisplay(cad_list_dialog), XtWindow(cad_list_dialog)); } else { // List CAD Objects cad_list_dialog = XtVaCreatePopupShell("List CAD Objects", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_list_pane = XtVaCreateWidget("CAD list Object pane", xmPanedWindowWidgetClass, cad_list_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); cad_list_form = XtVaCreateWidget("Cad list Object form", xmFormWidgetClass, cad_list_pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // heading: CAD Objects cad_list_label = XtVaCreateManagedWidget(langcode("CADPUD006"), xmLabelWidgetClass, cad_list_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to handle the special case of no CAD objects ? *** // scrolled pick list to allow selection of current objects /*set args for list */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, cad_list_label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; list_of_existing_CAD_objects_edit = XmCreateScrolledList(cad_list_form, "CAD objects for deletion scrolled list", al, ac); // make sure list is empty XmListDeleteAllItems(list_of_existing_CAD_objects_edit); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects_edit, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } // "Show/edit details" button_list_selected = XtVaCreateManagedWidget(langcode("CADPUD007"), xmPushButtonGadgetClass, cad_list_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects_edit, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_list_selected, XmNactivateCallback, Show_selected_CAD_object_details, Draw_CAD_Objects_list_dialog); // "Close" button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, cad_list_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects_edit, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_list_selected, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, Draw_CAD_Objects_list_dialog_close, Draw_CAD_Objects_erase_dialog); pos_dialog(cad_list_dialog); XmInternAtom(XtDisplay(cad_list_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_list_form); XtManageChild(list_of_existing_CAD_objects_edit); XtManageChild(cad_list_pane); XtPopup(cad_list_dialog,XtGrabNone); } } // Free the object and vertice lists then do a screen update. // callback from delete all button on cad_erase_dialog. // void Draw_CAD_Objects_erase( Widget w, XtPointer clientData, XtPointer callData) { // if we were called from the cad_erase_dialog, make sure it is closed properly if (cad_erase_dialog) { Draw_CAD_Objects_erase_dialog_close(w,clientData,callData); } CAD_object_delete_all(); polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position // Save the empty list out to file Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects redraw_symbols(da); } // Formats an area as a string in english (square miles) or metric units // (square kilometers). Switches to square feet or square meters if the // area is less than 0.1 of the units. // // Parameters: // area: an area in square kilometers. // area_description: area reformatted as a localized text string. // sizeof_area_description: array length of area_description. // void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description) { double area; // Format it for output and dump it out. We're using square terms, so // apply the conversion factor twice to convert from square kilometers // to the units of interest. The result here is squared meters or // squared feet. //fprintf(stderr,"Square km: %f\n", *area_km2); area = *area_km2 * 1000.0 * 1000.0 * cvt_m2len * cvt_m2len; // We could be measuring a very small or a very large object. // In the case of very small, convert it to square feet or // square meters. if (english_units) // Square feet { //fprintf(stderr,"Square feet: %f\n", area); if (area < 2787840.0) // Switch at 0.5 miles squared { // Smaller area: Output in feet squared xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA053") ); // ft //popup_message_always(langcode("POPUPMA020"),area_description); } else { // Larger area: Output in miles squared area = area / 27878400.0; xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA055") ); // mi //popup_message_always(langcode("POPUPMA020"),area_description); } } else // Square meters { //fprintf(stderr,"Square meters: %f\n", area); if (area < 100000.0) // Switch at 0.1 km squared { // Smaller area: Output in meters squared xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA054") ); // meters //popup_message_always(langcode("POPUPMA020"),area_description); } else { // Larger ara: Output in kilometers squared area = area / 1000000.0; xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("UNIOP00005") ); // km //popup_message_always(langcode("POPUPMA020"),area_description); } } } // Add an ending vertice that is the same as the starting vertice. // Best not to use the screen coordinates we captured first, as the // user may have zoomed or panned since then. Better to copy the // first vertice that we recorded in our linked list. // // Compute the area of the closed polygon. Write it out to STDERR, // the computed_area field in the Object, and to a dialog that pops // up on the screen. // void Draw_CAD_Objects_close_polygon( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static int sizeof_area_description = 200; VerticeRow *tmp; double area; int n; //char temp_course[20]; char area_description[sizeof_area_description]; xastir_snprintf(area_description, sizeof_area_description, "Area"); // Check whether we're currently working on a polygon. If not, // get out of here. if (polygon_last_x == -1 || polygon_last_y == -1) { // Tell the code that we're starting a new polygon by wiping // out the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position return; } // Find the last vertice in the linked list. That will be the // first vertice we recorded for the object. // Check for at least three vertices. We don't need to check // that the first/last point are equal: We force it below by // copying the first vertice to the last. // n = 0; if (CAD_list_head != NULL) { // Walk the linked list. Stop at the last record. tmp = CAD_list_head->start; if (tmp != NULL) { n++; while (tmp->next != NULL) { tmp = tmp->next; n++; } if (n > 2) { // We have more than a point or a line, therefore // can copy the first point to the last, closing the // polygon. CAD_vertice_allocate(tmp->latitude, tmp->longitude); } } } // Reload symbols/tracks/CAD objects and redraw the polygon redraw_symbols(da); #ifdef CAD_DEBUG fprintf(stderr,"Points in closed polygon: n = %d\n",n); #endif if (n < 3) { // Not enough points to compute an area. // Tell the code that we're starting a new polygon by wiping // out the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position return; } area = CAD_object_compute_area(CAD_list_head); // Save it in the object. Convert nautical square miles to // square kilometers because that's what "Format_area_for_output" // requires. area = area * 3.429903999977917; // Now in km squared //fprintf(stderr,"SQUARE KM: %f\n", area); CAD_list_head->computed_area = area; Format_area_for_output(&area, area_description, sizeof_area_description); #ifdef CAD_DEBUG // Also write the area to stderr fprintf(stderr,"New CAD object %s\n",area_description); #endif // Tell the code that we're starting a new polygon by wiping out // the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position CAD_object_set_label_at_centroid(CAD_list_head); // CAD object vertices are ready, needs associated data // obtain label, comment, and probability for this polygon // from user through a dialog. Set_CAD_object_parameters_dialog(area_description,NULL); } // Function called by UpdateTime when doing screen refresh. Draws // all CAD objects onto the screen again. // void Draw_All_CAD_Objects(Widget w) { CADRow *object_ptr = CAD_list_head; long x_long, y_lat; long x_offset, y_offset; float probability; char probability_string[8]; VerticeRow *vertice; double area; int actual_line_type = LineOnOffDash; static int sizeof_area_description = 50; // define here as local static to limit size of display on map // independent of size as shown on form char area_description[sizeof_area_description]; char dash[2]; // Start at CAD_list_head, iterate through entire linked list, // drawing as we go. Respect the line // width/line_color/line_type variables for each object. //fprintf(stderr,"Drawing CAD objects\n"); if (CAD_draw_objects==TRUE) { while (object_ptr != NULL) { probability = CAD_object_get_raw_probability(object_ptr,1); xastir_snprintf(probability_string, sizeof(probability_string), "%01.1f%%", probability); // find point at which to draw label and other descriptive text x_long = object_ptr->label_longitude; y_lat = object_ptr->label_latitude; #ifdef CAD_DEBUG fprintf(stderr,"Drawing object %s\n", (object_ptr->label) ? object_ptr->label : "NULL" ); #endif //fprintf(stderr,"Lat: %d\n", y_lat); //fprintf(stderr,"Long: %d\n", x_long); // if ((x_long+10>=0) && (x_long-10<=129600000l)) { // 360 deg // if ((y_lat+10>=0) && (y_lat-10<=64800000l)) { // 180 deg if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_latlabel)>0) & (CAD_show_label==TRUE)) { // Draw Label // 0x08 is background color // 0x40 is foreground color (yellow) draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->label,0x08,0x40,strlen(object_ptr->label)); x_offset=x_offset+12; y_offset=y_offset+15; } if (CAD_show_raw_probability==TRUE) { // draw probability draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,probability_string,0x08,0x40,strlen(probability_string)); y_offset=y_offset+15; } if ((CAD_show_comment==TRUE) & ((int)strlen(object_ptr->comment)>0)) { // draw comment draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->comment,0x08,0x40,strlen(object_ptr->comment)); y_offset=y_offset+15; } if (CAD_show_area==TRUE) { area = object_ptr->computed_area; Format_area_for_output(&area, area_description, sizeof_area_description); draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,area_description,0x08,0x40,strlen(area_description)); y_offset=y_offset+15; } } } // } // } // Iterate through the vertices and draw the lines vertice = object_ptr->start; switch (object_ptr->line_type) { case 1: actual_line_type = LineSolid; break; case 2: actual_line_type = LineOnOffDash; dash[0] = dash[1] = 8; break; case 3: actual_line_type = LineDoubleDash; dash[0] = dash[1] = 16; break; default: actual_line_type = LineOnOffDash; dash[0] = dash[1] = 8; break; } // Set up line color/width/type here (void)XSetLineAttributes (XtDisplay (da), gc_tint, object_ptr->line_width, actual_line_type, CapButt, JoinMiter); if (object_ptr->line_type != 1) { (void)XSetDashes (XtDisplay (da), gc_tint, 0, // dash offset dash, // dash list[] 2); // elements in dash lista } (void)XSetForeground (XtDisplay (da), gc_tint, object_ptr->line_color); (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); while (vertice != NULL) { if (vertice->next != NULL) { // Use the draw_vector function from maps.c draw_vector(w, vertice->longitude, vertice->latitude, vertice->next->longitude, vertice->next->latitude, gc_tint, pixmap_final, 0); } vertice = vertice->next; } object_ptr = object_ptr->next; } } } ///////////////////////////////////////// Object Dialog ////////////////////////////////////////// /* * Destroy Object Dialog Popup Window */ void Object_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),Ob_icon0); (void)XFreePixmap(XtDisplay(appshell),Ob_icon); XtDestroyWidget(shell); object_dialog = (Widget)NULL; // Take down the symbol selection dialog as well (if it's up) if (select_symbol_dialog) { Select_symbol_destroy_shell( widget, select_symbol_dialog, callData); } // NULL out the dialog field in the global struct used for // Coordinate Calculator. Prevents segfaults if the calculator is // still up and trying to write to us. coordinate_calc_array.calling_dialog = NULL; } // Snag the latest DR'ed position for an object/item and create the // types of strings that we need for Setup_object_data() and // Setup_item_data() for APRS and Base-91 compressed formats. // void fetch_current_DR_strings(DataRow *p_station, char *lat_str, char *lon_str, char *ext_lat_str, char *ext_lon_str) { long x_long, y_lat; // Fetch the latest position for a DR'ed object. Returns the // values in two longs, x_long and y_lat. compute_current_DR_position(p_station, &x_long, &y_lat); // Normal precision for APRS format convert_lat_l2s(y_lat, lat_str, MAX_LAT, CONVERT_LP_NOSP); convert_lon_l2s(x_long, lon_str, MAX_LONG, CONVERT_LP_NOSP); // Extended precision for Base-91 compressed format convert_lat_l2s(y_lat, ext_lat_str, MAX_LAT, CONVERT_HP_NOSP); convert_lon_l2s(x_long, ext_lon_str, MAX_LONG, CONVERT_HP_NOSP); } // Convert this eventually to populate a DataRow struct, then call // data.c:Create_object_item_tx_string(). Right now we have a lot // of code duplication between Setup_object_data, Setup_item_data, // and Create_object_item_tx_string. // // Make sure to look at the "transmit_compressed_objects_items" variable // to decide whether to send a compressed packet. /* * Setup APRS Information Field for Objects */ int Setup_object_data(char *line, int line_length, DataRow *p_station) { char lat_str[MAX_LAT]; char lon_str[MAX_LONG]; char ext_lat_str[20]; // Extended precision for base91 compression char ext_lon_str[20]; // Extended precision for base91 compression char comment[43+1]; // max 43 characters of comment char time[7+1]; struct tm *day_time; time_t sec; char complete_area_color[3]; int complete_area_type; int lat_offset, lon_offset; char complete_corridor[6]; char altitude[10]; char speed_course[8]; int speed; int course; int temp; long temp2; float temp3; char signpost[6]; char prob_min[20+1]; char prob_max[20+1]; int bearing; char *temp_ptr; char *temp_ptr2; int DR = 0; // Dead-reckoning flag int comment_field_used = 0; // Amount of comment field used up //fprintf(stderr,"Setup_object_data\n"); // If speed for the original object was non-zero, then we need // to snag the updated DR'ed position for the object. Snag the // current DR position and build the strings we need // for // position transmit. // if (p_station != NULL) { speed = atoi(p_station->speed); if (speed > 0 && !doing_move_operation) { fetch_current_DR_strings(p_station, lat_str, lon_str, ext_lat_str, ext_lon_str); DR++; // Set the dead-reckoning flag } // Keep the time current for our own objects. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); } temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(line); //(void)to_upper(line); Not per spec. Don't use this. if (!valid_object(line)) { return(0); } // Copy object name into "last_object" xastir_snprintf(last_object, sizeof(last_object), "%s", line); if (!DR) // We're not doing dead-reckoning, so proceed { temp_ptr = XmTextFieldGetString(object_lat_data_ns); if((char)toupper((int)temp_ptr[0]) == 'S') { line[0] = 'S'; } else { line[0] = 'N'; } XtFree(temp_ptr); // Check latitude for out-of-bounds temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp > 90) || (temp < 0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lat_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { return(0); } if ( (temp == 90) && (temp3 != 0.0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp_ptr2 = XmTextFieldGetString(object_lat_data_min); xastir_snprintf(lat_str, sizeof(lat_str), "%02d%05.2f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp_ptr2 = XmTextFieldGetString(object_lat_data_min); xastir_snprintf(ext_lat_str, sizeof(ext_lat_str), "%02d%05.3f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.0001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.0001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lon_data_ew); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); if((char)toupper((int)line[0]) == 'E') { line[0] = 'E'; } else { line[0] = 'W'; } // Check longitude for out-of-bounds temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp > 180) || (temp < 0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lon_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { return(0); } if ( (temp == 180) && (temp3 != 0.0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp_ptr2 = XmTextFieldGetString(object_lon_data_min); xastir_snprintf(lon_str, sizeof(lon_str), "%03d%05.2f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp_ptr2 = XmTextFieldGetString(object_lon_data_min); xastir_snprintf(ext_lon_str, sizeof(ext_lon_str), "%03d%05.3f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.0001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.0001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); } temp_ptr = XmTextFieldGetString(object_group_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); last_obj_grp = line[0]; if(isalpha((int)last_obj_grp)) { last_obj_grp = toupper((int)line[0]); // todo: toupper in dialog } // Check for overlay character if (last_obj_grp != '/' && last_obj_grp != '\\') { // Found an overlay character. Check that it's within the // proper range if ( (last_obj_grp >= '0' && last_obj_grp <= '9') || (last_obj_grp >= 'A' && last_obj_grp <= 'Z') ) { last_obj_overlay = last_obj_grp; last_obj_grp = '\\'; } else { last_obj_overlay = '\0'; } } else { last_obj_overlay = '\0'; } temp_ptr = XmTextFieldGetString(object_symbol_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); last_obj_sym = line[0]; temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); //fprintf(stderr,"Comment Field was: %s\n",comment); sec = sec_now(); day_time = gmtime(&sec); xastir_snprintf(time, sizeof(time), "%02d%02d%02dz", day_time->tm_mday, day_time->tm_hour, day_time->tm_min); // Handle Generic Options // Speed/Course Fields temp_ptr = XmTextFieldGetString(ob_course_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); xastir_snprintf(speed_course, sizeof(speed_course), "%s", ".../"); course = 0; if (strlen(line) != 0) // Course was entered { // Need to check for 1 to three digits only, and 001-360 degrees) temp = atoi(line); if ( (temp >= 1) && (temp <= 360) ) { xastir_snprintf(speed_course, sizeof(speed_course), "%03d/", temp); course = temp; } else if (temp == 0) // Spec says 001 to 360 degrees... { xastir_snprintf(speed_course, sizeof(speed_course), "%s", "360/"); } } temp_ptr = XmTextFieldGetString(ob_speed_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); speed = 0; if (strlen(line) != 0) // Speed was entered (we only handle knots currently) { // Need to check for 1 to three digits, no alpha characters temp = atoi(line); if ( (temp >= 0) && (temp <= 999) ) { xastir_snprintf(line, line_length, "%03d", temp); strncat(speed_course, line, sizeof(speed_course) - 1 - strlen(speed_course)); speed = temp; } else { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } } else // No speed entered, blank it out { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } if ( (speed_course[0] == '.') && (speed_course[4] == '.') ) { speed_course[0] = '\0'; // No speed or course entered, so blank it } if (Area_object_enabled) { speed_course[0] = '\0'; // Course/Speed not allowed if Area Object } // Altitude Field temp_ptr = XmTextFieldGetString(ob_altitude_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Altitude entered: %s\n", line); altitude[0] = '\0'; // Start with empty string if (strlen(line) != 0) // Altitude was entered (we only handle feet currently) { // Need to check for all digits, and 1 to 6 digits if (isdigit((int)line[0])) { temp2 = atoi(line); if ( (temp2 >= 0) && (temp2 <= 999999) ) { char temp_alt[20]; xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld", temp2); memcpy(altitude, temp_alt, sizeof(altitude)); altitude[sizeof(altitude)-1] = '\0'; // Terminate string //fprintf(stderr,"Altitude string: %s\n",altitude); } } } // Handle Specific Options // Area Objects if (Area_object_enabled) { //fprintf(stderr,"Area_bright: %d\n", Area_bright); //fprintf(stderr,"Area_filled: %d\n", Area_filled); if (Area_bright) // Bright color { xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%2s", Area_color); } else // Dim color { xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02.0f", (float)(atoi(&Area_color[1]) + 8) ); if ( (Area_color[1] == '0') || (Area_color[1] == '1') ) { complete_area_color[0] = '/'; } } if ( (Area_filled) && (Area_type != 1) && (Area_type != 6) ) { complete_area_type = Area_type + 5; } else // Can't fill in a line { complete_area_type = Area_type; } temp_ptr = XmTextFieldGetString(ob_lat_offset_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); lat_offset = sqrt(atof(line)); if (lat_offset > 99) { lat_offset = 99; } //fprintf(stderr,"Line: %s\tlat_offset: %d\n", line, lat_offset); temp_ptr = XmTextFieldGetString(ob_lon_offset_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); lon_offset = sqrt(atof(line)); if (lon_offset > 99) { lon_offset = 99; } //fprintf(stderr,"Line: %s\tlon_offset: %d\n", line, lon_offset); //fprintf(stderr,"Corridor Field: %s\n", XmTextFieldGetString(ob_corridor_data) ); // Corridor complete_corridor[0] = '\0'; if ( (Area_type == 1) || (Area_type == 6) ) { temp_ptr = XmTextFieldGetString(ob_corridor_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); if (strlen(line) != 0) // We have a line and some corridor data { // Need to check for 1 to three digits only temp = atoi(line); if ( (temp > 0) && (temp <= 999) ) { xastir_snprintf(complete_corridor, sizeof(complete_corridor), "{%d}", temp); //fprintf(stderr,"%s\n",complete_corridor); } } } //fprintf(stderr,"Complete_corridor: %s\n", complete_corridor); if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ";%-9s*%s%s%1d%02d%2s%02d%s%s%s", last_object, time, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case complete_area_type, // In comment field lat_offset, // In comment field complete_area_color,// In comment field lon_offset, // In comment field speed_course, // In comment field complete_corridor, // In comment field altitude); // In comment field comment_field_used = strlen(line) - 31; } else { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%1d%02d%2s%02d%s%s%s", last_object, time, lat_str, last_obj_grp, lon_str, last_obj_sym, complete_area_type, // In comment field lat_offset, // In comment field complete_area_color,// In comment field lon_offset, // In comment field speed_course, // In comment field complete_corridor, // In comment field altitude); // In comment field comment_field_used = strlen(line) - 37; } //fprintf(stderr,"String is: %s\n", line); } else if (Signpost_object_enabled) { temp_ptr = XmTextFieldGetString(signpost_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Signpost entered: %s\n", line); if (strlen(line) != 0) // Signpost data was entered { // Need to check for between one and three characters temp = strlen(line); if ( (temp >= 0) && (temp <= 3) ) { xastir_snprintf(signpost, sizeof(signpost), "{%s}", line); } else { signpost[0] = '\0'; } } else // No signpost data entered, blank it out { signpost[0] = '\0'; } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ";%-9s*%s%s%s%s", last_object, time, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case altitude, signpost); comment_field_used = strlen(line) - 31; } else { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s%s", last_object, time, lat_str, last_obj_grp, lon_str, last_obj_sym, speed_course, altitude, signpost); comment_field_used = strlen(line) - 37; } } else if (DF_object_enabled) // A DF'ing object of some type { if (Omni_antenna_enabled) { if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ";%-9s*%s%sDFS%s/%s%s", last_object, time, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case object_shgd, speed_course, altitude); comment_field_used = strlen(line) - 31; } else { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%cDFS%s/%s%s", last_object, time, lat_str, last_obj_grp, lon_str, last_obj_sym, object_shgd, speed_course, altitude); comment_field_used = strlen(line) - 37; } } else // Beam Heading DFS object { if (strlen(speed_course) != 7) xastir_snprintf(speed_course, sizeof(speed_course), "000/000"); temp_ptr = XmTextFieldGetString(ob_bearing_data); bearing = atoi(temp_ptr); XtFree(temp_ptr); if ( (bearing < 1) || (bearing > 360) ) { bearing = 360; } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ";%-9s*%s%s/%03i/%s%s", last_object, time, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case bearing, object_NRQ, altitude); comment_field_used = strlen(line) - 31; } else { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%03i/%s%s", last_object, time, lat_str, last_obj_grp, lon_str, last_obj_sym, speed_course, bearing, object_NRQ, altitude); comment_field_used = strlen(line) - 37; } } } else // Else it's a normal object { prob_min[0] = '\0'; prob_max[0] = '\0'; if (Probability_circles_enabled) { temp_ptr = XmTextFieldGetString(probability_data_min); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Probability min circle entered: %s\n", line); if (strlen(line) != 0) // Probability circle data was entered { xastir_snprintf(prob_min, sizeof(prob_min), "Pmin%s,", line); } temp_ptr = XmTextFieldGetString(probability_data_max); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Probability max circle entered: %s\n", line); if (strlen(line) != 0) // Probability circle data was entered { xastir_snprintf(prob_max, sizeof(prob_max), "Pmax%s,", line); } } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ";%-9s*%s%s%s%s%s", last_object, time, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case altitude, prob_min, prob_max); comment_field_used = strlen(line) - 31; } else { xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s%s%s", last_object, time, lat_str, last_obj_overlay ? last_obj_overlay : last_obj_grp, lon_str, last_obj_sym, speed_course, altitude, prob_min, prob_max); comment_field_used = strlen(line) - 37; } } // We need to tack the comment on the end, but need to make // sure we don't go over the maximum length for an object. The // maximum comment field is 43 chars. "comment_field_used" // tells us how many chars of that field we've used up already // with other parameters before adding the comment chars to the // end. // //fprintf(stderr,"Comment: %s\n",comment); if (strlen(comment) != 0) { if (comment[0] == '}') { // May be a multipoint polygon string at the start of // the comment field. Add a space before this special // character as multipoints have to start with " }" to // be valid. line[strlen(line) + 1] = '\0'; line[strlen(line)] = ' '; comment_field_used++; } temp = 0; // while ( (strlen(line) < 80) && (temp < (int)strlen(comment)) ) { while ((comment_field_used < 43) && (temp < (int)strlen(comment)) ) { //fprintf(stderr,"temp: %d->%d\t%c\n", temp, strlen(line), comment[temp]); line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; comment_field_used++; } } //fprintf(stderr,"line: %s\n",line); // NOTE: Compressed mode will be shorter still. Account // for that when compressed mode is implemented for objects. return(1); } // Convert this eventually to populate a DataRow struct, then call // data.c:Create_object_item_tx_string(). Right now we have a lot // of code duplication between Setup_object_data, Setup_item_data, // and Create_object_item_tx_string. // // Make sure to look at the "transmit_compressed_objects_items" variable // to decide whether to send a compressed packet. /* * Setup APRS Information Field for Items */ int Setup_item_data(char *line, int line_length, DataRow *p_station) { char lat_str[MAX_LAT]; char lon_str[MAX_LONG]; char ext_lat_str[20]; // Extended precision for base91 compression char ext_lon_str[20]; // Extended precision for base91 compression char comment[43+1]; // max 43 characters of comment char complete_area_color[3]; int complete_area_type; int lat_offset, lon_offset; char complete_corridor[6]; char altitude[10]; char speed_course[8]; int speed; int course; int temp; long temp2; float temp3; char tempstr[MAX_CALLSIGN+1]; char signpost[6]; char prob_min[20+1]; char prob_max[20+1]; int bearing; char *temp_ptr; char *temp_ptr2; int DR = 0; // Dead-reckoning flag int comment_field_used = 0; // Amount of comment field used up // If speed for the original object was non-zero, then we need // to snag the updated DR'ed position for the object. Snag the // current DR position and build the strings we need // for // position transmit. // if (p_station != NULL) { speed = atoi(p_station->speed); if (speed > 0 && !doing_move_operation) { fetch_current_DR_strings(p_station, lat_str, lon_str, ext_lat_str, ext_lon_str); DR++; // Set the dead-reckoning flag } // Keep the time current for our own items. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); } temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(line); //(void)to_upper(line); Not per spec. Don't use this. xastir_snprintf(tempstr, sizeof(tempstr), "%s", line); if (strlen(line) == 1) // Add two spaces (to make 3 minimum chars) { xastir_snprintf(line, line_length, "%s ", tempstr); } else if (strlen(line) == 2) // Add one space (to make 3 minimum chars) { xastir_snprintf(line, line_length, "%s ", tempstr); } if (!valid_item(line)) { return(0); } xastir_snprintf(last_object, sizeof(last_object), "%s", line); if (!DR) // We're not doing dead-reckoning, so proceed { temp_ptr = XmTextFieldGetString(object_lat_data_ns); if((char)toupper((int)temp_ptr[0]) == 'S') { line[0] = 'S'; } else { line[0] = 'N'; } XtFree(temp_ptr); // Check latitude for out-of-bounds temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp > 90) || (temp < 0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lat_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { return(0); } if ( (temp == 90) && (temp3 != 0.0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp_ptr2 = XmTextFieldGetString(object_lat_data_min); xastir_snprintf(lat_str, sizeof(lat_str), "%02d%05.2f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lat_data_deg); temp_ptr2 = XmTextFieldGetString(object_lat_data_min); xastir_snprintf(ext_lat_str, sizeof(ext_lat_str), "%02d%05.3f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.0001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.0001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lon_data_ew); if((char)toupper((int)temp_ptr[0]) == 'E') { line[0] = 'E'; } else { line[0] = 'W'; } XtFree(temp_ptr); // Check longitude for out-of-bounds temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp > 180) || (temp < 0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lon_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { return(0); } if ( (temp == 180) && (temp3 != 0.0) ) { return(0); } temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp_ptr2 = XmTextFieldGetString(object_lon_data_min); xastir_snprintf(lon_str, sizeof(lon_str), "%03d%05.2f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(object_lon_data_deg); temp_ptr2 = XmTextFieldGetString(object_lon_data_min); xastir_snprintf(ext_lon_str, sizeof(ext_lon_str), "%03d%05.3f%c", atoi(temp_ptr), // An attempt was made to round here, adding 0.0001 to the minutes // value. Problems arise if it goes above 59 minutes as the degrees // value would need to bump up also. This then gets into problems // at 90.0 degrees. The correct method would be to convert it to // decimal at a higher precision and then convert it back to DD // MM.MM format. // atof(temp_ptr2) + 0.0001, atof(temp_ptr2), line[0]); XtFree(temp_ptr); XtFree(temp_ptr2); } temp_ptr = XmTextFieldGetString(object_group_data); last_obj_grp = temp_ptr[0]; if(isalpha((int)last_obj_grp)) { last_obj_grp = toupper((int)temp_ptr[0]); // todo: toupper in dialog } XtFree(temp_ptr); // Check for overlay character if (last_obj_grp != '/' && last_obj_grp != '\\') { // Found an overlay character. Check that it's within the // proper range if ( (last_obj_grp >= '0' && last_obj_grp <= '9') || (last_obj_grp >= 'A' && last_obj_grp <= 'Z') ) { last_obj_overlay = last_obj_grp; last_obj_grp = '\\'; } else { last_obj_overlay = '\0'; } } else { last_obj_overlay = '\0'; } temp_ptr = XmTextFieldGetString(object_symbol_data); last_obj_sym = temp_ptr[0]; XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); // Handle Generic Options // Speed/Course Fields temp_ptr = XmTextFieldGetString(ob_course_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); sprintf(speed_course,".../"); // Start with invalid-data string course = 0; if (strlen(line) != 0) // Course was entered { // Need to check for 1 to three digits only, and 001-360 degrees) temp = atoi(line); if ( (temp >= 1) && (temp <= 360) ) { xastir_snprintf(speed_course, sizeof(speed_course), "%03d/", temp); course = temp; } else if (temp == 0) // Spec says 001 to 360 degrees... { sprintf(speed_course, "360/"); } } temp_ptr = XmTextFieldGetString(ob_speed_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); speed = 0; if (strlen(line) != 0) // Speed was entered (we only handle knots currently) { // Need to check for 1 to three digits, no alpha characters temp = atoi(line); if ( (temp >= 0) && (temp <= 999) ) { xastir_snprintf(line, line_length, "%03d", temp); strncat(speed_course, line, sizeof(speed_course) - 1 - strlen(speed_course)); speed = temp; } else { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } } else // No speed entered, blank it out { strncat(speed_course, "...", sizeof(speed_course) - 1 - strlen(speed_course)); } if ( (speed_course[0] == '.') && (speed_course[4] == '.') ) { speed_course[0] = '\0'; // No speed or course entered, so blank it } if (Area_object_enabled) { speed_course[0] = '\0'; // Course/Speed not allowed if Area Object } // Altitude Field temp_ptr = XmTextFieldGetString(ob_altitude_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Altitude entered: %s\n", line); altitude[0] = '\0'; // Start with empty string if (strlen(line) != 0) // Altitude was entered (we only handle feet currently) { // Need to check for all digits, and 1 to 6 digits if (isdigit((int)line[0])) { temp2 = atoi(line); if ((temp2 >= 0) && (temp2 <= 999999)) { char temp_alt[20]; xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld",temp2); memcpy(altitude, temp_alt, sizeof(altitude)); altitude[sizeof(altitude)-1] = '\0'; // Terminate string } } } // Handle Specific Options // Area Items if (Area_object_enabled) { if (Area_bright) // Bright color { xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%2s", Area_color); } else // Dim color { xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02.0f", (float)(atoi(&Area_color[1]) + 8) ); if ((Area_color[1] == '0') || (Area_color[1] == '1')) { complete_area_color[0] = '/'; } } if ( (Area_filled) && (Area_type != 1) && (Area_type != 6) ) { complete_area_type = Area_type + 5; } else // Can't fill in a line { complete_area_type = Area_type; } temp_ptr = XmTextFieldGetString(ob_lat_offset_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); lat_offset = sqrt(atof(line)); if (lat_offset > 99) { lat_offset = 99; } //fprintf(stderr,"Line: %s\tlat_offset: %d\n", line, lat_offset); temp_ptr = XmTextFieldGetString(ob_lon_offset_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); lon_offset = sqrt(atof(line)); if (lon_offset > 99) { lon_offset = 99; } //fprintf(stderr,"Line: %s\tlon_offset: %d\n", line, lon_offset); // Corridor complete_corridor[0] = '\0'; if ( (Area_type == 1) || (Area_type == 6) ) { temp_ptr = XmTextFieldGetString(ob_corridor_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); if (strlen(line) != 0) // We have a line and some corridor data { // Need to check for 1 to three digits only temp = atoi(line); if ( (temp > 0) && (temp <= 999) ) { xastir_snprintf(complete_corridor, sizeof(complete_corridor), "{%d}", temp); //fprintf(stderr,"%s\n",complete_corridor); } } } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ")%s!%s%1d%02d%2s%02d%s%s%s", last_object, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); comment_field_used = strlen(line) - 15 - strlen(last_object); } else { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%1d%02d%2s%02d%s%s%s", last_object, lat_str, last_obj_grp, lon_str, last_obj_sym, complete_area_type, lat_offset, complete_area_color, lon_offset, speed_course, complete_corridor, altitude); comment_field_used = strlen(line) - 21 - strlen(last_object); } } else if (Signpost_object_enabled) { temp_ptr = XmTextFieldGetString(signpost_data); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Signpost entered: %s\n", line); if (strlen(line) != 0) // Signpost data was entered { // Need to check for between one and three characters temp = strlen(line); if ( (temp >= 0) && (temp <= 3) ) { xastir_snprintf(signpost, sizeof(signpost), "{%s}", line); } else { signpost[0] = '\0'; } } else // No signpost data entered, blank it out { signpost[0] = '\0'; } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ")%s!%s%s%s", last_object, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case altitude, signpost); comment_field_used = strlen(line) - 15 - strlen(last_object); } else { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s%s", last_object, lat_str, last_obj_grp, lon_str, last_obj_sym, speed_course, altitude, signpost); comment_field_used = strlen(line) - 21 - strlen(last_object); } } else if (DF_object_enabled) // A DF'ing item of some type { if (Omni_antenna_enabled) { if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ")%s!%sDFS%s/%s%s", last_object, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case object_shgd, speed_course, altitude); comment_field_used = strlen(line) - 15 - strlen(last_object); } else { xastir_snprintf(line, line_length, ")%s!%s%c%s%cDFS%s/%s%s", last_object, lat_str, last_obj_grp, lon_str, last_obj_sym, object_shgd, speed_course, altitude); comment_field_used = strlen(line) - 21 - strlen(last_object); } } else // Beam Heading DFS item { if (strlen(speed_course) != 7) xastir_snprintf(speed_course, sizeof(speed_course), "000/000"); temp_ptr = XmTextFieldGetString(ob_bearing_data); bearing = atoi(temp_ptr); XtFree(temp_ptr); if ( (bearing < 1) || (bearing > 360) ) { bearing = 360; } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ")%s!%s/%03i/%s%s", last_object, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case bearing, object_NRQ, altitude); comment_field_used = strlen(line) - 15 - strlen(last_object); } else { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%03i/%s%s", last_object, lat_str, last_obj_grp, lon_str, last_obj_sym, speed_course, bearing, object_NRQ, altitude); comment_field_used = strlen(line) - 21 - strlen(last_object); } } } else // Else it's a normal item { prob_min[0] = '\0'; prob_max[0] = '\0'; if (Probability_circles_enabled) { temp_ptr = XmTextFieldGetString(probability_data_min); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Probability min circle entered: %s\n", //line); if (strlen(line) != 0) // Probability circle data was entered { xastir_snprintf(prob_min, sizeof(prob_min), "Pmin%s,", line); } temp_ptr = XmTextFieldGetString(probability_data_max); xastir_snprintf(line, line_length, "%s", temp_ptr); XtFree(temp_ptr); //fprintf(stderr,"Probability max circle entered: %s\n", //line); if (strlen(line) != 0) // Probability circle data was entered { xastir_snprintf(prob_max, sizeof(prob_max), "Pmax%s,", line); } } if (transmit_compressed_objects_items) { char temp_overlay = last_obj_overlay; // Need to compute "csT" at some point and add it to the object. // Until we do that we'll have no course/speed/altitude. Looks like // we can have course/speed or altitude, but not both. Must have to // add the "/A=000123" stuff to the end if we want both. // // If we have course and/or speed, use course/speed csT bytes. If // no course/speed but we have altitude, use altitude csT bytes. We // can cheat right now and just always use course/speed, adding // altitude with the altitude extension. Not as efficient, but it // gets the job done. // // Later we should change compress_posit() to accept an altitude // parameter, and have it decide which csT set of bytes to add, and // whether to add altitude as an uncompressed extension if // necessary. // Need to handle the conversion of numeric overlay // chars to "a-j" here. if (last_obj_overlay >= '0' && last_obj_overlay <= '9') { temp_overlay = last_obj_overlay + 'a'; } xastir_snprintf(line, line_length, ")%s!%s%s%s%s", last_object, compress_posit(ext_lat_str, (temp_overlay) ? temp_overlay : last_obj_grp, ext_lon_str, last_obj_sym, course, speed, // In knots ""), // PHG, must be blank in this case altitude, prob_min, prob_max); comment_field_used = strlen(line) - 15 - strlen(last_object); } else { xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s%s%s", last_object, lat_str, last_obj_overlay ? last_obj_overlay : last_obj_grp, lon_str, last_obj_sym, speed_course, altitude, prob_min, prob_max); comment_field_used = strlen(line) - 21 - strlen(last_object); } } // We need to tack the comment on the end, but need to make // sure we don't go over the maximum length for an item. //fprintf(stderr,"Comment: %s\n",comment); if (strlen(comment) != 0) { if (comment[0] == '}') { // May be a multipoint polygon string at the start of // the comment field. Add a space before this special // character as multipoints have to start with " }" to // be valid. line[strlen(line) + 1] = '\0'; line[strlen(line)] = ' '; comment_field_used++; } temp = 0; // while ( (strlen(line) < (64 + strlen(last_object))) && (temp < (int)strlen(comment)) ) { while ( (comment_field_used < 43) && (temp < (int)strlen(comment)) ) { //fprintf(stderr,"temp: %d->%d\t%c\n", temp, strlen(line), comment[temp]); line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; comment_field_used++; } } //fprintf(stderr,"line: %s\n",line); // NOTE: Compressed mode will be shorter still. Account // for that when compressed mode is implemented for items. return(1); } /* * Set an Object */ void Object_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; //fprintf(stderr,"Object_change_data_set\n"); // p_station will be NULL if the object is new. if (Setup_object_data(line, sizeof(line), p_station)) { // Update this object in our save file log_object_item(line,0,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // Keep the time current for our own objects. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Object_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } sched_yield(); // Wait for transmitted data to get processed Object_destroy_shell(widget,clientData,NULL); // Getting a segfault here on a Move operation, so just // comment it out. A redraw will occur shortly anyway. //redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else { // error message popup_message_always(langcode("POPEM00022"),langcode("POPEM00027")); } } /* * Set an Item */ void Item_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; if (Setup_item_data(line,sizeof(line), p_station)) { // Update this item in our save file log_object_item(line,0,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // Keep the time current for our own items. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Item_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback item data, not igating } sched_yield(); // Wait for transmitted data to get processed Object_destroy_shell(widget,clientData,NULL); // Getting a segfault here on a Move operation, so just // comment it out. A redraw will occur shortly anyway. //redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else { // error message popup_message_always(langcode("POPEM00022"),langcode("POPEM00027")); } } // Check the name of a new Object. If it already exists in our // database, warn the user. Confirmation dialog to continue? // void Object_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; char line[MAX_CALLSIGN+1]; DataRow *p_station; temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, sizeof(line), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(line); (void)remove_trailing_spaces(line); //fprintf(stderr,"Object name:%s\n", line); // We have the name now. Check it against our database of // stations/objects/items. Do an exact match. // if (search_station_name(&p_station,line,1) && (p_station->flag & ST_ACTIVE)) { // Found a live object with that name. Don't allow Object // creation. Bring up a warning message instead. popup_message_always(langcode("POPEM00035"), langcode("POPEM00038")); } else { // Not found. Allow the Object to be created. Object_change_data_set(widget, clientData, callData); } } // Check the name of a new Item. If it already exists in our // database, warn the user. Confirmation dialog to continue? // void Item_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; char line[MAX_CALLSIGN+1]; DataRow *p_station; temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, sizeof(line), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(line); (void)remove_trailing_spaces(line); //fprintf(stderr,"Item name:%s\n", line); // We have the name now. Check it against our database of // stations/objects/items. Do an exact match. // if (search_station_name(&p_station,line,1) && (p_station->flag & ST_ACTIVE)) { // Found a live object with that name. Don't allow Object // creation. Bring up a warning message instead. popup_message_always(langcode("POPEM00035"), langcode("POPEM00038")); } else { // Not found. Allow the Item to be created. Item_change_data_set(widget, clientData, callData); } } /* * Delete an Object */ void Object_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; if (Setup_object_data(line, sizeof(line), p_station)) { line[10] = '_'; // mark as deleted object // Update this object in our save file, then comment all // instances out in the file. log_object_item(line,1,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Object_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit object data, not igating } Object_destroy_shell(widget,clientData,NULL); } } /* * Delete an Item */ void Item_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? int i, done; DataRow *p_station = global_parameter1; if (Setup_item_data(line,sizeof(line), p_station)) { done = 0; i = 0; while ( (!done) && (i < 11) ) { if (line[i] == '!') { line[i] = '_'; // mark as deleted object done++; // Exit from loop } i++; } // Update this item in our save file, then comment all // instances out in the file. log_object_item(line,1,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Item_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit item data, not igating } Object_destroy_shell(widget,clientData,NULL); } } /* * Select a symbol graphically */ void Ob_change_symbol(Widget widget, XtPointer clientData, XtPointer callData) { //fprintf(stderr,"Trying to change a symbol\n"); symbol_change_requested_from = 2; // Tell Select_symbol who to return the data to Select_symbol(widget, clientData, callData); } /* * Update symbol picture for changed symbol or table */ void updateObjectPictureCallback(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char table, overlay; char symb, group; char *temp_ptr; XtVaSetValues(object_icon, XmNlabelPixmap, Ob_icon0, NULL); // clear old icon XtManageChild(object_icon); temp_ptr = XmTextFieldGetString(object_group_data); group = temp_ptr[0]; XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(object_symbol_data); symb = temp_ptr[0]; XtFree(temp_ptr); if (group == '/' || group == '\\') { // No overlay character table = group; overlay = ' '; } else { // Found overlay character. Check that it's a valid // overlay. if ( (group >= '0' && group <= '9') || (group >= 'A' && group <= 'Z') ) { // Valid overlay character table = '\\'; overlay = group; } else { // Bad overlay character table = '\\'; overlay = ' '; } } symbol(object_icon,0,table,symb,overlay,Ob_icon,0,0,0,' '); // create icon XtVaSetValues(object_icon,XmNlabelPixmap,Ob_icon,NULL); // draw new icon XtManageChild(object_icon); } // Handler for "Signpost" toggle button void Signpost_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Signpost_object_enabled = 1; Area_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"Signpost Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'm'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Signpost_object_enabled = 0; //fprintf(stderr,"Signpost Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Probability Circles" toggle button void Probability_circle_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Signpost_object_enabled = 0; Area_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 1; //fprintf(stderr,"Probability Circles are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); // Set to hiker symbol by default, but can be changed by // user to something else. temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '['; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Probability_circles_enabled = 0; //fprintf(stderr,"Signpost Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Enable Area Type" toggle button void Area_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Area_object_enabled = 1; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"Area Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); XtSetSensitive(ob_speed,FALSE); XtSetSensitive(ob_speed_data,FALSE); XtSetSensitive(ob_course,FALSE); XtSetSensitive(ob_course_data,FALSE); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'l'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Area_object_enabled = 0; //fprintf(stderr,"Area Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XtSetSensitive(ob_speed,TRUE); XtSetSensitive(ob_speed_data,TRUE); XtSetSensitive(ob_course,TRUE); XtSetSensitive(ob_course_data,TRUE); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "DF Bearing Object" toggle button void DF_bearing_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 1; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"DF Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); XtSetSensitive(ob_speed,TRUE); XtSetSensitive(ob_speed_data,TRUE); XtSetSensitive(ob_course,TRUE); XtSetSensitive(ob_course_data,TRUE); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 0; temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { DF_object_enabled = 0; //fprintf(stderr,"DF Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Map View Object" toggle button void Map_View_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { // Make a bunch of the fields insensitive that we don't use // here. Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 1; Probability_circles_enabled = 0; //fprintf(stderr,"Map View Objects are ENABLED\n"); // Make a bunch of the fields insensitive that we don't use here? // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'E'; // Eyeball symbol temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); XtSetSensitive(ob_option_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Map_View_object_enabled = 0; //fprintf(stderr,"Map View Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); XtSetSensitive(ob_option_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); // Don't want to restore the comment if it is a Map View object, // as Set_Del_Object() changes that field in that case. if (!Map_View_object_enabled) { XmTextFieldSetString(object_comment_data,comment); } } /* Area object type radio buttons */ void Area_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_type = atoi(which); // Set to shape desired if ( (Area_type == 1) || (Area_type == 6) ) // If either line type { //fprintf(stderr,"Line type: %d\n", Area_type); XtSetSensitive(ob_corridor,TRUE); XtSetSensitive(ob_corridor_data,TRUE); XtSetSensitive(ob_corridor_miles,TRUE); XtSetSensitive(open_filled_toggle,FALSE); } else // Not line type { //fprintf(stderr,"Not line type: %d\n", Area_type); XtSetSensitive(ob_corridor,FALSE); XtSetSensitive(ob_corridor_data,FALSE); XtSetSensitive(ob_corridor_miles,FALSE); XtSetSensitive(open_filled_toggle,TRUE); } } else { Area_type = 0; // Open circle //fprintf(stderr,"Type zero\n"); } //fprintf(stderr,"Area type: %d\n", Area_type); } /* Area object color radio buttons */ void Area_color_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_color[0] = which[0]; // Set to color desired. Area_color[1] = which[1]; Area_color[2] = '\0'; } else { Area_color[0] = '/'; Area_color[1] = '0'; // Black Area_color[2] = '\0'; } //fprintf(stderr,"Area color: %s\n", Area_color); } /* Area bright color enable button */ void Area_bright_dim_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_bright = atoi(which); //fprintf(stderr,"Bright colors are ENABLED: %d\n", Area_bright); } else { Area_bright = 0; //fprintf(stderr,"Bright colors are DISABLED: %d\n", Area_bright); } } /* Area filled enable button */ void Area_open_filled_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_filled = atoi(which); //fprintf(stderr,"Filled shapes ENABLED: %d\n", Area_filled); } else { Area_filled = 0; //fprintf(stderr,"Filled shapes DISABLED: %d\n", Area_filled); } } // Handler for "Omni Antenna" toggle button void Omni_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { //fprintf(stderr,"Omni Antenna ENABLED\n"); XmToggleButtonSetState(beam_antenna_toggle, FALSE, FALSE); XtSetSensitive(frameomni,TRUE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 1; Beam_antenna_enabled = 0; } else { //fprintf(stderr,"Omni Antenna DISABLED\n"); XtSetSensitive(frameomni,FALSE); Omni_antenna_enabled = 0; } } // Handler for "Beam Antenna" toggle button void Beam_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { //fprintf(stderr,"Beam Antenna ENABLED\n"); XmToggleButtonSetState(omni_antenna_toggle, FALSE, FALSE); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,TRUE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 1; } else { //fprintf(stderr,"Beam Antenna DISABLED\n"); XtSetSensitive(framebeam,FALSE); Beam_antenna_enabled = 0; } } /* Object signal radio buttons */ void Ob_signal_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[0] = which[0]; // Set to signal quality heard } else { object_shgd[0] = '0'; // 0 (Signal not heard) } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object height radio buttons */ void Ob_height_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[1] = which[0]; // Set to height desired } else { object_shgd[1] = '0'; // 0 (10ft HAAT) } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object gain radio buttons */ void Ob_gain_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[2] = which[0]; // Set to antenna gain desired } else { object_shgd[2] = '0'; // 0dB gain } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object directivity radio buttons */ void Ob_directivity_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[3] = which[0]; // Set to antenna pattern desired } else { object_shgd[3] = '0'; // Omni-directional pattern } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object beamwidth radio buttons */ void Ob_width_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_NRQ[2] = which[0]; // Set to antenna beamwidth desired } else { object_NRQ[2] = '0'; // Beamwidth = "Useless" } object_NRQ[3] = '\0'; //fprintf(stderr,"NRQ: %s\n", object_NRQ); } /* populate predefined object (SAR) struct */ void Populate_predefined_objects(predefinedObject *predefinedObjects) { // The number of objects you are defining below must be // exactly equal to number_of_predefined_objects // and less than MAX_NUMBER_OF_PREDEFINED_OBJECTS. // using counter j for this seems inelegant ** // A set of predefined SAR objects are hardcoded and used by default // other sets of predefined objects (SAR in km, public service event, // and user defined objects) can be loaded from a file. // // Detailed instructions for the format of the files can be found in // the two example files provided: predefined_SAR.sys and // predefined_EVENT.sys char predefined_object_definition_file[263]; int read_file_ok = 0; int line_max_length = 255; int object_read_ok = 0; char line[line_max_length]; char *value; char *variable; FILE *fp_file; int j = 0; char error_correct_location[300]; char predef_obj_path[MAX_VALUE]; #ifdef OBJECT_DEF_FILE_USER_BASE char temp_file_path[MAX_VALUE]; #endif xastir_snprintf(line,sizeof(line),"%s","\0"); xastir_snprintf(predefined_object_definition_file,sizeof(predefined_object_definition_file),"config/%s",predefined_object_definition_filename); get_user_base_dir(predefined_object_definition_file, predef_obj_path, sizeof(predef_obj_path)); number_of_predefined_objects = 0; if (predefined_menu_from_file == 1 ) { // Check to see if a file containing predefined object definitions // exists, if it does, open it and try to read the definitions // if this fails, use the hardcoded SAR default instead. // fprintf(stderr,"Checking for predefined objects menu file\n"); #ifdef OBJECT_DEF_FILE_USER_BASE if (filethere(predef_obj_path)) { fp_file = fopen(predef_obj_path,"r"); #else // OBJECT_DEF_FILE_USER_BASE if (filethere(get_data_base_dir(predefined_object_definition_file))) { fp_file = fopen(get_data_base_dir(predefined_object_definition_file),"r"); #endif // OBJECT_DEF_FILE_USER_BASE xastir_snprintf(error_correct_location, sizeof(error_correct_location), "Loading from %s/%s \n", #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_file_path, sizeof(temp_file_path)), #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config"), #endif // OBJECT_DEF_FILE_USER_BASE predefined_object_definition_file); fprintf(stderr, "%s", error_correct_location); while (!feof(fp_file)) { // read lines to end of file (void)get_line(fp_file, line, line_max_length); // ignore blank lines and lines starting with # if ((strncmp("#",line,1)!=0) && (strlen(line) > 2)) { // if line starts "NAME" begin an object // next five lines should be PAGE, SYMBOL, DATA, MENU, HIDDENCHILD // NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required. // HIDDENCHILD must come last (it is being used to identify the // end of one object). // split line into variable/value pairs on tab // See predefined_SAR.sys and predefined_event.sys for more details. variable = strtok((char *)&line,"\t"); if (strcmp("NAME",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call), "%s", value); // by default, set data to an empty string, allowing DATA to be ommitted xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); object_read_ok ++; } } if (strcmp("PAGE",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page), "%s", value); object_read_ok ++; } } if (strcmp("SYMBOL",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol), "%s", value); object_read_ok ++; } } if (strcmp("DATA",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value == NULL || strcmp(value,"NULL")==0) { xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); } else { xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data), "%s", value); } } if (strcmp("MENU",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call), "%s", value); object_read_ok ++; } } if (strcmp("HIDDENCHILD",variable)==0) { value = strtok(NULL,"\t\r\n"); if (strcmp(value,"YES")==0) { predefinedObjects[j].show_on_menu = 0; predefinedObjects[j].index_of_child = j - 1; predefinedObjects[j].index = j; } else { predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; } if (object_read_ok == 4) { // All elements for an object were read correctly. // Begin filling next element in array. j++; // Read of at least one object was successful, // don't display default hardcoded menu items. read_file_ok = 1; // Reset value counter for next object. object_read_ok = 0; } else { // Something was missing or HIDDENCHILD was out of order. // Don't increment array (overwrite a partly filled entry). fprintf(stderr,"Error in reading predefined object menu file:\nAn object is not correctly defined.\n"); } } } } // end while !feof() fclose(fp_file); if (read_file_ok==0) { fprintf(stderr,"Error in reading predefined objects menu file:\nNo valid objects found.\n"); } } else { fprintf(stderr,"Error: Predefined objects menu file not found.\n"); xastir_snprintf(error_correct_location, sizeof(error_correct_location), "File should be in %s\n", #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_file_path, sizeof(temp_file_path))); #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config")); #endif // OBJECT_DEF_FILE_USER_BASE fprintf(stderr, "%s", error_correct_location); } } if (read_file_ok==0) { // file read failed or was not requested, display default SAR menu // command post xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"ICP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"c"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"ICP: Command Post"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Staging area xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Staging"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"S"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Staging"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Initial Planning Point // set up to draw as two objects with different probability circles xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP_"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.75,Pmax1.0"); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"[not shown]"); // show on menu = 0 will hide this entry on menu predefinedObjects[j].show_on_menu = 0; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.25,Pmax0.5"); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"IPP: InitialPlanningPoint"); predefinedObjects[j].show_on_menu = 1; // index of child j - 1 will add additional callback to IPP_ predefinedObjects[j].index_of_child = j - 1; predefinedObjects[j].index = j; j++; // Point last seen xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"PLS"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"PLS: Point Last Seen"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Last known point xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"LKP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"."); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"LKP: Last Known Point"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Base xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Base"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"B"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Base"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Helibase (helicopter support base) xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Helibase"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"H"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Helibase"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Helispot (helicopter landing spot) // Heli- will be created as Heli-1, Heli-2, Heli-3, etc. // terminal - on a call is a magic character. see Create_SAR+Object. xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Heli-"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Heli-n: Helispot"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Camp xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Camp"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"C"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Camp"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; } // Could read additional entries from a file here. // The total number of entries should be left fairly small // to prevent the menu from becoming too large and unweildy. number_of_predefined_objects = j; if (number_of_predefined_objects>MAX_NUMBER_OF_PREDEFINED_OBJECTS) { // need beter handling of this - we will allready have run // past the end of the array if we have reached here. number_of_predefined_objects=MAX_NUMBER_OF_PREDEFINED_OBJECTS; } } /* Create a predefined SAR/Public Event object Create an object of the specified type at the current mouse position without a dialog. Current undesirable behavior: If an object of the same name exists, takes control of that object and moves it to the current mouse position. clientData is pointer to an integer representing the index of a predefined object in the predefinedObjects array */ void Create_SAR_Object(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { Dimension width, height; char call[MAX_CALLSIGN+1]; long x_lat,x_lon; char origin[MAX_CALLSIGN+1]; // mycall char data[MAX_LINE_SIZE]; char page[2]; // reserve space for probability circle as well as symbol /Pmin0.25,Pmax0.5, char symbol_plus[PREDEFINED_OBJECT_DATA_LENGTH]; char symbol[2]; char c_lon[10]; char c_lat[10]; char time[7]; intptr_t i; DataRow *p_station; int done = 0; int iterations_left = 1000; // Max iterations of while loop below int extra_num = 1; char orig_call[MAX_CALLSIGN+1]; // set some defaults in case of a non-matched value xastir_snprintf(page,sizeof(page),"/"); xastir_snprintf(symbol,sizeof(symbol),"/"); xastir_snprintf(call, sizeof(call), "Marker"); //for (i=0;i -1) { if (i <= number_of_predefined_objects) { xastir_snprintf(page,sizeof(page), "%s", predefinedObjects[i].page); xastir_snprintf(symbol,sizeof(symbol), "%s", predefinedObjects[i].symbol); xastir_snprintf(call, sizeof(call), "%s", predefinedObjects[i].call); xastir_snprintf(symbol_plus, sizeof(symbol_plus), "%s%s",symbol,predefinedObjects[i].data); } } // Get mouse position. XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); x_lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); x_lat = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); if(debug_level & 1) fprintf(stderr, "Creating symbol %s %s at: %lu %lu with calldata: [%li]\n", page, symbol, x_lat, x_lon, (intptr_t)clientData); // CONVERT_LP_NOSP = DDMM.MMN convert_lat_l2s(x_lat, (char *)c_lat, sizeof(c_lat), CONVERT_LP_NOSP); convert_lon_l2s(x_lon, (char *)c_lon, sizeof(c_lon), CONVERT_LP_NOSP); // Save "call" away in "orig_call" so that we can use it again // and again as we try to come up with a unique name for the // object. // xastir_snprintf(orig_call, sizeof(orig_call), "%s", call); // '-' is a magic character. // // If the last character in call is a "-", the symbol is expected // to be a numeric series starting with call-1, so change call to // call-1. This lets us describe Heli- and create Heli-1, Heli-2 // and similar series. Storing call to orig_call before appending // the number should allow the sequence to increment normally. if ((int)'-'==(int)*(call+(strlen(call)-1))) { // make sure that we don't write past the end of call if (strlen(call)flag & (ST_OBJECT | ST_ITEM)) != 0) // It's an object or item { // Check whether object/item has been killed already if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE) { // // The object or item has been killed. Ok to use // this object name. Get out of the while loop and // create the object. // done++; continue; // Next loop iteration (Exit the while loop) } } // If we get to this point we have an object name that matches // another in our database. We must come up with a new name. We // add digits to the end of the original name until we get one that // works for us. /* // If my_callsign (Exact match includes SSID) // if (is_my_call(p_station->origin,1)) { if (is_my_object_item(p_station)) { // The previous object with the same name is owned by // me. // a) MOVE the EXISTING object (default), perhaps with the option // to clear the track. Clearing the track would only take // effect on our local map screen, not on everyone else's. // b) RENAME the NEW object, perhaps tacking a number // onto the end until we get to an unused name. // c) CANCEL request fprintf(stderr, "Object with same name exists, owned by me\n"); // Pop up a new dialog with the various options on it. Save our // state here so that we can create the object in the callbacks for // the next dialog. // // Code goes here... else { // The previous object with the same name is NOT owned // by me. // a) ADOPT the existing object and MOVE it (a very // poor idea). // Same track-clearing as option 1a. // b) RENAME the NEW object (default), perhaps tacking // a number onto the end until we get to an unused // name. // c) CANCEL request fprintf(stderr, "Object with same name exists, owned by %s\n", p_station->origin); // Pop up a new dialog with the various options on it. Save our // state here so that we can create the object in the callbacks for // the next dialog. // // Code goes here... } */ extra_num++; // Append extra_num to the object name (starts at "2"), try // again to see if it is unique. // // Note: Converting to float only to use width specifiers // properly and quiet a compiler warning. xastir_snprintf(num_string, sizeof(num_string), "%2.0f", (float)extra_num); strcpy(call, orig_call); call[sizeof(call)-1] = '\0'; // Terminate string strcat(call, num_string); call[sizeof(call)-1] = '\0'; // Terminate string // ****** Bug ******** // need to check length of call - if it has gone over 9 characters only // the first 9 will be treated as unique, thus FirstAid11 will become FirstAid1 // and become new position for existing FirstAid1. // MAX_CALLSIGN is the constraining global. // In that case, need to fail gracefully and throw an error message. iterations_left--; } // End of while loop if (iterations_left == 0) { // Pop up a message stating that we couldn't find an empty name in // 1000 iterations. Call popup_message_always() fprintf(stderr, "No more iterations left\n"); } xastir_snprintf(origin, sizeof(origin), "%s", my_callsign); xastir_snprintf(time, sizeof(time), "%02d%02d%02d", get_hours(), get_minutes(), get_seconds() ); // Prepare APRS data string using latitude and longitude from mouse click location // and page, symbol, and any additional data from the prepared object. xastir_snprintf(data, sizeof(data), ";%-9s*%sh%s%s%s%s", call, time, c_lat, page, c_lon, symbol_plus); //fprintf(stderr,"Packet:%s\n", data); log_object_item(data,0,last_object); // *********** New objects not being displayed on map untill restart if (object_tx_disable || transmit_disable) { output_my_data(data,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(data,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } // Fill in fields from an existing object/item or create the proper // transmit string for a new object/item from these fields. /* * Setup Object/Item Dialog * clientData = pointer to object struct, if it's a modify or a move operation, * else it's NULL. * If calldata = 2, then we're doing a move object operation. We want in that * case to fill in the new values for lat/long and make them take effect. * If calldata = 1, then we've dropped through Station_info/Station_data * on the way to Modify->Object. * Need to put the tests for the different types of objects * at the top of this function, then the dialog will build properly for * the type of object initially. */ void Set_Del_Object( Widget w, XtPointer clientData, XtPointer calldata) { Dimension width, height; long lat,lon; char lat_str[MAX_LAT]; char lon_str[MAX_LONG]; static Widget ob_pane, ob_scrollwindow, ob_form, ob_name,ob_latlon_frame,ob_latlon_form, ob_lat, ob_lat_deg, ob_lat_min, ob_lon, ob_lon_deg, ob_lon_min, ob_lon_ew, ob_form1, signpost_form, signpost_label, probability_frame,probability_form, probability_label_min, probability_label_max, ob_option_form, area_form, bright_dim_toggle, shape_box,toption1,toption2,toption3,toption4,toption5, color_box,coption1,coption2,coption3,coption4,coption5,coption6,coption7,coption8, formomni, signal_box,soption0,soption1,soption2,soption3,soption4,soption5,soption6,soption7,soption8,soption9, height_box,hoption0,hoption1,hoption2,hoption3,hoption4,hoption5,hoption6,hoption7,hoption8,hoption9, gain_box,goption0,goption1,goption2,goption3,goption4,goption5,goption6,goption7,goption8,goption9, directivity_box,doption0,doption1,doption2,doption3,doption4,doption5,doption6,doption7,doption8, formbeam, width_box,woption0,woption1,woption2,woption3,woption4,woption5,woption6,woption7,woption8,woption9, ob_bearing, ob_lat_offset,ob_lon_offset, ob_sep, ob_button_set,ob_button_del,ob_button_cancel,it_button_set, ob_button_symbol, compute_button; char temp_data[40]; Atom delw; DataRow *p_station = (DataRow *)clientData; Arg al[50]; /* Arg List */ unsigned int ac; /* Arg Count */ long x,y; /* if (p_station != NULL) fprintf(stderr,"Have a pointer to an object. "); else fprintf(stderr,"No pointer, new object? "); if (calldata != NULL) { if (strcmp(calldata,"2") == 0) fprintf(stderr,"Set_Del_Object: calldata: 2. Move object.\n"); else if (strcmp(calldata,"1") == 0) fprintf(stderr,"Set_Del_Object: calldata: 1. Modify object.\n"); else if (strcmp(calldata,"0") == 0) fprintf(stderr,"Set_Del_Object: calldata: 0. New object.\n"); else fprintf(stderr,"Set_Del_Object: calldata: invalid. New object.\n"); } */ // Save the data so that other routines can access it. Some of the // callbacks can only handle one parameter, and we need two. if (p_station != NULL) { global_parameter1 = clientData; } else { global_parameter1 = NULL; } global_parameter2 = calldata; // This function can be invoked from the mouse menus or by being called // directly by other routines. We look at the p_station pointer to decide // how we were called. // if (p_station != NULL) // We were called from the Modify_object() { // or Move() functions //fprintf(stderr,"Got a pointer!\n"); lon = p_station->coord_lon; // Fill in values from the original object lat = p_station->coord_lat; } else { // We were called from the "Create New Object" mouse menu or // by the "Move" option get default position for object, the // position we have clicked at. For the special case of a // Map View object, we instead want the screen center for // this new object. // if (Map_View_object_enabled) { // Get center of screen lon = center_longitude; lat = center_latitude; } else { // Get mouse position XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); lat = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); } } // If the object dialog is up, we need to kill it and draw a new // one so that we have the correct values filled in. if (object_dialog) { Object_destroy_shell( w, object_dialog, NULL); } // Check for the three "Special" types of objects we deal with and set // the global variables for them here. This will result in the correct // type of dialog being drawn for each type of object. // Question: What about for Modify->Object where we're trying to change // the type of the object? if (p_station != NULL) { /* if (calldata != NULL) { if (strcmp(calldata,"2") == 0) fprintf(stderr,"Set_Del_Object: calldata: 2. Move object.\n"); else if (strcmp(calldata,"1") == 0) fprintf(stderr,"Set_Del_Object: calldata: 1. Modify object.\n"); else if (strcmp(calldata,"0") == 0) fprintf(stderr,"Set_Del_Object: calldata: 0. New object.\n"); else fprintf(stderr,"Set_Del_Object: calldata: invalid. New object.\n"); } */ // Check to see whether we should even be here at all! if ( !(p_station->flag & ST_OBJECT) && !(p_station->flag & ST_ITEM)) // Not an object or item { //fprintf(stderr,"flag: %i\n", (int)p_station->flag); popup_message_always(langcode("POPEM00022"), langcode("POPEM00043") ); // "Not an Object/Item!" return; } // Set to known defaults first Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; if (p_station->aprs_symbol.area_object.type != AREA_NONE) // Found an area object { Area_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == 'm') // Found a signpost object && (p_station->aprs_symbol.aprs_type == '\\') ) { Signpost_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == '\\') // Found a DF object && (p_station->aprs_symbol.aprs_type == '/') && ((strlen(p_station->signal_gain) == 7) // That has data associated with it || (strlen(p_station->bearing) == 3) || (strlen(p_station->NRQ) == 3) ) ) { DF_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == 'E') // Found a Map View object && (p_station->aprs_symbol.aprs_type == '/') && (strstr(p_station->power_gain,"RNG") != 0) ) // Has a range value { //fprintf(stderr,"Found a range\n"); Map_View_object_enabled = 1; } else if (p_station->probability_min[0] != '\0' // Found some data || p_station->probability_max[0] != '\0') // Found some data { Probability_circles_enabled = 1; } } //fprintf(stderr,"Area:Signpost:DF %i:%i:%i\n",Area_object_enabled,Signpost_object_enabled,DF_object_enabled); // Ok. The stage is now set to draw the proper type of dialog for the // type of object we're interested in currently. if(object_dialog) // it is already open { (void)XRaiseWindow(XtDisplay(object_dialog), XtWindow(object_dialog)); } else // create new popup window { object_dialog = XtVaCreatePopupShell(langcode("POPUPOB001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); ob_pane = XtVaCreateWidget("Set_Del_Object pane", xmPanedWindowWidgetClass, object_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, ob_pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); ob_form = XtVaCreateWidget("Set_Del_Object ob_form", xmFormWidgetClass, ob_scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Name" ob_name = XtVaCreateManagedWidget(langcode("POPUPOB002"), xmLabelWidgetClass, ob_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // object name object_name_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, ob_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNmaxLength, 9, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_name, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); //----- Frame for table / symbol ob_frame = XtVaCreateManagedWidget("Set_Del_Object ob_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_name_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Station Symbol" // ob_ts (void)XtVaCreateManagedWidget(langcode("WPUPCFS009"), xmLabelWidgetClass, ob_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_form1 = XtVaCreateWidget("Set_Del_Object form1", xmFormWidgetClass, ob_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Group/overlay" ob_group = XtVaCreateManagedWidget(langcode("WPUPCFS010"), xmLabelWidgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // table object_group_data = XtVaCreateManagedWidget("Set_Del_Object group", xmTextFieldWidgetClass, ob_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_group, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Symbol" ob_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS011"), xmLabelWidgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_group_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // symbol object_symbol_data = XtVaCreateManagedWidget("Set_Del_Object symbol", xmTextFieldWidgetClass, ob_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_symbol, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // icon Ob_icon0 = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); Ob_icon = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); object_icon = XtVaCreateManagedWidget("Set_Del_Object icon", xmLabelWidgetClass, ob_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, Ob_icon, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_symbol_data, XmNleftOffset, 15, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_button_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS028"), xmPushButtonGadgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_icon, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_symbol, XmNactivateCallback, Ob_change_symbol, object_dialog); //----- Frame for Lat/Long ob_latlon_frame = XtVaCreateManagedWidget("Set_Del_Object ob_latlon_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Location" //ob_latlon_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB028"), xmLabelWidgetClass, ob_latlon_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_latlon_form = XtVaCreateWidget("Set_Del_Object ob_latlon_form", xmFormWidgetClass, ob_latlon_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "LAT" ob_lat = XtVaCreateManagedWidget(langcode("WPUPCFS003"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lat deg object_lat_data_deg = XtVaCreateManagedWidget("Set_Del_Object lat_deg", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 2, XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "deg" ob_lat_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lat min object_lat_data_min = XtVaCreateManagedWidget("Set_Del_Object lat_min", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "min" ob_lat_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // N/S object_lat_data_ns = XtVaCreateManagedWidget("Set_Del_Object lat_ns", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "(N/S)" // ob_lat_ns (void)XtVaCreateManagedWidget(langcode("WPUPCFS006"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_ns, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "LONG" ob_lon = XtVaCreateManagedWidget(langcode("WPUPCFS007"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // long object_lon_data_deg = XtVaCreateManagedWidget("Set_Del_Object long_deg", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 14, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "deg" ob_lon_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // min object_lon_data_min = XtVaCreateManagedWidget("Set_Del_Object long_min", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 14, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "min" ob_lon_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // E/W object_lon_data_ew = XtVaCreateManagedWidget("Set_Del_Object long_ew", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 14, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "(E/W)" ob_lon_ew = XtVaCreateManagedWidget(langcode("WPUPCFS008"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_ew, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); compute_button = XtVaCreateManagedWidget(langcode("COORD002"), xmPushButtonGadgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_ew, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Fill in the pointers to our input textfields so that the coordinate // calculator can fiddle with them. coordinate_calc_array.calling_dialog = object_dialog; coordinate_calc_array.input_lat_deg = object_lat_data_deg; coordinate_calc_array.input_lat_min = object_lat_data_min; coordinate_calc_array.input_lat_dir = object_lat_data_ns; coordinate_calc_array.input_lon_deg = object_lon_data_deg; coordinate_calc_array.input_lon_min = object_lon_data_min; coordinate_calc_array.input_lon_dir = object_lon_data_ew; // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, ob_latlon_form); // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, "Set_Del_Object"); XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, langcode("POPUPOB001")); //----- Frame for generic options ob_option_frame = XtVaCreateManagedWidget("Set_Del_Object ob_option_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Generic Options" // ob_option_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB027"), xmLabelWidgetClass, ob_option_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_option_form = XtVaCreateWidget("Set_Del_Object ob_option_form", xmFormWidgetClass, ob_option_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Speed" ob_speed = XtVaCreateManagedWidget(langcode("POPUPOB036"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_speed_data = XtVaCreateManagedWidget("Set_Del_Object ob_speed_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_speed, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Course" ob_course = XtVaCreateManagedWidget(langcode("POPUPOB037"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_speed_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_course_data = XtVaCreateManagedWidget("Set_Del_Object ob_course_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_course, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Altitude" ob_altitude = XtVaCreateManagedWidget(langcode("POPUPOB035"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_course_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_altitude_data = XtVaCreateManagedWidget("Set_Del_Object ob_altitude_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_altitude, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //----- Comment Field // "Comment:" ob_comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"), xmLabelWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_option_frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); object_comment_data = XtVaCreateManagedWidget("Set_Del_Object comment", xmTextFieldWidgetClass, ob_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 37, // max 43 without Data Extension XmNmaxLength, 43, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_comment, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_option_frame, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Probability Circles" probabilities_toggle = XtVaCreateManagedWidget(langcode("POPUPOB047"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_latlon_frame, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(probabilities_toggle,XmNvalueChangedCallback,Probability_circle_toggle,(XtPointer)p_station); // "Signpost Enable" signpost_toggle = XtVaCreateManagedWidget(langcode("POPUPOB029"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probabilities_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(signpost_toggle,XmNvalueChangedCallback,Signpost_object_toggle,(XtPointer)p_station); // "Area Enable" area_toggle = XtVaCreateManagedWidget(langcode("POPUPOB008"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(area_toggle,XmNvalueChangedCallback,Area_object_toggle,(XtPointer)p_station); // "Area Enable" df_bearing_toggle = XtVaCreateManagedWidget(langcode("POPUPOB038"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, area_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(df_bearing_toggle,XmNvalueChangedCallback,DF_bearing_object_toggle,(XtPointer)p_station); // "Map View Object" map_view_toggle = XtVaCreateManagedWidget(langcode("POPUPOB048"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, df_bearing_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(map_view_toggle,XmNvalueChangedCallback,Map_View_object_toggle,(XtPointer)p_station); //----- Frame for Probability Circles info if (Probability_circles_enabled) { //fprintf(stderr,"Drawing probability circle data\n"); probability_frame = XtVaCreateManagedWidget("Set_Del_Object probability_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Probability Circles" // probability_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB047"), xmLabelWidgetClass, probability_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_form = XtVaCreateWidget("Set_Del_Object probability_form", xmFormWidgetClass, probability_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Min (mi):" probability_label_min = XtVaCreateManagedWidget(langcode("POPUPOB049"), xmLabelWidgetClass, probability_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_data_min = XtVaCreateManagedWidget("Set_Del_Object probability_data_min", xmTextFieldWidgetClass, probability_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNmaxLength, 10, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, probability_label_min, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Max (mi):" probability_label_max = XtVaCreateManagedWidget(langcode("POPUPOB050"), xmLabelWidgetClass, probability_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_label_min, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_data_max = XtVaCreateManagedWidget("Set_Del_Object probability_data_max", xmTextFieldWidgetClass, probability_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNmaxLength, 10, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, probability_label_max, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_label_min, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for signpost info else if (Signpost_object_enabled) { //fprintf(stderr,"Drawing signpost data\n"); signpost_frame = XtVaCreateManagedWidget("Set_Del_Object signpost_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Signpost" // signpost_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB031"), xmLabelWidgetClass, signpost_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); signpost_form = XtVaCreateWidget("Set_Del_Object signpost_form", xmFormWidgetClass, signpost_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Signpost Data" signpost_label = XtVaCreateManagedWidget(langcode("POPUPOB030"), xmLabelWidgetClass, signpost_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); signpost_data = XtVaCreateManagedWidget("Set_Del_Object signpost_data", xmTextFieldWidgetClass, signpost_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, signpost_label, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for area info else if (Area_object_enabled) { //fprintf(stderr,"Drawing Area data\n"); area_frame = XtVaCreateManagedWidget("Set_Del_Object area_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Area Options" // area_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB007"), xmLabelWidgetClass, area_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); area_form = XtVaCreateWidget("Set_Del_Object area_form", xmFormWidgetClass, area_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Bright Color Enable" bright_dim_toggle = XtVaCreateManagedWidget(langcode("POPUPOB009"), xmToggleButtonGadgetClass, area_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNset, FALSE, // Select default to be OFF MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(bright_dim_toggle,XmNvalueChangedCallback,Area_bright_dim_toggle,"1"); Area_bright = 0; // Set to default each time dialog is created // "Color-Fill Enable" open_filled_toggle = XtVaCreateManagedWidget(langcode("POPUPOB010"), xmToggleButtonGadgetClass, area_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, bright_dim_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNset, FALSE, // Select default to be OFF MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(open_filled_toggle,XmNvalueChangedCallback,Area_open_filled_toggle,"1"); Area_filled = 0; // Set to default each time dialog is created // Shape of object ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; shape_box = XmCreateRadioBox(area_form, "Set_Del_Object Shape Options box", al, ac); XtVaSetValues(shape_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bright_dim_toggle, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,1, NULL); // "Circle" toption1 = XtVaCreateManagedWidget(langcode("POPUPOB011"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption1,XmNvalueChangedCallback,Area_type_toggle,"0"); // "Line-Right '/'" toption2 = XtVaCreateManagedWidget(langcode("POPUPOB013"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption2,XmNvalueChangedCallback,Area_type_toggle,"1"); // "Line-Left '\' toption3 = XtVaCreateManagedWidget(langcode("POPUPOB012"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption3,XmNvalueChangedCallback,Area_type_toggle,"6"); // "Triangle" toption4 = XtVaCreateManagedWidget(langcode("POPUPOB014"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption4,XmNvalueChangedCallback,Area_type_toggle,"3"); // "Rectangle" toption5 = XtVaCreateManagedWidget(langcode("POPUPOB015"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption5,XmNvalueChangedCallback,Area_type_toggle,"4"); // Color of object color_box = XmCreateRadioBox(area_form, "Set_Del_Object Color Options box", al, ac); XtVaSetValues(color_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, shape_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, NULL); XtVaSetValues(color_box, XmNnumColumns,4, NULL); // "Black" coption1 = XtVaCreateManagedWidget(langcode("POPUPOB016"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption1,XmNvalueChangedCallback,Area_color_toggle,"/0"); // "Blue" coption2 = XtVaCreateManagedWidget(langcode("POPUPOB017"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption2,XmNvalueChangedCallback,Area_color_toggle,"/1"); // "Green" coption3 = XtVaCreateManagedWidget(langcode("POPUPOB018"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption3,XmNvalueChangedCallback,Area_color_toggle,"/2"); // "Cyan" coption4 = XtVaCreateManagedWidget(langcode("POPUPOB019"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption4,XmNvalueChangedCallback,Area_color_toggle,"/3"); // "Red" coption5 = XtVaCreateManagedWidget(langcode("POPUPOB020"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption5,XmNvalueChangedCallback,Area_color_toggle,"/4"); // "Violet" coption6 = XtVaCreateManagedWidget(langcode("POPUPOB021"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption6,XmNvalueChangedCallback,Area_color_toggle,"/5"); // "Yellow" coption7 = XtVaCreateManagedWidget(langcode("POPUPOB022"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption7,XmNvalueChangedCallback,Area_color_toggle,"/6"); // "Grey" coption8 = XtVaCreateManagedWidget(langcode("POPUPOB023"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption8,XmNvalueChangedCallback,Area_color_toggle,"/7"); // Latitude offset // "Offset Up" ob_lat_offset = XtVaCreateManagedWidget(langcode("POPUPOB024"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_lat_offset_data = XtVaCreateManagedWidget("Set_Del_Object lat offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNmaxLength, 4, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_offset, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Longitude offset // "Offset Left (except for '/')" ob_lon_offset = XtVaCreateManagedWidget(langcode("POPUPOB025"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_offset_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_lon_offset_data = XtVaCreateManagedWidget("Set_Del_Object long offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNmaxLength, 4, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_offset, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Corridor (Lines only)" ob_corridor = XtVaCreateManagedWidget(langcode("POPUPOB026"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_offset_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_corridor_data = XtVaCreateManagedWidget("Set_Del_Object lat offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_corridor, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Miles" ob_corridor_miles = XtVaCreateManagedWidget(langcode("UNIOP00004"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_corridor_data, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtSetSensitive(ob_corridor,FALSE); XtSetSensitive(ob_corridor_data,FALSE); XtSetSensitive(ob_corridor_miles,FALSE); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, area_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for DF-omni info else if (DF_object_enabled) { //fprintf(stderr,"Drawing DF data\n"); // "Omni Antenna" omni_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB041"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, area_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(omni_antenna_toggle,XmNvalueChangedCallback,Omni_antenna_toggle,(XtPointer)p_station); // "Beam Antenna" beam_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB042"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, omni_antenna_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, area_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(beam_antenna_toggle,XmNvalueChangedCallback,Beam_antenna_toggle,(XtPointer)p_station); frameomni = XtVaCreateManagedWidget("Set_Del_Object frameomni", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // omnilabel (void)XtVaCreateManagedWidget(langcode("POPUPOB039"), xmLabelWidgetClass, frameomni, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formomni = XtVaCreateWidget("Set_Del_Object formomni", xmFormWidgetClass, frameomni, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Power ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; signal_box = XmCreateRadioBox(formomni, "Set_Del_Object Power Radio Box", al, ac); XtVaSetValues(signal_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns, 11, NULL); // No signal detected what-so-ever soption0 = XtVaCreateManagedWidget("0", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption0,XmNvalueChangedCallback,Ob_signal_toggle,"0"); // Detectible signal (Maybe) soption1 = XtVaCreateManagedWidget("1", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption1,XmNvalueChangedCallback,Ob_signal_toggle,"1"); // Detectible signal (certain but not copyable) soption2 = XtVaCreateManagedWidget("2", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption2,XmNvalueChangedCallback,Ob_signal_toggle,"2"); // Weak signal marginally readable soption3 = XtVaCreateManagedWidget("3", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption3,XmNvalueChangedCallback,Ob_signal_toggle,"3"); // Noisy but copyable soption4 = XtVaCreateManagedWidget("4", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption4,XmNvalueChangedCallback,Ob_signal_toggle,"4"); // Some noise but easy to copy soption5 = XtVaCreateManagedWidget("5", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption5,XmNvalueChangedCallback,Ob_signal_toggle,"5"); // Good signal with detectible noise soption6 = XtVaCreateManagedWidget("6", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption6,XmNvalueChangedCallback,Ob_signal_toggle,"6"); // Near full-quieting signal soption7 = XtVaCreateManagedWidget("7", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption7,XmNvalueChangedCallback,Ob_signal_toggle,"7"); // Dead full-quieting signal, no noise detectible soption8 = XtVaCreateManagedWidget("8", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption8,XmNvalueChangedCallback,Ob_signal_toggle,"8"); // Extremely strong signal "pins the meter" soption9 = XtVaCreateManagedWidget("9", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption9,XmNvalueChangedCallback,Ob_signal_toggle,"9"); // Height height_box = XmCreateRadioBox(formomni, "Set_Del_Object Height Radio Box", al, ac); XtVaSetValues(height_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,signal_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 10 Feet hoption0 = XtVaCreateManagedWidget( (english_units) ? "10ft" : "3m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption0,XmNvalueChangedCallback,Ob_height_toggle,"0"); // 20 Feet hoption1 = XtVaCreateManagedWidget( (english_units) ? "20ft" : "6m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption1,XmNvalueChangedCallback,Ob_height_toggle,"1"); // 40 Feet hoption2 = XtVaCreateManagedWidget( (english_units) ? "40ft" : "12m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption2,XmNvalueChangedCallback,Ob_height_toggle,"2"); // 80 Feet hoption3 = XtVaCreateManagedWidget( (english_units) ? "80ft" : "24m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption3,XmNvalueChangedCallback,Ob_height_toggle,"3"); // 160 Feet hoption4 = XtVaCreateManagedWidget( (english_units) ? "160ft" : "49m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption4,XmNvalueChangedCallback,Ob_height_toggle,"4"); // 320 Feet hoption5 = XtVaCreateManagedWidget( (english_units) ? "320ft" : "98m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption5,XmNvalueChangedCallback,Ob_height_toggle,"5"); // 640 Feet hoption6 = XtVaCreateManagedWidget( (english_units) ? "640ft" : "195m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption6,XmNvalueChangedCallback,Ob_height_toggle,"6"); // 1280 Feet hoption7 = XtVaCreateManagedWidget( (english_units) ? "1280ft" : "390m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption7,XmNvalueChangedCallback,Ob_height_toggle,"7"); // 2560 Feet hoption8 = XtVaCreateManagedWidget( (english_units) ? "2560ft" : "780m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption8,XmNvalueChangedCallback,Ob_height_toggle,"8"); // 5120 Feet hoption9 = XtVaCreateManagedWidget( (english_units) ? "5120ft" : "1561m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption9,XmNvalueChangedCallback,Ob_height_toggle,"9"); // Gain gain_box = XmCreateRadioBox(formomni, "Set_Del_Object Gain Radio Box", al, ac); XtVaSetValues(gain_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,height_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 0 dB goption0 = XtVaCreateManagedWidget("0dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption0,XmNvalueChangedCallback,Ob_gain_toggle,"0"); // 1 dB goption1 = XtVaCreateManagedWidget("1dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption1,XmNvalueChangedCallback,Ob_gain_toggle,"1"); // 2 dB goption2 = XtVaCreateManagedWidget("2dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption2,XmNvalueChangedCallback,Ob_gain_toggle,"2"); // 3 dB goption3 = XtVaCreateManagedWidget("3dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption3,XmNvalueChangedCallback,Ob_gain_toggle,"3"); // 4 dB goption4 = XtVaCreateManagedWidget("4dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption4,XmNvalueChangedCallback,Ob_gain_toggle,"4"); // 5 dB goption5 = XtVaCreateManagedWidget("5dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption5,XmNvalueChangedCallback,Ob_gain_toggle,"5"); // 6 dB goption6 = XtVaCreateManagedWidget("6dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption6,XmNvalueChangedCallback,Ob_gain_toggle,"6"); // 7 dB goption7 = XtVaCreateManagedWidget("7dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption7,XmNvalueChangedCallback,Ob_gain_toggle,"7"); // 8 dB goption8 = XtVaCreateManagedWidget("8dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption8,XmNvalueChangedCallback,Ob_gain_toggle,"8"); // 9 dB goption9 = XtVaCreateManagedWidget("9dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption9,XmNvalueChangedCallback,Ob_gain_toggle,"9"); // Gain directivity_box = XmCreateRadioBox(formomni, "Set_Del_Object Directivity Radio Box", al, ac); XtVaSetValues(directivity_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,gain_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // Omni-directional doption0 = XtVaCreateManagedWidget(langcode("WPUPCFS016"), xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption0,XmNvalueChangedCallback,Ob_directivity_toggle,"0"); // 45 NE doption1 = XtVaCreateManagedWidget("45\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption1,XmNvalueChangedCallback,Ob_directivity_toggle,"1"); // 90 E doption2 = XtVaCreateManagedWidget("90\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption2,XmNvalueChangedCallback,Ob_directivity_toggle,"2"); // 135 SE doption3 = XtVaCreateManagedWidget("135\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption3,XmNvalueChangedCallback,Ob_directivity_toggle,"3"); // 180 S doption4 = XtVaCreateManagedWidget("180\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption4,XmNvalueChangedCallback,Ob_directivity_toggle,"4"); // 225 SW doption5 = XtVaCreateManagedWidget("225\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption5,XmNvalueChangedCallback,Ob_directivity_toggle,"5"); // 270 W doption6 = XtVaCreateManagedWidget("270\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption6,XmNvalueChangedCallback,Ob_directivity_toggle,"6"); // 315 NW doption7 = XtVaCreateManagedWidget("315\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption7,XmNvalueChangedCallback,Ob_directivity_toggle,"7"); // 360 N doption8 = XtVaCreateManagedWidget("360\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption8,XmNvalueChangedCallback,Ob_directivity_toggle,"8"); //----- Frame for DF-beam info framebeam = XtVaCreateManagedWidget("Set_Del_Object framebeam", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frameomni, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // beamlabel (void)XtVaCreateManagedWidget(langcode("POPUPOB040"), xmLabelWidgetClass, framebeam, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formbeam = XtVaCreateWidget("Set_Del_Object formbeam", xmFormWidgetClass, framebeam, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Beam width ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; width_box = XmCreateRadioBox(formbeam, "Set_Del_Object Width Box", al, ac); XtVaSetValues(width_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns, 11, NULL); // Useless woption0 = XtVaCreateManagedWidget(langcode("POPUPOB043"), xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption0,XmNvalueChangedCallback,Ob_width_toggle,"0"); // < 240 Degrees woption1 = XtVaCreateManagedWidget("<240\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption1,XmNvalueChangedCallback,Ob_width_toggle,"1"); // < 120 Degrees woption2 = XtVaCreateManagedWidget("<120\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption2,XmNvalueChangedCallback,Ob_width_toggle,"2"); // < 64 Degrees woption3 = XtVaCreateManagedWidget("<64\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption3,XmNvalueChangedCallback,Ob_width_toggle,"3"); // < 32 Degrees woption4 = XtVaCreateManagedWidget("<32\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption4,XmNvalueChangedCallback,Ob_width_toggle,"4"); // < 16 Degrees woption5 = XtVaCreateManagedWidget("<16\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption5,XmNvalueChangedCallback,Ob_width_toggle,"5"); // < 8 Degrees woption6 = XtVaCreateManagedWidget("<8\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption6,XmNvalueChangedCallback,Ob_width_toggle,"6"); // < 4 Degrees woption7 = XtVaCreateManagedWidget("<4\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption7,XmNvalueChangedCallback,Ob_width_toggle,"7"); // < 2 Degrees woption8 = XtVaCreateManagedWidget("<2\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption8,XmNvalueChangedCallback,Ob_width_toggle,"8"); // < 1 Degrees woption9 = XtVaCreateManagedWidget("<1\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption9,XmNvalueChangedCallback,Ob_width_toggle,"9"); // "Bearing" ob_bearing = XtVaCreateManagedWidget(langcode("POPUPOB046"), xmLabelWidgetClass, formbeam, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, width_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Bearing data ob_bearing_data = XtVaCreateManagedWidget("Set_Del_Object ob_bearing_data", xmTextFieldWidgetClass, formbeam, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNmaxLength, 9, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, width_box, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_bearing, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 0; ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framebeam, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } // End of DF-specific widgets //----- No Special options selected. We need a widget here for the next widget to attach to. if (!DF_object_enabled && !Area_object_enabled && !Signpost_object_enabled && !Probability_circles_enabled) { //fprintf(stderr,"No special object types\n"); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Buttons if (p_station != NULL) // We were called from the Modify_object() or Move function { // Change the buttons/callbacks based on whether we're dealing with an item or an object if ((p_station->flag & ST_ITEM) != 0) // Modifying an Item { // Here we need Modify Item/Delete Item/Cancel buttons ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB034"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_set, XmNactivateCallback, Item_change_data_set, object_dialog); // Check whether we own this item if (strcasecmp(p_station->origin,my_callsign)==0) { // We own this item, set up the "Delete" // button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB033"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_del, object_dialog); } else { // Somebody else owns this item, set up the // "Adopt" button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB045"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_set, object_dialog); } } else // Modifying an Object { // Here we need Modify Object/Delete Object/Cancel buttons ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB005"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_set, XmNactivateCallback, Object_change_data_set, object_dialog); // Check whether we own this Object if (strcasecmp(p_station->origin,my_callsign)==0) { // We own this object, set up the "Delete" // button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB004"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_del, object_dialog); } else { // Somebody else owns this object, set up the // "Adopt" button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB044"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_set, object_dialog); } } } else // We were called from Create->Object mouse menu { ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB003"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); it_button_set = XtVaCreateManagedWidget(langcode("POPUPOB006"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Changed to different callback routines here which // check the new object/item name against our internal // database then call // Object_change_data_set/Item_change_data_set if all // ok. If a conflict (object/item already exists), do a // popup_message() instead or bring up a confirmation // dialog before creating the object/item. // //XtAddCallback(ob_button_set, // XmNactivateCallback, // Object_change_data_set, // object_dialog); //XtAddCallback(it_button_set, // XmNactivateCallback, // Item_change_data_set, // object_dialog); XtAddCallback(ob_button_set, XmNactivateCallback, Object_confirm_data_set, object_dialog); XtAddCallback(it_button_set, XmNactivateCallback, Item_confirm_data_set, object_dialog); } ob_button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_cancel, XmNactivateCallback, Object_destroy_shell, object_dialog); // Set ToggleButtons for the current state. Don't notify the callback // functions associated with them or we'll be in an infinite loop. if (Area_object_enabled) { XmToggleButtonSetState(area_toggle, TRUE, FALSE); } if (Signpost_object_enabled) { XmToggleButtonSetState(signpost_toggle, TRUE, FALSE); } if (DF_object_enabled) { XmToggleButtonSetState(df_bearing_toggle, TRUE, FALSE); } if (Map_View_object_enabled) { XmToggleButtonSetState(map_view_toggle, TRUE, FALSE); } if (Probability_circles_enabled) { XmToggleButtonSetState(probabilities_toggle, TRUE, FALSE); } // Fill in current data if object already exists if (p_station != NULL) // We were called from the Modify_object() or Move functions { // Don't allow changing types if the object is already created. // Already tried allowing it, and it causes other problems. XtSetSensitive(area_toggle, FALSE); XtSetSensitive(signpost_toggle, FALSE); XtSetSensitive(df_bearing_toggle, FALSE); XtSetSensitive(map_view_toggle, FALSE); XtSetSensitive(probabilities_toggle, FALSE); XmTextFieldSetString(object_name_data,p_station->call_sign); // Need to make the above field non-editable 'cuz we're trying to modify // _parameters_ of the object and the name has to stay the same in order // to do this. Change the name and we'll be creating a new object instead // of modifying an old one. XtSetSensitive(object_name_data, FALSE); // Would be nice to change the colors too // Check for overlay character if (p_station->aprs_symbol.special_overlay) { // Found an overlay character temp_data[0] = p_station->aprs_symbol.special_overlay; } else // No overlay character { temp_data[0] = p_station->aprs_symbol.aprs_type; } temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = p_station->aprs_symbol.aprs_symbol; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // We only check the first possible comment string in // the record //if (strlen(p_station->comments) > 0) if (Map_View_object_enabled) { if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { char temp[100]; xastir_snprintf(temp, sizeof(temp), "%s%s", p_station->power_gain, p_station->comment_data->text_ptr); XmTextFieldSetString(object_comment_data,temp); } else { XmTextFieldSetString(object_comment_data,p_station->power_gain); } } else if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { XmTextFieldSetString(object_comment_data,p_station->comment_data->text_ptr); } else { XmTextFieldSetString(object_comment_data,""); } // if ( (p_station->aprs_symbol.area_object.type != AREA_NONE) // Found an area object // && Area_object_enabled ) { if (Area_object_enabled) { XtSetSensitive(ob_frame,FALSE); XtSetSensitive(area_frame,TRUE); switch (p_station->aprs_symbol.area_object.type) { case (1): // Line '/' XmToggleButtonSetState(toption2, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); if (p_station->aprs_symbol.area_object.corridor_width > 0) xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.corridor_width ); else { temp_data[0] = '\0'; // Empty string } XmTextFieldSetString( ob_corridor_data, temp_data ); break; case (6): // Line '\' XmToggleButtonGadgetSetState(toption3, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); if (p_station->aprs_symbol.area_object.corridor_width > 0) xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.corridor_width ); else { temp_data[0] = '\0'; // Empty string } XmTextFieldSetString( ob_corridor_data, temp_data ); break; case (3): // Open Triangle XmToggleButtonGadgetSetState(toption4, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; case (4): // Open Rectangle XmToggleButtonGadgetSetState(toption5, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; case (5): // Filled Circle XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (8): // Filled Triangle XmToggleButtonGadgetSetState(toption4, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (9): // Filled Rectangle XmToggleButtonGadgetSetState(toption5, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (0): // Open Circle default: XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; } switch (p_station->aprs_symbol.area_object.color) { case (1): // Blue Bright XmToggleButtonGadgetSetState(coption2, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (2): // Green Bright XmToggleButtonGadgetSetState(coption3, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (3): // Cyan Bright XmToggleButtonGadgetSetState(coption4, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (4): // Red Bright XmToggleButtonGadgetSetState(coption5, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (5): // Violet Bright XmToggleButtonGadgetSetState(coption6, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (6): // Yellow Bright XmToggleButtonGadgetSetState(coption7, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (7): // Gray Bright XmToggleButtonGadgetSetState(coption8, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (8): // Black Dim XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (9): // Blue Dim XmToggleButtonGadgetSetState(coption2, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (10): // Green Dim XmToggleButtonGadgetSetState(coption3, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (11): // Cyan Dim XmToggleButtonGadgetSetState(coption4, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (12): // Red Dim XmToggleButtonGadgetSetState(coption5, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (13): // Violet Dim XmToggleButtonGadgetSetState(coption6, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (14): // Yellow Dim XmToggleButtonGadgetSetState(coption7, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (15): // Gray Dim XmToggleButtonGadgetSetState(coption8, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (0): // Black Bright default: XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; } xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.sqrt_lat_off * p_station->aprs_symbol.area_object.sqrt_lat_off ); XmTextFieldSetString( ob_lat_offset_data, temp_data ); xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.sqrt_lon_off * p_station->aprs_symbol.area_object.sqrt_lon_off ); XmTextFieldSetString( ob_lon_offset_data, temp_data ); } // Done with filling in Area Objects else // Signpost/Probability/Normal Object { // Handle Generic Options (common to Signpost/Normal Objects) if (strlen(p_station->speed) != 0) { xastir_snprintf(temp_data, sizeof(temp_data), "%d", (int)(atof(p_station->speed) + 0.5) ); XmTextFieldSetString( ob_speed_data, temp_data ); } else { XmTextFieldSetString( ob_speed_data, "" ); } if (strlen(p_station->course) != 0) { XmTextFieldSetString( ob_course_data, p_station->course); } else { XmTextFieldSetString( ob_course_data, "" ); } // if ( (p_station->aprs_symbol.aprs_symbol == 'm') // Found a signpost object // && (p_station->aprs_symbol.aprs_type == '\\') // && Signpost_object_enabled) { if (Signpost_object_enabled) { XtSetSensitive(ob_frame,FALSE); XtSetSensitive(signpost_frame,TRUE); XmTextFieldSetString( signpost_data, p_station->signpost); } // Done with filling in Signpost Objects if (Probability_circles_enabled) { // Fetch the min/max fields from the object data and // write that data into the input fields. XmTextFieldSetString( probability_data_min, p_station->probability_min ); XmTextFieldSetString( probability_data_max, p_station->probability_max ); } // else if ( (p_station->aprs_symbol.aprs_type == '/') // Found a DF object // && (p_station->aprs_symbol.aprs_symbol == '\\' )) { if (DF_object_enabled) { XtSetSensitive(ob_frame,FALSE); //fprintf(stderr,"Found a DF object\n"); // Decide if it was an omni-DF object or a beam heading object if (p_station->NRQ[0] == '\0') // Must be an omni-DF object { //fprintf(stderr,"omni-DF\n"); //fprintf(stderr,"Signal_gain: %s\n", p_station->signal_gain); XmToggleButtonSetState(omni_antenna_toggle, TRUE, TRUE); // Set the received signal quality toggle switch (p_station->signal_gain[3]) { case ('1'): // 1 XmToggleButtonGadgetSetState(soption1, TRUE, TRUE); break; case ('2'): // 2 XmToggleButtonGadgetSetState(soption2, TRUE, TRUE); break; case ('3'): // 3 XmToggleButtonGadgetSetState(soption3, TRUE, TRUE); break; case ('4'): // 4 XmToggleButtonGadgetSetState(soption4, TRUE, TRUE); break; case ('5'): // 5 XmToggleButtonGadgetSetState(soption5, TRUE, TRUE); break; case ('6'): // 6 XmToggleButtonGadgetSetState(soption6, TRUE, TRUE); break; case ('7'): // 7 XmToggleButtonGadgetSetState(soption7, TRUE, TRUE); break; case ('8'): // 8 XmToggleButtonGadgetSetState(soption8, TRUE, TRUE); break; case ('9'): // 9 XmToggleButtonGadgetSetState(soption9, TRUE, TRUE); break; case ('0'): // 0 default: XmToggleButtonGadgetSetState(soption0, TRUE, TRUE); break; } // Set the HAAT toggle switch (p_station->signal_gain[4]) { case ('1'): // 20ft XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); break; case ('2'): // 40ft XmToggleButtonGadgetSetState(hoption2, TRUE, TRUE); break; case ('3'): // 80ft XmToggleButtonGadgetSetState(hoption3, TRUE, TRUE); break; case ('4'): // 160ft XmToggleButtonGadgetSetState(hoption4, TRUE, TRUE); break; case ('5'): // 320ft XmToggleButtonGadgetSetState(hoption5, TRUE, TRUE); break; case ('6'): // 640ft XmToggleButtonGadgetSetState(hoption6, TRUE, TRUE); break; case ('7'): // 1280ft XmToggleButtonGadgetSetState(hoption7, TRUE, TRUE); break; case ('8'): // 2560ft XmToggleButtonGadgetSetState(hoption8, TRUE, TRUE); break; case ('9'): // 5120ft XmToggleButtonGadgetSetState(hoption9, TRUE, TRUE); break; case ('0'): // 10ft default: XmToggleButtonGadgetSetState(hoption0, TRUE, TRUE); break; } // Set the antenna gain toggle switch (p_station->signal_gain[5]) { case ('1'): // 1dB XmToggleButtonGadgetSetState(goption1, TRUE, TRUE); break; case ('2'): // 2dB XmToggleButtonGadgetSetState(goption2, TRUE, TRUE); break; case ('3'): // 3dB XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); break; case ('4'): // 4dB XmToggleButtonGadgetSetState(goption4, TRUE, TRUE); break; case ('5'): // 5dB XmToggleButtonGadgetSetState(goption5, TRUE, TRUE); break; case ('6'): // 6dB XmToggleButtonGadgetSetState(goption6, TRUE, TRUE); break; case ('7'): // 7dB XmToggleButtonGadgetSetState(goption7, TRUE, TRUE); break; case ('8'): // 8dB XmToggleButtonGadgetSetState(goption8, TRUE, TRUE); break; case ('9'): // 9dB XmToggleButtonGadgetSetState(goption9, TRUE, TRUE); break; case ('0'): // 0dB default: XmToggleButtonGadgetSetState(goption0, TRUE, TRUE); break; } // Set the antenna directivity toggle switch (p_station->signal_gain[6]) { case ('1'): // 45 XmToggleButtonGadgetSetState(doption1, TRUE, TRUE); break; case ('2'): // 90 XmToggleButtonGadgetSetState(doption2, TRUE, TRUE); break; case ('3'): // 135 XmToggleButtonGadgetSetState(doption3, TRUE, TRUE); break; case ('4'): // 180 XmToggleButtonGadgetSetState(doption4, TRUE, TRUE); break; case ('5'): // 225 XmToggleButtonGadgetSetState(doption5, TRUE, TRUE); break; case ('6'): // 270 XmToggleButtonGadgetSetState(doption6, TRUE, TRUE); break; case ('7'): // 315 XmToggleButtonGadgetSetState(doption7, TRUE, TRUE); break; case ('8'): // 360 XmToggleButtonGadgetSetState(doption8, TRUE, TRUE); break; case ('0'): // Omni default: XmToggleButtonGadgetSetState(doption0, TRUE, TRUE); break; } } else // Must be a beam-heading object { //fprintf(stderr,"beam-heading\n"); XmToggleButtonSetState(beam_antenna_toggle, TRUE, TRUE); XmTextFieldSetString(ob_bearing_data, p_station->bearing); switch (p_station->NRQ[2]) { case ('1'): // 240 XmToggleButtonGadgetSetState(woption1, TRUE, TRUE); break; case ('2'): // 120 XmToggleButtonGadgetSetState(woption2, TRUE, TRUE); break; case ('3'): // 64 XmToggleButtonGadgetSetState(woption3, TRUE, TRUE); break; case ('4'): // 32 XmToggleButtonGadgetSetState(woption4, TRUE, TRUE); break; case ('5'): // 16 XmToggleButtonGadgetSetState(woption5, TRUE, TRUE); break; case ('6'): // 8 XmToggleButtonGadgetSetState(woption6, TRUE, TRUE); break; case ('7'): // 4 XmToggleButtonGadgetSetState(woption7, TRUE, TRUE); break; case ('8'): // 2 XmToggleButtonGadgetSetState(woption8, TRUE, TRUE); break; case ('9'): // 1 XmToggleButtonGadgetSetState(woption9, TRUE, TRUE); break; case ('0'): // Useless default: XmToggleButtonGadgetSetState(woption0, TRUE, TRUE); break; } } } else // Found a normal object { // Nothing needed in this block currently } // Done with filling in Normal objects } // Done with filling in Signpost, DF, or Normal Objects // Handle Generic Options (common to all) // Convert altitude from meters to feet if (strlen(p_station->altitude) != 0) { xastir_snprintf(temp_data, sizeof(temp_data), "%d", (int)((atof(p_station->altitude) / 0.3048) + 0.5) ); XmTextFieldSetString( ob_altitude_data, temp_data ); } else { XmTextFieldSetString( ob_altitude_data, "" ); } } // Else we're creating a new object from scratch: p_station == NULL else { if (Area_object_enabled) { XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); // Black XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); // Dim XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); // Circle } XmTextFieldSetString(object_name_data,""); // Set the symbol type based on the global variables if (Area_object_enabled) { temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'l'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); } else if (Signpost_object_enabled) { temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'm'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XmTextFieldSetString( signpost_data, "" ); XtSetSensitive(ob_frame,FALSE); } else if (Probability_circles_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '['; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XmTextFieldSetString( probability_data_min, "" ); XmTextFieldSetString( probability_data_max, "" ); } else if (DF_object_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // Defaults Omni-DF XmToggleButtonGadgetSetState(soption0, TRUE, TRUE); // Nothing heard XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); // 20 feet HAAT XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); // 3dB gain antenna XmToggleButtonGadgetSetState(doption0, TRUE, TRUE); // No directivity // Defaults Beam-DF XmToggleButtonGadgetSetState(woption5, TRUE, TRUE); // 16 degree beamwidth XtSetSensitive(ob_frame,FALSE); } else if (Map_View_object_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'E'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); XtSetSensitive(ob_option_frame,FALSE); } else // Normal object/item { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); } // Compute the range for the Map View object and store // it in the comment field. if (Map_View_object_enabled) { double top_range, left_range, max_range; char range[10]; Dimension width, height; // Get the display parameters XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); // Find distance from center to top of screen. // top_range = distance from center_longitude, // center_latitude to center_longitude, // center_latitude-((height*scale_y)/2). top_range = calc_distance(center_latitude, center_longitude, NW_corner_latitude, center_longitude); //fprintf(stderr," top_range:%1.0f meters\n", top_range); // Find distance from center to left of screen. // left_range = distance from center_longitude, // center_latitude to // center_longitude-((width*scale_x)/2), // center_latitude. left_range = calc_distance(center_latitude, center_longitude, center_latitude, NW_corner_longitude); //fprintf(stderr,"left_range:%1.0f meters\n", left_range); // Compute greater of the two. This is our range in // meters. if (top_range > left_range) { max_range = top_range; } else { max_range = left_range; } // Convert from meters to miles max_range = max_range / 1000.0; // kilometers max_range = max_range * 0.62137; // miles // Restrict it to four digits. if (max_range > 9999.0) { max_range = 9999.0; } //fprintf(stderr,"Range:%04d miles\n", (int)(max_range + 0.5)); xastir_snprintf(range, sizeof(range), "RNG%04d", (int)(max_range + 0.5)); // Poor man's rounding XmTextFieldSetString(object_comment_data, range); } else { XmTextFieldSetString(object_comment_data,""); } } if (strcmp(calldata,"2") != 0) // Normal Modify->Object or Create->Object behavior { // Fill in original lat/lon values convert_lat_l2s(lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); substr(temp_data,lat_str,2); XmTextFieldSetString(object_lat_data_deg,temp_data); substr(temp_data,lat_str+2,6); XmTextFieldSetString(object_lat_data_min,temp_data); substr(temp_data,lat_str+8,1); XmTextFieldSetString(object_lat_data_ns,temp_data); convert_lon_l2s(lon, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); substr(temp_data,lon_str,3); XmTextFieldSetString(object_lon_data_deg,temp_data); substr(temp_data,lon_str+3,6); XmTextFieldSetString(object_lon_data_min,temp_data); substr(temp_data,lon_str+9,1); XmTextFieldSetString(object_lon_data_ew,temp_data); } else // We're in the middle of moving an object, calldata was "2" { // Fill in new lat/long values //fprintf(stderr,"Here we will fill in the new lat/long values\n"); x = (center_longitude - ((screen_width * scale_x)/2) + (input_x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (input_y * scale_y)); if (x < 0) { x = 0l; // 180W } if (x > 129600000l) { x = 129600000l; // 180E } if (y < 0) { y = 0l; // 90N } if (y > 64800000l) { y = 64800000l; // 90S } convert_lat_l2s(y, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); substr(temp_data,lat_str,2); XmTextFieldSetString(object_lat_data_deg,temp_data); substr(temp_data,lat_str+2,6); XmTextFieldSetString(object_lat_data_min,temp_data); substr(temp_data,lat_str+8,1); XmTextFieldSetString(object_lat_data_ns,temp_data); convert_lon_l2s(x, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); substr(temp_data,lon_str,3); XmTextFieldSetString(object_lon_data_deg,temp_data); substr(temp_data,lon_str+3,6); XmTextFieldSetString(object_lon_data_min,temp_data); substr(temp_data,lon_str+9,1); XmTextFieldSetString(object_lon_data_ew,temp_data); } XtAddCallback(object_group_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog); XtAddCallback(object_symbol_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); pos_dialog(object_dialog); delw = XmInternAtom(XtDisplay(object_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(object_dialog, delw, Object_destroy_shell, (XtPointer)object_dialog); if (Signpost_object_enabled) { XtManageChild(signpost_form); } else if (Probability_circles_enabled) { XtManageChild(probability_form); } else if (Area_object_enabled) { XtManageChild(shape_box); XtManageChild(color_box); XtManageChild(area_form); } else if (DF_object_enabled) { XtManageChild(signal_box); XtManageChild(height_box); XtManageChild(gain_box); XtManageChild(directivity_box); XtManageChild(width_box); XtManageChild(formomni); XtManageChild(formbeam); } XtManageChild(ob_latlon_form); XtManageChild(ob_option_form); XtManageChild(ob_form1); XtManageChild(ob_form); XtManageChild(ob_pane); resize_dialog(ob_form, object_dialog); XtPopup(object_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(object_dialog); XmProcessTraversal(ob_button_cancel, XmTRAVERSE_CURRENT); } // This will cause the move to happen quickly without any button presses. if (calldata != NULL) // If we're doing a "move" operation { if (strcmp(calldata,"2") == 0) { if ((p_station->flag & ST_ITEM) != 0) // Moving an Item { //fprintf(stderr,"Calling Item_change_data_set()\n"); Item_change_data_set(w,object_dialog,object_dialog); // Move it now! //fprintf(stderr,"Done with call\n"); } else // Moving an Object { //fprintf(stderr,"Calling Object_change_data_set()\n"); Object_change_data_set(w,object_dialog,object_dialog); // Move it now! //fprintf(stderr,"Done with call\n"); } } } } // End of Set_Del_Object /* * Change data for current object * If calldata = 2, we're doing a move object operation. Pass the * value on through to Set_Del_Object. */ void Modify_object( Widget w, XtPointer clientData, XtPointer calldata) { DataRow *p_station = clientData; //if (calldata != NULL) // fprintf(stderr,"Modify_object: calldata: %s\n", (char *)calldata); //fprintf(stderr,"Object Name: %s\n", p_station->call_sign); // Only move the object if it is our callsign, else force the // user to adopt the object first, then move it. // // Not exact match (this one is useful for testing) //// if (!is_my_call(p_station->origin,0)) { // if (!is_my_object_item(p_station)) { // // Exact match includes SSID (this one is for production code) // if (!is_my_call(p_station->origin,1)) { if (!is_my_object_item(p_station)) { // It's not from my callsign if (strncmp(calldata,"2",1) == 0) { // We're doing a Move Object operation //fprintf(stderr,"Modify_object: Object not owned by //me!\n"); popup_message_always(langcode("POPEM00035"), langcode("POPEM00042")); return; } } Set_Del_Object( w, p_station, calldata ); } // // Disown function called by object/item decode routines. // If an object/item is received that matches something in our // object.log file, we immediately cease to transmit that object and // we mark each line containing that object in our log file with a // hash mark ('#'). This comments out that object so that the next // time we reboot, we won't start transmitting it again. // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void disown_object_item(char *call_sign, char *new_owner) { char file[200]; char file_temp[200]; FILE *f; FILE *f_temp; char line[300]; char name[15]; int ret; //fprintf(stderr,"disown_object_item, object: %s, new_owner: %s\n", // call_sign, // new_owner); // If it's my call in the new_owner field, then I must have just // deleted the object and am transmitting a killed object for // it. If it's not my call, someone else has assumed control of // the object. // // Comment out any references to the object in the log file so // that we don't start retransmitting it on a restart. if (is_my_call(new_owner,1)) // Exact match includes SSID { //fprintf(stderr,"Commenting out %s in object.log\n", //call_sign); } else { fprintf(stderr,"Disowning '%s': '%s' is taking over control of it.\n", call_sign, new_owner); } get_user_base_dir("config/object.log", file, sizeof(file)); get_user_base_dir("config/object-temp.log", file_temp, sizeof(file_temp)); //fprintf(stderr,"%s\t%s\n",file,file_temp); // Our own internal function from util.c ret = copy_file(file, file_temp); if (ret) { fprintf(stderr,"\n\nCouldn't create temp file %s!\n\n\n", file_temp); return; } // Open the temp file and write to the original file, with hash // marks in front of the appropriate lines. f_temp=fopen(file_temp,"r"); f=fopen(file,"w"); if (f == NULL) { fprintf(stderr,"Couldn't open %s\n",file); return; } if (f_temp == NULL) { fprintf(stderr,"Couldn't open %s\n",file_temp); return; } // Read lines from the temp file and write them to the standard // file, modifying them as necessary. while (fgets(line, 300, f_temp) != NULL) { // Need to check that the length matches for both! Best way // is to parse the object/item name out of the string and // then do a normal string compare between the two. if (line[0] == ';') // Object { substr(name,&line[1],9); name[9] = '\0'; remove_trailing_spaces(name); } else if (line[0] == ')') // Item { int i; // 3-9 char name for (i = 1; i <= 9; i++) { if (line[i] == '!' || line[i] == '_') { name[i-1] = '\0'; break; } name[i-1] = line[i]; } name[9] = '\0'; // In case we never saw '!' || '_' // Don't remove trailing spaces for Items, else we won't // get a match. } else if (line[1] == ';') // Commented out Object { substr(name,&line[2],10); name[9] = '\0'; remove_trailing_spaces(name); } else if (line[1] == ')') // Commented out Item { int i; // 3-9 char name for (i = 2; i <= 10; i++) { if (line[i] == '!' || line[i] == '_') { name[i-1] = '\0'; break; } name[i-1] = line[i]; } name[9] = '\0'; // In case we never saw '!' || '_' // Don't remove trailing spaces for Items, else we won't // get a match. } //fprintf(stderr,"'%s'\t'%s'\n", name, call_sign); if (valid_object(name)) { if ( strcmp(name,call_sign) == 0 ) { // Match. Comment it out in the file unless it's // already commented out. if (line[0] != '#') { fprintf(f,"#%s",line); //fprintf(stderr,"#%s",line); } else { fprintf(f,"%s",line); //fprintf(stderr,"%s",line); } } else { // No match. Copy the line verbatim unless it's // just a // blank line. if (line[0] != '\n') { fprintf(f,"%s",line); //fprintf(stderr,"%s",line); } } } } fclose(f); fclose(f_temp); } // // Logging function called by object/item create/modify routines. // We log each object/item as one line in a file. // // We need to check for objects of the same name in the file, // deleting lines that have the same name, and adding new records to // the end. Actually BAD IDEA! We want to keep the history of the // object so that we can trace its movements later. // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // Change this function so that deleted objects/items get disowned // instead (commented out in the file so that they're not // transmitted again after a restart). See disown_object_item(). // void log_object_item(char *line, int disable_object, char *object_name) { char file[MAX_VALUE]; FILE *f; get_user_base_dir("config/object.log", file, sizeof(file)); f=fopen(file,"a"); if (f!=NULL) { fprintf(f,"%s\n",line); (void)fclose(f); if (debug_level & 1) { fprintf(stderr,"Saving object/item to file: %s",line); } // Comment out all instances of the object/item in the log // file. This will make sure that the object is not // retransmitted again when Xastir is restarted. if (disable_object) { disown_object_item(object_name, my_callsign); } } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } } // // Function to load saved objects and items back into Xastir. This // is called on startup. This implements persistent objects/items // across Xastir restarts. // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // This appears to skip the loading of killed objects/items. We may // instead want to begin transmitting them again until they time // out, then mark them with a '#' in the log file at that point. // void reload_object_item(void) { char file[MAX_VALUE]; FILE *f; char line[300+1]; char line2[350]; int save_state; get_user_base_dir("config/object.log", file, sizeof(file)); f=fopen(file,"r"); if (f!=NULL) { // Turn off duplicate point checking (need this in order to // work with SAR objects). Save state so that we don't mess // it up. save_state = skip_dupe_checking; skip_dupe_checking++; while (fgets(line, 300, f) != NULL) { if (debug_level & 1) { fprintf(stderr,"Loading object/item from file: %s",line); } if (line[0] != '#') // Skip comment lines { xastir_snprintf(line2, sizeof(line2), "%s>%s:%s", my_callsign, VERSIONFRM, line); // Decode this packet. This will put it into our // station database and cause it to be transmitted // at // regular intervals. Port is set to -1 here. decode_ax25_line( line2, DATA_VIA_LOCAL, -1, 1); // Right about here we could do a lookup for the object/item // matching the name and change the timing on it. This could serve // to spread the transmit timing out a bit so that all objects/items // are not transmitted together. Another easier option would be to // change the routine which chooses when to transmit, having it // randomize the numbers a bit each time. I chose the second // option. } } (void)fclose(f); // Restore the skip_dupe_checking state skip_dupe_checking = save_state; // Update the screen redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, screen_width, screen_height, 0, 0); } else { if (debug_level & 1) { fprintf(stderr,"Couldn't open file for reading: %s\n", file); } } // Start transmitting these objects in about 30 seconds. // Prevent transmission of objects until sometime after we're // done with our initial load. last_object_check = sec_now() + 30; } Xastir-Release-2.2.2/src/objects.h000066400000000000000000000144731501463444000167500ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_OBJECTS_H #define XASTIR_OBJECTS_H #include #include // For mutex debugging with Linux threads only #ifdef __linux__ #define MUTEX_DEBUG 1 #endif // __linux__ #ifdef __LCLINT__ #define PACKAGE "xastir" #define VERSION "lclint" #define VERSIONTXT "xastir lclint debug version" #else // __LCLINT__ #define VERSIONTXT PACKAGE " " VERSION #endif // __LCLINT__ extern Widget object_dialog; extern Widget object_group_data; extern Widget object_symbol_data; extern void updateObjectPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern void Draw_All_CAD_Objects(Widget w); extern void Draw_CAD_Objects_erase_dialog(Widget w, XtPointer clientData, XtPointer callData); extern void Draw_CAD_Objects_list_dialog(Widget w, XtPointer clientData, XtPointer callData); extern int draw_CAD_objects_flag; extern int polygon_last_x; extern int polygon_last_y; extern int doing_move_operation; extern char last_object[9+1]; extern char last_obj_grp; extern char last_obj_sym; extern int CAD_draw_objects; extern int CAD_show_label; extern int CAD_show_raw_probability; extern int CAD_show_comment; extern int CAD_show_area; /* JMT - works in FreeBSD */ // Note: weird conditional thing is there just to shut up // "ignoring return value" warnings from GCC on newer Linux systems #define DISABLE_SETUID_PRIVILEGE do { \ if (seteuid(getuid())==0){/* all is well*/} \ if (setegid(getgid())==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)getuid(), (int)getgid()); } \ } while(0) #define ENABLE_SETUID_PRIVILEGE do { \ if (seteuid(euid)==0){/* all is well*/} \ if (setegid(egid)==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)euid, (int)egid); } \ } while(0) // -------------------------------------------------------------------- // // Function protypes and globals to support predefined SAR/Public service // objects. // // // MAX_NUMBER_OF_PREDEFINED_OBJECTS is the maximum number of predefined // objects that can appear on the Create/Move Here popup menu. #define MAX_NUMBER_OF_PREDEFINED_OBJECTS 11 // // PREDEFINED_OBJECT_DATA_LENGTH is the maximum length of a string // that can follow the symbol specifier in a predefined object (such // as a probability circle definition) plus one (for the terminator). #define PREDEFINED_OBJECT_DATA_LENGTH 44 // // number_of_predefined_objects holds the actual number of predefined // objects available to display on the Create/Move popup menu. extern int number_of_predefined_objects; // File name of ~/.xastir/config file containing definitions for // a predefined object menu. extern char predefined_object_definition_filename[256]; // Flag to indicate whether or not to load the predefined objects menu // from the file specified by predefined_object_definition_filename or // to use the hardcoded SAR object set. 0=use hardcoded SAR // 1=use predefined_object_definition_filename extern int predefined_menu_from_file; //extern void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata); extern void Create_SAR_Object(Widget w, XtPointer clientData, XtPointer calldata); typedef struct { char call[MAX_CALLSIGN+1]; // Callsign = object name. char page[2]; // APRS symbol code page. char symbol[2]; // APRS symbol specifier. char data[PREDEFINED_OBJECT_DATA_LENGTH]; // Data following the symbol. char menu_call[26]; // Name to display on menu. intptr_t index; // Index of this object // in the predefinedObjects array. int show_on_menu; // !=1 to hide on menu. int index_of_child; // > -1 to create two objects // in the same place at the // same time, value is the // index of the second object // in the predefinedObjects array. } predefinedObject; // predefinedObjects is an array of predefined object definitions, // once filled using Populate_predefined_objects it can be traversed // to build a list of predefined objects for menus, picklists, or // other user interface controls. // extern predefinedObject predefinedObjects[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; extern void Populate_predefined_objects(predefinedObject *predefinedObjects); // -------------------------------------------------------------------- extern int valid_object(char *name); extern int valid_item(char *name); extern void Object_History_Refresh( Widget w, XtPointer clientData, XtPointer callData); extern void Object_History_Clear( Widget w, XtPointer clientData, XtPointer callData); extern void Move_Object( Widget widget, XtPointer clientData, XtPointer callData); extern void Draw_CAD_Objects_mode( Widget widget, XtPointer clientData, XtPointer callData); extern void Draw_CAD_Objects_close_polygon(Widget w, XtPointer clientData, XtPointer calldata); extern void Draw_CAD_Objects_erase(Widget w, XtPointer clientData, XtPointer calldata); extern void CAD_vertice_allocate(long latitude, long longitude); extern void CAD_object_allocate(long latitude, long longitude); extern void Modify_object( Widget w, XtPointer clientData, XtPointer calldata); extern void Restore_CAD_Objects_from_file(void); extern void disown_object_item(char *call_sign, char *new_owner); extern void log_object_item(char *line, int disable_object, char *object_name); extern void reload_object_item(void); extern void check_and_transmit_objects_items(time_t time); #endif /* XASTIR_OBJECTS_H */ Xastir-Release-2.2.2/src/popup.h000066400000000000000000000026511501463444000164550ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_POPUP_H #define XASTIR_POPUP_H #define MAX_POPUPS 30 #define MAX_POPUPS_TIME 600 /* Max time popups will display 600=10min*/ typedef struct { char name[10]; Widget popup_message_dialog; Widget popup_message_data; Widget pane, scrollwindow, form, button_close; time_t sec_opened; } Popup_Window; /* from popup_gui.c */ extern void popup_gui_init(void); extern void clear_popup_message_windows(void); extern void popup_time_out_check(int curr_sec); #endif /* XASTIR_POPUP_H */ Xastir-Release-2.2.2/src/popup_gui.c000066400000000000000000000272171501463444000173210ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "xastir.h" #include "main.h" #include "popup.h" #include "main.h" #include "lang.h" #include "rotated.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist static Popup_Window pw[MAX_POPUPS]; static Popup_Window pwb; static xastir_mutex popup_message_dialog_lock; void popup_gui_init(void) { init_critical_section( &popup_message_dialog_lock ); } /**** Popup Message ******/ void clear_popup_message_windows(void) { int i; begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:clear_popup_message_windows" ); for (i=0; iMAX_POPUPS_TIME) { XtPopdown(pw[i].popup_message_dialog); begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" ); XtDestroyWidget(pw[i].popup_message_dialog); pw[i].popup_message_dialog = (Widget)NULL; pw[i].popup_message_data = (Widget)NULL; end_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" ); } } } } } void popup_message_always(char *banner, char *message) { XmString msg_str; int j,i; Atom delw; if (disable_all_popups) { return; } if (banner == NULL || message == NULL) { return; } i=0; for (j=0; j -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)XRotDrawAlignedString(XtDisplay(da), id_font, my_rotation, pixmap_alerts, gc, x, y, message, BRIGHT); } else { (void)XRotDrawAlignedString(XtDisplay(da), id_font, my_rotation, pixmap_alerts, gc, x, y, message, BLEFT); } // Schedule a screen update in roughly 3 seconds remove_ID_message_time = sec_now() + 3; pending_ID_message = 1; // Write it to the screen. Symbols/tracks will disappear during // this short interval time. (void)XCopyArea(XtDisplay(da), pixmap_alerts, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else // ATV Screen ID is not enabled { pending_ID_message = 0; } } Xastir-Release-2.2.2/src/rac_data.c000066400000000000000000000306701501463444000170450ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //==================================================================== // Canadian Callsign Lookup // Richard Hagemeyer, VE3UNW // GNU COPYLEFT applies // 1999-11-08 // // For use with XASTIR by Frank Giannandrea //******************************************************************** #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include "xastir.h" #include "rac_data.h" #include "xa_config.h" #include "main.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" /* ==================================================================== */ /* my version of chomp from perl, removes spaces and dashes */ /* */ /* ******************************************************************** */ int chomp(char *input, unsigned int i) { unsigned int x; for (x=i; input[x] == ' ' || input[x] == '-'; x--) { input[x] = '\0'; } return ( (int)(i-x) ); } /* ==================================================================== */ /* build a new (or newer if I check the file date) index file */ /* check for current ic index file */ /* FG: added a date check in case the RAC file has been updated. */ /* AMACALL.LST must have a time stamp newer than the index file */ /* time stamp. Use the touch command on the AMACALL.LST file to */ /* make the time current if necessary. */ /* ******************************************************************** */ int build_rac_index(void) { FILE *fdb; FILE *fndx; unsigned long call_offset = 0; unsigned long x = 0; char racdata[RAC_DATA_LEN+8]; char amacall_path[MAX_VALUE]; get_user_base_dir("data/AMACALL.ndx", amacall_path, sizeof(amacall_path)); /* ==================================================================== */ /* If the index file is there, exit */ /* */ if (filethere(amacall_path)) { /* if file is there make sure the index date is newer */ if(file_time(amacall_path)<=file_time(amacall_path)) { return(1); } else { // RAC index old, rebuilding statusline(langcode("STIFCC0103"), 1); fprintf(stderr,"RAC index is old. Rebuilding index.\n"); // XmTextFieldSetString(text,"RAC Index old rebuilding"); // XtManageChild(text); // XmUpdateDisplay(XtParent(text)); } } /* ==================================================================== */ /* Open the database and index file */ /* */ fdb=fopen(get_data_base_dir("fcc/AMACALL.LST"),"rb"); if (fdb==NULL) { fprintf(stderr,"Build:Could not open RAC data base: %s\n", get_data_base_dir("fcc/AMACALL.LST") ); return(0); } fndx=fopen(amacall_path,"w"); if (fndx==NULL) { fprintf(stderr,"Build:Could not open/create RAC data base index: %s\n", amacall_path ); (void)fclose(fdb); return(0); } /* ==================================================================== */ /* Skip past the header to the first callsign (VA2AA) */ /* */ memset(racdata, 0, sizeof(racdata)); while (!feof(fdb) && strncmp(racdata,"VA",2)) { call_offset = (unsigned long)ftell(fdb); if (fgets(racdata, (int)sizeof(racdata), fdb)==NULL) { fprintf(stderr,"Build:header:Unable to read data base\n"); (void)fclose(fdb); (void)fclose(fndx); fprintf(stderr,"rc=0\n"); return (0); } } /* ==================================================================== */ /* write out the current callsign and RBA of the db file */ /* skip 100 records and do it again until no more */ /* */ while (!feof(fdb)) { fprintf(fndx,"%6.6s%li\n",racdata,(long)call_offset); call_offset = (unsigned long)ftell(fdb); for (x=0; x<=100 && !feof(fdb); x++) if (fgets(racdata, (int)sizeof(racdata), fdb)==NULL) { break; } } (void)fclose(fdb); (void)fclose(fndx); // XmTextFieldSetString(text,""); // XtManageChild(text); return(1); } /* ==================================================================== */ /* Check for ic data base file */ /* Check/build the index */ /* */ /* ******************************************************************** */ int check_rac_data(void) { int rac_data_available = 0; if( filethere( get_data_base_dir("fcc/AMACALL.LST") ) ) { if (build_rac_index()) { rac_data_available=1; } else { fprintf(stderr,"Check:Could not build ic data base index\n"); rac_data_available=0; } } return(rac_data_available); } /* ==================================================================== */ /* The real work. Pass the callsign, get the info */ /* */ /* ******************************************************************** */ int search_rac_data(char *callsign, rac_record *data) { FILE *fdb; FILE *fndx; long call_offset = 0l; char char_offset[16]; char index[32]; int found = 0; rac_record racdata; /*char filler[8];*/ char amacall_path[MAX_VALUE]; get_user_base_dir("data/AMACALL.ndx", amacall_path, sizeof(amacall_path)); xastir_snprintf(index, sizeof(index)," "); xastir_snprintf(racdata.callsign, sizeof(racdata.callsign)," "); /* ==================================================================== */ /* Search thru the index, get the RBA */ /* */ fndx = fopen(amacall_path, "r"); if(fndx != NULL) { if (fgets(index, (int)sizeof(index), fndx) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base index: %s\n", amacall_path ); return (0); } memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string while (!feof(fndx) && strncmp(callsign, index, 6) > 0) { memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string if (fgets(index, (int)sizeof(index), fndx) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base index(2): %s\n", amacall_path ); return (0); } } } else { fprintf(stderr, "Search:Could not open RAC data base index: %s\n", amacall_path ); return (0); } call_offset = atol(char_offset); (void)fclose(fndx); /* ==================================================================== */ /* Now we have our pointer into the main database (text) file. */ /* Start from there and linear search the data. */ /* This will take an avg of 1/2 of the # skipped making the index */ /* */ fdb = fopen(get_data_base_dir("fcc/AMACALL.LST"), "r"); if (fdb != NULL) { (void)fseek(fdb, call_offset, SEEK_SET); if (callsign[5] == '-') { (void)chomp(callsign,5); } while (!feof(fdb) && strncmp((char *)&racdata, callsign, 6) < 0) //WE7U // Problem here: We're sticking 8 bytes too many into racdata! if (fgets((char *)&racdata, sizeof(racdata), fdb) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base: %s\n", amacall_path ); return (0); } } else { fprintf(stderr,"Search:Could not open RAC data base: %s\n", get_data_base_dir("fcc/AMACALL.LST") ); } /* || (callsign[5] == '-' && strncmp((char *)&racdata,callsign,5) < 0)) */ (void)chomp(racdata.callsign, 6); if (!strncmp((char *)racdata.callsign, callsign, 6)) { found = 1; // Some of these cause problems on 64-bit processors, so commented // them out for now. // (void)chomp(racdata.first_name, 35); // (void)chomp(racdata.last_name, 35); // (void)chomp(racdata.address, 70); // (void)chomp(racdata.city, 35); // (void)chomp(racdata.province, 2); // (void)chomp(racdata.postal_code, 10); // (void)chomp(racdata.qual_a, 1); // (void)chomp(racdata.qual_b, 1); // (void)chomp(racdata.qual_c, 1); // (void)chomp(racdata.qual_d, 1); // (void)chomp(racdata.club_name, 141); // (void)chomp(racdata.club_address, 70); // (void)chomp(racdata.club_city, 35); // (void)chomp(racdata.club_province, 2); // (void)chomp(racdata.club_postal_code, 9); xastir_snprintf(data->callsign, sizeof(data->callsign), "%s", racdata.callsign); xastir_snprintf(data->first_name, sizeof(data->first_name), "%s", racdata.first_name); xastir_snprintf(data->last_name, sizeof(data->last_name), "%s", racdata.last_name); xastir_snprintf(data->address, sizeof(data->address), "%s", racdata.address); xastir_snprintf(data->city, sizeof(data->city), "%s", racdata.city); xastir_snprintf(data->province, sizeof(data->province), "%s", racdata.province); xastir_snprintf(data->postal_code, sizeof(data->postal_code), "%s", racdata.postal_code); xastir_snprintf(data->qual_a, sizeof(data->qual_a), "%s", racdata.qual_a); xastir_snprintf(data->qual_b, sizeof(data->qual_b), "%s", racdata.qual_b); xastir_snprintf(data->qual_c, sizeof(data->qual_c), "%s", racdata.qual_c); xastir_snprintf(data->qual_d, sizeof(data->qual_d), "%s", racdata.qual_d); xastir_snprintf(data->club_name, sizeof(data->club_name), "%s", racdata.club_name); xastir_snprintf(data->club_address, sizeof(data->club_address), "%s", racdata.club_address); xastir_snprintf(data->club_city, sizeof(data->club_city), "%s", racdata.club_city); xastir_snprintf(data->club_province, sizeof(data->club_province), "%s", racdata.club_province); xastir_snprintf(data->club_postal_code, sizeof(data->club_postal_code), "%s", racdata.club_postal_code); } (void)fclose(fdb); if (!found) { // "Callsign Search", "Callsign Not Found!" popup_message_always(langcode("STIFCC0101"), langcode("STIFCC0102") ); } return(found); } Xastir-Release-2.2.2/src/rac_data.h000066400000000000000000000034041501463444000170450ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Industry Canada/RAC Database structure * 472 bytes -- filler is club info * qual fields represent basic, 5wpm, 12wpm, advanced */ #ifndef __XASTIR_RAC_DATA_H #define __XASTIR_RAC_DATA_H #define RAC_DATA_LEN 472 typedef struct { char callsign[7]; char first_name[36]; char last_name[36]; char address[71]; char city[36]; char province[3]; char postal_code[11]; char qual_a[2]; char qual_b[2]; char qual_c[2]; char qual_d[2]; char club_name[142]; char club_address[71]; char club_city[36]; char club_province[3]; char club_postal_code[10]; char crlf[2]; char filler[8]; // To prevent overruns } rac_record; extern int search_rac_data(char *callsign, rac_record *data); extern int search_rac_data_appl(char *callsign, rac_record *data); extern int check_rac_data(void); #endif /* __XASTIR_RAC_DATA_H */ Xastir-Release-2.2.2/src/rotated.c000066400000000000000000001332531501463444000167520ustar00rootroot00000000000000 // // Portions Copyright (C) 2000-2023 The Xastir Group // // Note that this version has been changed since xvertext 5.0 in order // to get rid of compiler warnings and such. The original 5.0 notice // is below. --we7u /* ********************************************************************** */ /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ /* ********************************************************************** */ /* BETTER: xvertext now does rotation at any angle!! * * BEWARE: function arguments have CHANGED since version 2.0!! */ /* ********************************************************************** */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "rotated.h" #include "snprintf.h" #include "xastir.h" // Must be last include file #include "leak_detection.h" /* ---------------------------------------------------------------------- */ /* Make sure cache size is set */ #ifndef CACHE_SIZE_LIMIT #define CACHE_SIZE_LIMIT 0 #endif /*CACHE_SIZE_LIMIT */ /* Make sure a cache method is specified */ #ifndef CACHE_XIMAGES #ifndef CACHE_BITMAPS #define CACHE_BITMAPS #endif /*CACHE_BITMAPS*/ #endif /*CACHE_XIMAGES*/ /* ---------------------------------------------------------------------- */ /* Debugging macros */ #ifdef DEBUG static int debug=1; #else // DEBUG static int debug=0; #endif /*DEBUG*/ #define DEBUG_PRINT1(a) if (debug) fprintf(stderr, a) #define DEBUG_PRINT2(a, b) if (debug) fprintf(stderr, a, b) #define DEBUG_PRINT3(a, b, c) if (debug) fprintf(stderr, a, b, c) #define DEBUG_PRINT4(a, b, c, d) if (debug) fprintf(stderr, a, b, c, d) #define DEBUG_PRINT5(a, b, c, d, e) if (debug) fprintf(stderr, a, b, c, d, e) /* ---------------------------------------------------------------------- */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // M_PI // constants used to check for approximate equality with 90, 180, and 270 degrees // (int)((M_PI/2)*1000) #define INT_M_PI_2_1000 1570 // (int)(M_PI*1000) #define INT_M_PI_1000 3141 // (int)((3*M_PI/2)*1000) #define INT_3_M_PI_2_1000 4712 /* ---------------------------------------------------------------------- */ /* A structure holding everything needed for a rotated string */ typedef struct rotated_text_item_template { Pixmap bitmap; XImage *ximage; char *text; char *font_name; Font fid; float angle; int align; float magnify; int cols_in; int rows_in; int cols_out; int rows_out; int nl; int max_width; float *corners_x; float *corners_y; long int size; int cached; struct rotated_text_item_template *next; } RotatedTextItem; RotatedTextItem *first_text_item=NULL; /* ---------------------------------------------------------------------- */ /* A structure holding current magnification and bounding box padding */ static struct style_template { float magnify; int bbx_pad; } style= { 1., 0 }; /* ---------------------------------------------------------------------- */ static char *my_strdup(char *); static char *my_strtok(char *, char *); static XImage *MakeXImage(Display *, int, int); static int XRotPaintAlignedString(Display *,XFontStruct *,float, Drawable, GC, int, int, char*, int, int); static int XRotDrawHorizontalString(Display *, XFontStruct *, Drawable, GC, int, int, char*, int, int); static RotatedTextItem *XRotRetrieveFromCache(Display *, XFontStruct *, float, char *, int); static RotatedTextItem *XRotCreateTextItem(Display *, XFontStruct *, float, char *, int); static void XRotAddToLinkedList(Display *, RotatedTextItem *); static void XRotFreeTextItem(Display *, RotatedTextItem *); static XImage *XRotMagnifyImage(Display *, XImage *); /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Routine to mimic `strdup()' (some machines don't have it) */ /**************************************************************************/ // // This function allocates some memory without freeing it. // static char *my_strdup(char *str) { char *s; if(str==NULL) { return NULL; } s=(char *)malloc((unsigned)(strlen(str)+1)); if(s!=NULL) { xastir_snprintf(s, strlen(str)+1, "%s", str); } else { fprintf(stderr,"Couldn't allocate memory in my_strdup()\n"); } return s; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Routine to replace `strtok' : this one returns a zero length string if */ /* it encounters two consecutive delimiters */ /**************************************************************************/ static char *my_strtok(char *str1, char *str2) { char *ret; int i, j, stop; static int start, len; static char *stext; if(str2==NULL) { return NULL; } /* initialise if str1 not NULL */ if(str1!=NULL) { start=0; stext=str1; len=strlen(str1); } /* run out of tokens ? */ if(start>=len) { return NULL; } /* loop through characters */ for(i=start; i0.) { style.magnify=m; } } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Set the padding used when calculating bounding boxes */ /**************************************************************************/ void XRotSetBoundingBoxPad(int p) { if(p>=0) { style.bbx_pad=p; } } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Create an XImage structure and allocate memory for it */ /**************************************************************************/ // // Function does not free the memory. // static XImage *MakeXImage(Display *dpy, int w, int h) { XImage *I; char *data; /* reserve memory for image */ data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1); if(data==NULL) { fprintf(stderr,"Couldn't allocate memory in MakeXImage()\n"); return NULL; } /* create the XImage */ I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, data, w, h, 8, 0); if(I==NULL) { return NULL; } I->byte_order=I->bitmap_bit_order=MSBFirst; return I; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -no alignment, no background */ /**************************************************************************/ int XRotDrawString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str) { return (XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, str, NONE, 0)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -no alignment, paints background */ /**************************************************************************/ int XRotDrawImageString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, str, NONE, 1)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -does alignment, no background */ /**************************************************************************/ int XRotDrawAlignedString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text, align, 0)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -does alignment, paints background */ /**************************************************************************/ int XRotDrawAlignedImageString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text, align, 1)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Aligns and paints a rotated string */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static int XRotPaintAlignedString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg) { int i; GC my_gc; int xp, yp; float hot_x, hot_y; float hot_xp, hot_yp; float sin_angle, cos_angle; RotatedTextItem *item; Pixmap bitmap_to_paint; /* return early for NULL/empty strings */ if(text==NULL) { return 0; } if(strlen(text)==0) { return 0; } /* manipulate angle to 0<=angle<360 degrees */ while(angle<0) { angle+=360; } while(angle>=360) { angle-=360; } angle*=M_PI/180; /* horizontal text made easy */ if(angle==0. && style.magnify==1.) return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text, align, bg)); /* get a rotated bitmap */ item=XRotRetrieveFromCache(dpy, font, angle, text, align); if(item==NULL) { return(0); } /* this gc has similar properties to the user's gc */ my_gc=XCreateGC(dpy, drawable, 0, 0); XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask, my_gc); /* alignment : which point (hot_x, hot_y) relative to bitmap centre coincides with user's specified point? */ /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { hot_y=(float)item->rows_in/2*style.magnify; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { hot_y=0; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { hot_y=-(float)item->rows_in/2*style.magnify; } else { hot_y=-((float)item->rows_in/2-(float)font->descent)*style.magnify; } /* x position */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { hot_x=-(float)item->max_width/2*style.magnify; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { hot_x=0; } else { hot_x=(float)item->max_width/2*style.magnify; } /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* rotate hot_x and hot_y around bitmap centre */ hot_xp= hot_x*cos_angle - hot_y*sin_angle; hot_yp= hot_x*sin_angle + hot_y*cos_angle; /* text background will be drawn using XFillPolygon */ if(bg) { GC depth_one_gc; XPoint *xpoints; Pixmap empty_stipple; /* reserve space for XPoints, free'd later */ xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint))); if(!xpoints) { fprintf(stderr,"Couldn't allocate memory in XRotPaintAlignedString()\n"); return 1; } /* rotate corner positions */ for(i=0; i<4*item->nl; i++) { xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle + (item->corners_y[i]+hot_y)*sin_angle); xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle + (item->corners_y[i]+hot_y)*cos_angle); } /* we want to swap foreground and background colors here; XGetGCValues() is only available in R4+ */ empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1); depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0); XSetForeground(dpy, depth_one_gc, 0); XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2); XSetStipple(dpy, my_gc, empty_stipple); XSetFillStyle(dpy, my_gc, FillOpaqueStippled); if (item->nl >= 1) { XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "XRotPaintAlignedString: Points too few:%d, skipping XFillPolygon", item->nl); } /* free our resources */ free((char *)xpoints); XFreeGC(dpy, depth_one_gc); XFreePixmap(dpy, empty_stipple); } /* where should top left corner of bitmap go ? */ xp=(float)x-((float)item->cols_out/2 +hot_xp); yp=(float)y-((float)item->rows_out/2 -hot_yp); /* by default we draw the rotated bitmap, solid */ bitmap_to_paint=item->bitmap; /* handle user stippling */ #ifndef X11R3 { GC depth_one_gc; XGCValues values; Pixmap new_bitmap, inverse; /* try and get some GC properties */ if(XGetGCValues(dpy, gc, GCStipple|GCFillStyle|GCForeground|GCBackground| GCTileStipXOrigin|GCTileStipYOrigin, &values)) { /* only do this if stippling requested */ if((values.fill_style==FillStippled || values.fill_style==FillOpaqueStippled) && !bg) { /* opaque stipple: draw rotated text in background colour */ if(values.fill_style==FillOpaqueStippled) { XSetForeground(dpy, my_gc, values.background); XSetFillStyle(dpy, my_gc, FillStippled); XSetStipple(dpy, my_gc, item->bitmap); XSetTSOrigin(dpy, my_gc, xp, yp); XFillRectangle(dpy, drawable, my_gc, xp, yp, item->cols_out, item->rows_out); XSetForeground(dpy, my_gc, values.foreground); } /* this will merge the rotated text and the user's stipple */ new_bitmap=XCreatePixmap(dpy, drawable, item->cols_out, item->rows_out, 1); /* create a GC */ depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0); XSetForeground(dpy, depth_one_gc, 1); XSetBackground(dpy, depth_one_gc, 0); /* set the relative stipple origin */ XSetTSOrigin(dpy, depth_one_gc, values.ts_x_origin-xp, values.ts_y_origin-yp); /* fill the whole bitmap with the user's stipple */ XSetStipple(dpy, depth_one_gc, values.stipple); XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled); XFillRectangle(dpy, new_bitmap, depth_one_gc, 0, 0, item->cols_out, item->rows_out); /* set stipple origin back to normal */ XSetTSOrigin(dpy, depth_one_gc, 0, 0); /* this will contain an inverse copy of the rotated text */ inverse=XCreatePixmap(dpy, drawable, item->cols_out, item->rows_out, 1); /* invert text */ XSetFillStyle(dpy, depth_one_gc, FillSolid); XSetFunction(dpy, depth_one_gc, GXcopyInverted); XCopyArea(dpy, item->bitmap, inverse, depth_one_gc, 0, 0, item->cols_out, item->rows_out, 0, 0); /* now delete user's stipple everywhere EXCEPT on text */ XSetForeground(dpy, depth_one_gc, 0); XSetBackground(dpy, depth_one_gc, 1); XSetStipple(dpy, depth_one_gc, inverse); XSetFillStyle(dpy, depth_one_gc, FillStippled); XSetFunction(dpy, depth_one_gc, GXcopy); XFillRectangle(dpy, new_bitmap, depth_one_gc, 0, 0, item->cols_out, item->rows_out); /* free resources */ XFreePixmap(dpy, inverse); XFreeGC(dpy, depth_one_gc); /* this is the new bitmap */ bitmap_to_paint=new_bitmap; } } } #endif /*X11R3*/ /* paint text using stipple technique */ XSetFillStyle(dpy, my_gc, FillStippled); XSetStipple(dpy, my_gc, bitmap_to_paint); XSetTSOrigin(dpy, my_gc, xp, yp); XFillRectangle(dpy, drawable, my_gc, xp, yp, item->cols_out, item->rows_out); /* free our resources */ XFreeGC(dpy, my_gc); /* stippled bitmap no longer needed */ if(bitmap_to_paint!=item->bitmap) { XFreePixmap(dpy, bitmap_to_paint); } #ifdef CACHE_XIMAGES XFreePixmap(dpy, item->bitmap); #endif /*CACHE_XIMAGES*/ /* if item isn't cached, destroy it completely */ if(!item->cached) { XRotFreeTextItem(dpy,item); } /* we got to the end OK! */ return 0; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Draw a horizontal string in a quick fashion */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static int XRotDrawHorizontalString( Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg) { GC my_gc; int nl=1, i; int height; int xp, yp; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int dir, asc, desc; XCharStruct overall; DEBUG_PRINT1("**\nHorizontal text.\n"); /* this gc has similar properties to the user's gc (including stipple) */ my_gc=XCreateGC(dpy, drawable, 0, 0); XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle| GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc); XSetFont(dpy, my_gc, font->fid); /* count number of sections in string */ if(align!=NONE) for(i=0; i < (int)(strlen(text)-1); i++) if(text[i]=='\n') { nl++; } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* overall font height */ height=font->ascent+font->descent; /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { yp=y+font->ascent; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { yp=y-nl*height/2+font->ascent; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { yp=y-nl*height+font->ascent; } else { yp=y; } // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return 1; } str3=my_strtok(str1, str2); /* loop through each section in the string */ do { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); /* where to draw section in x ? */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { xp=x; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { xp=x-overall.rbearing/2; } else { xp=x-overall.rbearing; } /* draw string onto bitmap */ if(!bg) { XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); } else { XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); } /* move to next line */ yp+=height; str3=my_strtok((char *)NULL, str2); } while(str3!=NULL); free(str1); XFreeGC(dpy, my_gc); return 0; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Query cache for a match with this font/text/angle/alignment */ /* request, otherwise arrange for its creation */ /**************************************************************************/ static RotatedTextItem *XRotRetrieveFromCache( Display *dpy, XFontStruct *font, float angle, char *text, int align) { Font fid; char *font_name=NULL; unsigned long name_value; RotatedTextItem *item=NULL; RotatedTextItem *i1=first_text_item; /* get font name, if it exists */ if(XGetFontProperty(font, XA_FONT, &name_value)) { DEBUG_PRINT1("got font name OK\n"); font_name=XGetAtomName(dpy, name_value); fid=0; } #ifdef CACHE_FID /* otherwise rely (unreliably?) on font ID */ else { DEBUG_PRINT1("can't get fontname, caching FID\n"); font_name=NULL; fid=font->fid; } #else // CACHE_FID /* not allowed to cache font ID's */ else { DEBUG_PRINT1("can't get fontname, can't cache\n"); font_name=NULL; fid=0; } #endif /*CACHE_FID*/ /* look for a match in cache */ /* matching formula: identical text; identical fontname (if defined, font ID's if not); angles close enough (<0.00001 here, could be smaller); HORIZONTAL alignment matches, OR it's a one line string; magnifications the same */ while(i1 && !item) { /* match everything EXCEPT fontname/ID */ if(strcmp(text, i1->text)==0 && fabs(angle-i1->angle)<0.00001 && style.magnify==i1->magnify && (i1->nl==1 || ((align==0)?9:(align-1))%3== ((i1->align==0)?9:(i1->align-1))%3)) { /* now match fontname/ID */ if(font_name!=NULL && i1->font_name!=NULL) { if(strcmp(font_name, i1->font_name)==0) { item=i1; DEBUG_PRINT1("Matched against font names\n"); } else { i1=i1->next; } } #ifdef CACHE_FID else if(font_name==NULL && i1->font_name==NULL) { if(fid==i1->fid) { item=i1; DEBUG_PRINT1("Matched against FID's\n"); } else { i1=i1->next; } } #endif /*CACHE_FID*/ else { i1=i1->next; } } else { i1=i1->next; } } if(item) { DEBUG_PRINT1("**\nFound target in cache.\n"); } if(!item) { DEBUG_PRINT1("**\nNo match in cache.\n"); } /* no match */ if(!item) { /* create new item */ item=XRotCreateTextItem(dpy, font, angle, text, align); if(!item) { return NULL; } /* record what it shows */ // Allocates some memory item->text=my_strdup(text); /* fontname or ID */ if(font_name!=NULL) { // Allocates some memory item->font_name=my_strdup(font_name); item->fid=0; } else { item->font_name=NULL; item->fid=fid; } item->angle=angle; item->align=align; item->magnify=style.magnify; /* cache it */ XRotAddToLinkedList(dpy, item); } if(font_name) { XFree(font_name); } /* if XImage is cached, need to recreate the bitmap */ #ifdef CACHE_XIMAGES { GC depth_one_gc; /* create bitmap to hold rotated text */ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_out, item->rows_out, 1); /* depth one gc */ depth_one_gc=XCreateGC(dpy, item->bitmap, NULL, 0); XSetBackground(dpy, depth_one_gc, 0); XSetForeground(dpy, depth_one_gc, 1); /* make the text bitmap from XImage */ XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0, item->cols_out, item->rows_out); XFreeGC(dpy, depth_one_gc); } #endif /*CACHE_XIMAGES*/ return item; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Create a rotated text item */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static RotatedTextItem *XRotCreateTextItem( Display *dpy, XFontStruct *font, float angle, char *text, int align) { RotatedTextItem *item=NULL; Pixmap canvas; GC font_gc; XImage *I_in; int i, j; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int height; int byte_w_in, byte_w_out; int xp, yp; float sin_angle, cos_angle; int it, jt; float di, dj; int ic=0; float xl, xr, xinc; int byte_out; int dir, asc, desc; XCharStruct overall; int old_cols_in=0, old_rows_in=0; int cols_in2, rows_in2; int intAngle1000; // stores first few digits of angle, // used to avoid problems with rounding error in // recognition of 90 degree angles /* allocate memory */ item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem)); if(!item) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } /* count number of sections in string */ item->nl=1; if(align!=NONE) for(i=0; i < (int)(strlen(text)-1); i++) if(text[i]=='\n') { item->nl++; } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* find width of longest section */ // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); item->max_width=overall.rbearing; /* loop through each section */ do { str3=my_strtok((char *)NULL, str2); if(str3!=NULL) { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); if(overall.rbearing>item->max_width) { item->max_width=overall.rbearing; } } } while(str3!=NULL); free(str1); /* overall font height */ height=font->ascent+font->descent; /* dimensions horizontal text will have */ item->cols_in=item->max_width; item->rows_in=item->nl*height; /* bitmap for drawing on */ canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_in, item->rows_in, 1); /* create a GC for the bitmap */ font_gc=XCreateGC(dpy, canvas, 0, 0); XSetBackground(dpy, font_gc, 0); XSetFont(dpy, font_gc, font->fid); /* make sure the bitmap is blank */ XSetForeground(dpy, font_gc, 0); XFillRectangle(dpy, canvas, font_gc, 0, 0, item->cols_in+1, item->rows_in+1); XSetForeground(dpy, font_gc, 1); /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* text background will be drawn using XFillPolygon */ item->corners_x= (float *)malloc((unsigned)(4*item->nl*sizeof(float))); if(!item->corners_x) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } item->corners_y= (float *)malloc((unsigned)(4*item->nl*sizeof(float))); if(!item->corners_y) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } /* draw text horizontally */ /* start at top of bitmap */ yp=font->ascent; // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); /* loop through each section in the string */ do { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); /* where to draw section in x ? */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { xp=0; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { xp=(item->max_width-overall.rbearing)/2; } else { xp=item->max_width-overall.rbearing; } /* draw string onto bitmap */ XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3)); /* keep a note of corner positions of this string */ item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify; item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2) *style.magnify; item->corners_x[ic+1]=item->corners_x[ic]; item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify; item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+ (float)overall.rbearing*style.magnify; item->corners_y[item->nl*4-1-ic]=item->corners_y[ic]; item->corners_x[item->nl*4-2-ic]= item->corners_x[item->nl*4-1-ic]; item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1]; ic+=2; /* move to next line */ yp+=height; str3=my_strtok((char *)NULL, str2); } while(str3!=NULL); free(str1); /* create image to hold horizontal text */ I_in=MakeXImage(dpy, item->cols_in, item->rows_in); if(I_in==NULL) { return NULL; } /* extract horizontal text */ XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in, 1, XYPixmap, I_in, 0, 0); I_in->format=XYBitmap; /* magnify horizontal text */ if(style.magnify!=1.) { I_in=XRotMagnifyImage(dpy, I_in); old_cols_in=item->cols_in; old_rows_in=item->rows_in; item->cols_in=(float)item->cols_in*style.magnify; item->rows_in=(float)item->rows_in*style.magnify; } /* how big will rotated text be ? */ item->cols_out=fabs((float)item->rows_in*sin_angle) + fabs((float)item->cols_in*cos_angle) +0.99999 +2; item->rows_out=fabs((float)item->rows_in*cos_angle) + fabs((float)item->cols_in*sin_angle) +0.99999 +2; if(item->cols_out%2==0) { item->cols_out++; } if(item->rows_out%2==0) { item->rows_out++; } /* create image to hold rotated text */ item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out); if(item->ximage==NULL) { return NULL; } byte_w_in=(item->cols_in-1)/8+1; byte_w_out=(item->cols_out-1)/8+1; /* we try to make this bit as fast as possible - which is why it looks a bit over-the-top */ /* vertical distance from centre */ dj=0.5-(float)item->rows_out/2; /* where abouts does text actually lie in rotated image? */ intAngle1000 = (int)(angle*1000); if ( intAngle1000==0 || intAngle1000==INT_M_PI_2_1000 || intAngle1000==INT_M_PI_1000 || intAngle1000==INT_3_M_PI_2_1000 ) { // 0, 90, 180, 270 degrees are special cases // floating point errors may prevent recognition of them unless // we round off, that is a value that started as 180 may not be // recognized as == M_PI/2. Rounding to .001 radian seems a // reasonable choice for the purpose of orienting text strings. xl=0; xr=(float)item->cols_out; xinc=0; } else if(anglecols_out/2+ (dj-(float)item->rows_in/(2*cos_angle))/ tan(angle)-2; xr=(float)item->cols_out/2+ (dj+(float)item->rows_in/(2*cos_angle))/ tan(angle)+2; xinc=1./tan(angle); } else { xl=(float)item->cols_out/2+ (dj+(float)item->rows_in/(2*cos_angle))/ tan(angle)-2; xr=(float)item->cols_out/2+ (dj-(float)item->rows_in/(2*cos_angle))/ tan(angle)+2; xinc=1./tan(angle); } // Set up some constants for loops below cols_in2 = item->cols_in / 2; rows_in2 = item->rows_in / 2; // Handle special cases of 90 degree rotation if ( intAngle1000 == INT_M_PI_2_1000 ) { // angle is 180 degrees, text is rotated 90 degrees from horizontal and runs up x axis for(j=0; jrows_out; j++) { di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2; byte_out=(item->rows_out-j-1)*byte_w_out; for(i=((xl<0)?0:(int)xl); i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) { jt=(float)rows_in2 + di; it=(float)cols_in2 + dj; if(it>=0 && itcols_in && jt>=0 && jtrows_in) if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0) { item->ximage->data[byte_out+i/8]|=128>>i%8; } di+=1; } dj+=1; xl+=xinc; xr+=xinc; } // handling for special cases of 90 and 270 not written yet. // need elseif clauses here. } else { // not a 90 degree rotation, use sin/cos transform /* loop through all relevant bits in rotated image */ for(j=0; jrows_out; j++) { float dj_sin, dj_cos; float temp_it, temp_jt; /* no point re-calculating these every pass */ di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2; byte_out=(item->rows_out-j-1)*byte_w_out; // New code: Calculate these outside the inner loop for // major speed gains. dj_sin = dj * sin_angle; dj_cos = dj * cos_angle; temp_it = (float)cols_in2 + dj_sin; temp_jt = (float)rows_in2 - dj_cos; /* loop through meaningful columns */ for(i=((xl<0)?0:(int)xl); i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) { // rotate coordinates // Original code (very slow) //it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle); //jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle); // New code (much faster) //it=(float)cols_in2 + ( di*cos_angle + dj_sin); //jt=(float)rows_in2 - (-di*sin_angle + dj_cos); it=(float)temp_it + di*cos_angle; jt=(float)temp_jt + di*sin_angle; /* set pixel if required */ if(it>=0 && itcols_in && jt>=0 && jtrows_in) if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0) { item->ximage->data[byte_out+i/8]|=128>>i%8; } di+=1; } dj+=1; xl+=xinc; xr+=xinc; } } XDestroyImage(I_in); if(style.magnify!=1.) { item->cols_in=old_cols_in; item->rows_in=old_rows_in; } #ifdef CACHE_BITMAPS /* create a bitmap to hold rotated text */ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_out, item->rows_out, 1); /* make the text bitmap from XImage */ XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0, item->cols_out, item->rows_out); XDestroyImage(item->ximage); #endif /*CACHE_BITMAPS*/ XFreeGC(dpy, font_gc); XFreePixmap(dpy, canvas); return item; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Adds a text item to the end of the cache, removing as many items */ /* from the front as required to keep cache size below limit */ /**************************************************************************/ static void XRotAddToLinkedList( Display *dpy, RotatedTextItem *item) { static long int current_size=0; static RotatedTextItem *last=NULL; RotatedTextItem *i1=first_text_item, *i2=NULL; #ifdef CACHE_BITMAPS /* I don't know how much memory a pixmap takes in the server - probably this + a bit more we can't account for */ item->size=((item->cols_out-1)/8+1)*item->rows_out; #else // CACHE_BITMAPS /* this is pretty much the size of a RotatedTextItem */ item->size=((item->cols_out-1)/8+1)*item->rows_out + sizeof(XImage) + strlen(item->text) + item->nl*8*sizeof(float) + sizeof(RotatedTextItem); if(item->font_name!=NULL) { item->size+=strlen(item->font_name); } else { item->size+=sizeof(Font); } #endif /*CACHE_BITMAPS */ #ifdef DEBUG /* count number of items in cache, for debugging */ { int i=0; while(i1) { i++; i1=i1->next; } DEBUG_PRINT2("Cache has %d items.\n", i); i1=first_text_item; } #endif // DEBUG DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n", current_size, item->size, (long)(CACHE_SIZE_LIMIT*1024)); /* if this item is bigger than whole cache, forget it */ if(item->size>CACHE_SIZE_LIMIT*1024) { DEBUG_PRINT1("Too big to cache\n\n"); item->cached=0; return; } /* remove elements from cache as needed */ while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) { DEBUG_PRINT2("Removed %d bytes\n", (int)i1->size); if(i1->font_name!=NULL) DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n", i1->text, i1->font_name, i1->angle, i1->align); #ifdef CACHE_FID if(i1->font_name==NULL) DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n", i1->text, i1->fid, i1->angle, i1->align); #endif /*CACHE_FID*/ current_size-=i1->size; i2=i1->next; /* free resources used by the unlucky item */ XRotFreeTextItem(dpy, i1); /* remove it from linked list */ first_text_item=i2; i1=i2; } /* add new item to end of linked list */ if(first_text_item==NULL) { item->next=NULL; first_text_item=item; last=item; } else { item->next=NULL; last->next=item; last=item; } /* new cache size */ current_size+=item->size; item->cached=1; DEBUG_PRINT1("Added item to cache.\n"); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Free the resources used by a text item */ /**************************************************************************/ static void XRotFreeTextItem( Display *dpy, RotatedTextItem *item) { free(item->text); if(item->font_name!=NULL) { free(item->font_name); } free((char *)item->corners_x); free((char *)item->corners_y); #ifdef CACHE_BITMAPS XFreePixmap(dpy, item->bitmap); #else // CACHE_BITMAPS XDestroyImage(item->ximage); #endif /* CACHE_BITMAPS */ free((char *)item); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Magnify an XImage using bilinear interpolation */ /**************************************************************************/ static XImage *XRotMagnifyImage( Display *dpy, XImage *ximage) { int i, j; float x, y; float u,t; XImage *I_out; int cols_in, rows_in; int cols_out, rows_out; int i2, j2; float z1, z2, z3, z4; int byte_width_in, byte_width_out; float mag_inv; /* size of input image */ cols_in=ximage->width; rows_in=ximage->height; /* size of final image */ cols_out=(float)cols_in*style.magnify; rows_out=(float)rows_in*style.magnify; /* this will hold final image */ I_out=MakeXImage(dpy, cols_out, rows_out); if(I_out==NULL) { return NULL; } /* width in bytes of input, output images */ byte_width_in=(cols_in-1)/8+1; byte_width_out=(cols_out-1)/8+1; /* for speed */ mag_inv=1./style.magnify; y=0.; /* loop over magnified image */ for(j2=0; j2data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=z1; z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; z4=z3; } /* top edge */ else if(i!=cols_in-1 && j==rows_in-1) { t=x-(float)i; u=0; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z3=z2; z4=z1; } /* top right corner */ else if(i==cols_in-1 && j==rows_in-1) { u=0; t=0; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=z1; z3=z1; z4=z1; } /* somewhere `safe' */ else { t=x-(float)i; u=y-(float)j; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; } /* if interpolated value is greater than 0.5, set bit */ if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5) { I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8; } x+=mag_inv; } y+=mag_inv; } /* destroy original */ XDestroyImage(ximage); /* return big image */ return I_out; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Calculate the bounding box some text will have when painted */ /**************************************************************************/ // // This function allocates some memory, frees all but xp_out which // is returned. // XPoint *XRotTextExtents( Display * UNUSED(dpy), XFontStruct *font, float angle, int x, int y, char *text, int align) { int i; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int height; float sin_angle, cos_angle; int nl, max_width; int cols_in, rows_in; float hot_x, hot_y; XPoint *xp_in, *xp_out; int dir, asc, desc; XCharStruct overall; /* manipulate angle to 0<=angle<360 degrees */ while(angle<0) { angle+=360; } while(angle>360) { angle-=360; } angle*=M_PI/180; /* count number of sections in string */ nl=1; if(align!=NONE) { for (i=0; i < (int)(strlen(text)-1); i++) { if(text[i]=='\n') { nl++; } } } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* find width of longest section */ // Allocates some memory, free'd below str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); max_width=overall.rbearing; /* loop through each section */ do { str3=my_strtok((char *)NULL, str2); if(str3!=NULL) { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); if(overall.rbearing>max_width) { max_width=overall.rbearing; } } } while(str3!=NULL); free(str1); /* overall font height */ height=font->ascent+font->descent; /* dimensions horizontal text will have */ cols_in=max_width; rows_in=nl*height; /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { hot_y=(float)rows_in/2*style.magnify; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { hot_y=0; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { hot_y=-(float)rows_in/2*style.magnify; } else { hot_y=-((float)rows_in/2-(float)font->descent)*style.magnify; } /* x position */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { hot_x=-(float)max_width/2*style.magnify; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { hot_x=0; } else { hot_x=(float)max_width/2*style.magnify; } /* reserve space for XPoints */ xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); if(!xp_in) { fprintf(stderr,"Couldn't allocate memory in XRotTextExtents()\n"); return NULL; } xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); if(!xp_out) { fprintf(stderr,"Couldn't allocate memory in XRotTextExtents()\n"); return NULL; } /* bounding box when horizontal, relative to bitmap centre */ xp_in[0].x=-(float)cols_in*style.magnify/2-style.bbx_pad; xp_in[0].y= (float)rows_in*style.magnify/2+style.bbx_pad; xp_in[1].x= (float)cols_in*style.magnify/2+style.bbx_pad; xp_in[1].y= (float)rows_in*style.magnify/2+style.bbx_pad; xp_in[2].x= (float)cols_in*style.magnify/2+style.bbx_pad; xp_in[2].y=-(float)rows_in*style.magnify/2-style.bbx_pad; xp_in[3].x=-(float)cols_in*style.magnify/2-style.bbx_pad; xp_in[3].y=-(float)rows_in*style.magnify/2-style.bbx_pad; xp_in[4].x=xp_in[0].x; xp_in[4].y=xp_in[0].y; /* rotate and translate bounding box */ for(i=0; i<5; i++) { xp_out[i].x=(float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle + ((float)xp_in[i].y+hot_y)*sin_angle); xp_out[i].y=(float)y + (-((float)xp_in[i].x-hot_x)*sin_angle + ((float)xp_in[i].y+hot_y)*cos_angle); } free((char *)xp_in); return xp_out; } Xastir-Release-2.2.2/src/rotated.h000066400000000000000000000053051501463444000167530ustar00rootroot00000000000000 // // Portions Copyright (C) 2000-2023 The Xastir Group // /* ************************************************************************ */ /* Header file for the `xvertext 5.0' routines. Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */ /* ************************************************************************ */ #ifndef _XVERTEXT_INCLUDED_ #define _XVERTEXT_INCLUDED_ #define XV_VERSION 5.0 #define XV_COPYRIGHT \ "xvertext routines Copyright (c) 1993 Alan Richardson" /* ---------------------------------------------------------------------- */ /* text alignment */ #define NONE 0 #define TLEFT 1 #define TCENTRE 2 #define TRIGHT 3 #define MLEFT 4 #define MCENTRE 5 #define MRIGHT 6 #define BLEFT 7 #define BCENTRE 8 #define BRIGHT 9 /* ---------------------------------------------------------------------- */ /* this shoulf be C++ compliant, thanks to vlp@latina.inesc.pt (Vasco Lopes Paulo) */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { float XRotVersion(char*, int); void XRotSetMagnification(float); void XRotSetBoundingBoxPad(int); int XRotDrawString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); int XRotDrawImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); int XRotDrawAlignedString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); int XRotDrawAlignedImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); XPoint *XRotTextExtents(Display*, XFontStruct*, float, int, int, char*, int); } #else // _cplusplus || c_plusplus extern float XRotVersion(char *, int); extern void XRotSetMagnification(float); extern void XRotSetBoundingBoxPad(int); extern int XRotDrawString(Display *, XFontStruct*, float, Drawable, GC, int, int, char*); extern int XRotDrawImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); extern int XRotDrawAlignedString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); extern int XRotDrawAlignedImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); extern XPoint *XRotTextExtents(Display*, XFontStruct*, float, int, int, char*, int); #endif /* __cplusplus */ /* ---------------------------------------------------------------------- */ #endif /* _XVERTEXT_INCLUDED_ */ Xastir-Release-2.2.2/src/rpl_malloc.c000066400000000000000000000033211501463444000174240ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* // // We DON'T want config.h to redefine malloc in this file else we'll // get an infinite loop. // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H */ #include #include "rpl_malloc.h" // // Work around bug on some systems where malloc (0) fails. // written by Jim Meyering // // configure.ac calls out AC_FUNC_MALLOC which checks the malloc() // function. If malloc() is determined to do the wrong thing when // passed a 0 value, the Autoconf macro will do this: // #define malloc rpl_malloc // We then need to have an rpl_malloc function defined. Here it is: // // Allocate an N-byte block of memory from the heap. // If N is zero, allocate a 1-byte block. // void *rpl_malloc (size_t size) { if (size == 0) { size++; } return malloc (size); } Xastir-Release-2.2.2/src/rpl_malloc.h000066400000000000000000000020731501463444000174340ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_RPL_MALLOC_H #define __XASTIR_RPL_MALLOC_H extern void *rpl_malloc (size_t size); #endif // __XASTIR_RPL_MALLOC_H Xastir-Release-2.2.2/src/rtree/000077500000000000000000000000001501463444000162565ustar00rootroot00000000000000Xastir-Release-2.2.2/src/rtree/.vimrc000066400000000000000000000014331501463444000174000ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/src/rtree/Makefile.am000066400000000000000000000004721501463444000203150ustar00rootroot00000000000000 # Copyright (C) 2000-2023 The Xastir Group noinst_LIBRARIES=librtree.a librtree_a_SOURCES= card.c \ card.h \ index.c \ index.h \ node.c \ rect.c \ split_l.c \ split_l.h Xastir-Release-2.2.2/src/rtree/card.c000066400000000000000000000035521501463444000173400ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include "index.h" #include "card.h" int Xastir_NODECARD = MAXCARD; int Xastir_LEAFCARD = MAXCARD; static int set_max(int *which, int new_max) { if(2 > new_max || new_max > MAXCARD) { return 0; } *which = new_max; return 1; } int Xastir_RTreeSetNodeMax(int new_max) { return set_max(&Xastir_NODECARD, new_max); } int Xastir_RTreeSetLeafMax(int new_max) { return set_max(&Xastir_LEAFCARD, new_max); } int Xastir_RTreeGetNodeMax(void) { return Xastir_NODECARD; } int Xastir_RTreeGetLeafMax(void) { return Xastir_LEAFCARD; } Xastir-Release-2.2.2/src/rtree/card.h000066400000000000000000000033301501463444000173370ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #ifndef __CARD__ #define __CARD__ extern int Xastir_NODECARD; extern int Xastir_LEAFCARD; /* balance criteria for node splitting */ /* NOTE: can be changed if needed. */ #define MinNodeFill (Xastir_NODECARD / 2) #define MinLeafFill (Xastir_LEAFCARD / 2) #define MAXKIDS(n) ((n)->level > 0 ? Xastir_NODECARD : Xastir_LEAFCARD) #define MINFILL(n) ((n)->level > 0 ? MinNodeFill : MinLeafFill) #endif Xastir-Release-2.2.2/src/rtree/gammavol.c000066400000000000000000000037741501463444000202400ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #ifndef M_PI #define M_PI 3.1415926535 #endif #ifndef ABS #define ABS(a) ((a) > 0 ? (a) : -(a)) #endif #define EP .0000000001 const double log_pi = log(M_PI); double sphere_volume(double dimension) { double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } int main(void) { double dim=0, delta=1; while(ABS(delta) > EP) if(sphere_volume(dim + delta) > sphere_volume(dim)) { dim += delta; } else { delta /= -2; } printf("max volume = %.10f at dimension %.10f\n", sphere_volume(dim), dim); return 0; } Xastir-Release-2.2.2/src/rtree/index.c000066400000000000000000000231371501463444000175370ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include "card.h" // Make a new index, empty. Consists of a single node. // struct Node * Xastir_RTreeNewIndex(void) { struct Node *x; x = Xastir_RTreeNewNode(); x->level = 0; /* leaf */ return x; } // Search in an index tree or subtree for all data rectangles that // overlap the argument rectangle. // Return the number of qualifying data rects. // int Xastir_RTreeSearch(struct Node *N, struct Rect *R, SearchHitCallback shcb, void* cbarg) { struct Node *n = N; struct Rect *r = R; // NOTE: Suspected bug was R sent in as Node* and cast to Rect* here. Fix not yet tested. int hitCount = 0; int i; assert(n); assert(n->level >= 0); assert(r); if (n->level > 0) /* this is an internal node in the tree */ { for (i=0; ibranch[i].child && Xastir_RTreeOverlap(r,&n->branch[i].rect)) { hitCount += Xastir_RTreeSearch(n->branch[i].child, R, shcb, cbarg); } } else /* this is a leaf node */ { for (i=0; ibranch[i].child && Xastir_RTreeOverlap(r,&n->branch[i].rect)) { hitCount++; if(shcb) // call the user-provided callback if( ! shcb(n->branch[i].child, cbarg)) { return hitCount; // callback wants to terminate search early } } } return hitCount; } // Inserts a new data rectangle into the index structure. // Recursively descends tree, propagates splits back up. // Returns 0 if node was not split. Old node updated. // If node was split, returns 1 and sets the pointer pointed to by // new_node to point to the new node. Old node updated to become one of two. // The level argument specifies the number of steps up from the leaf // level to insert; e.g. a data rectangle goes in at level = 0. // static int Xastir_RTreeInsertRect2(struct Rect *r, void *tid, struct Node *n, struct Node **new_node, int level) { /* register struct Rect *r = R; register int tid = Tid; register struct Node *n = N, **new_node = New_node; register int level = Level; */ int i; struct Branch b; struct Node *n2; assert(r && n && new_node); assert(level >= 0 && level <= n->level); // Still above level for insertion, go down tree recursively // if (n->level > level) { i = Xastir_RTreePickBranch(r, n); if (!Xastir_RTreeInsertRect2(r, tid, n->branch[i].child, &n2, level)) { // child was not split // n->branch[i].rect = Xastir_RTreeCombineRect(r,&(n->branch[i].rect)); return 0; } else // child was split { n->branch[i].rect = Xastir_RTreeNodeCover(n->branch[i].child); b.child = n2; b.rect = Xastir_RTreeNodeCover(n2); return Xastir_RTreeAddBranch(&b, n, new_node); } } // Have reached level for insertion. Add rect, split if necessary // else if (n->level == level) { b.rect = *r; b.child = (struct Node *) tid; /* child field of leaves contains tid of data record */ return Xastir_RTreeAddBranch(&b, n, new_node); } else { /* Not supposed to happen */ assert (FALSE); return 0; } } // Insert a data rectangle into an index structure. // Xastir_RTreeInsertRect provides for splitting the root; // returns 1 if root was split, 0 if it was not. // The level argument specifies the number of steps up from the leaf // level to insert; e.g. a data rectangle goes in at level = 0. // Xastir_RTreeInsertRect2 does the recursion. // int Xastir_RTreeInsertRect(struct Rect *R, void *Tid, struct Node **Root, int Level) { struct Rect *r = R; void *tid = Tid; struct Node **root = Root; int level = Level; int i; struct Node *newroot; struct Node *newnode; struct Branch b; int result; assert(r && root); assert(level >= 0 && level <= (*root)->level); for (i=0; iboundary[i] <= r->boundary[NUMDIMS+i]); } if (Xastir_RTreeInsertRect2(r, tid, *root, &newnode, level)) /* root split */ { newroot = Xastir_RTreeNewNode(); /* grow a new root, & tree taller */ newroot->level = (*root)->level + 1; b.rect = Xastir_RTreeNodeCover(*root); b.child = *root; Xastir_RTreeAddBranch(&b, newroot, NULL); b.rect = Xastir_RTreeNodeCover(newnode); b.child = newnode; Xastir_RTreeAddBranch(&b, newroot, NULL); *root = newroot; result = 1; } else { result = 0; } return result; } // Allocate space for a node in the list used in DeletRect to // store Nodes that are too empty. // static struct ListNode * Xastir_RTreeNewListNode(void) { return (struct ListNode *) malloc(sizeof(struct ListNode)); //return new ListNode; } static void Xastir_RTreeFreeListNode(struct ListNode *p) { free(p); //delete(p); } // Add a node to the reinsertion list. All its branches will later // be reinserted into the index structure. // static void Xastir_RTreeReInsert(struct Node *n, struct ListNode **ee) { struct ListNode *l; l = Xastir_RTreeNewListNode(); l->node = n; l->next = *ee; *ee = l; } // Delete a rectangle from non-root part of an index structure. // Called by Xastir_RTreeDeleteRect. Descends tree recursively, // merges branches on the way back up. // Returns 1 if record not found, 0 if success. // static int Xastir_RTreeDeleteRect2(struct Rect *R, void *Tid, struct Node *N, struct ListNode **Ee) { struct Rect *r = R; void *tid = Tid; struct Node *n = N; struct ListNode **ee = Ee; int i; assert(r && n && ee); assert(tid != NULL); assert(n->level >= 0); if (n->level > 0) // not a leaf node { for (i = 0; i < Xastir_NODECARD; i++) { if (n->branch[i].child && Xastir_RTreeOverlap(r, &(n->branch[i].rect))) { if (!Xastir_RTreeDeleteRect2(r, tid, n->branch[i].child, ee)) { if (n->branch[i].child->count >= MinNodeFill) n->branch[i].rect = Xastir_RTreeNodeCover( n->branch[i].child); else { // not enough entries in child, // eliminate child node // Xastir_RTreeReInsert(n->branch[i].child, ee); Xastir_RTreeDisconnectBranch(n, i); } return 0; } } } return 1; } else // a leaf node { for (i = 0; i < Xastir_LEAFCARD; i++) { if (n->branch[i].child && n->branch[i].child == (struct Node *) tid) { Xastir_RTreeDisconnectBranch(n, i); return 0; } } return 1; } } // Delete a data rectangle from an index structure. // Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. // Returns 1 if record not found, 0 if success. // Xastir_RTreeDeleteRect provides for eliminating the root. // int Xastir_RTreeDeleteRect(struct Rect *R, void *Tid, struct Node**Nn) { struct Rect *r = R; void *tid = Tid; struct Node **nn = Nn; int i; struct Node *tmp_nptr=NULL; // Original superliminal.com // source did not initialize. // Code analysis says shouldn't // matter, but let's initialize // to shut up GCC struct ListNode *reInsertList = NULL; struct ListNode *e; assert(r && nn); assert(*nn); assert(tid != NULL); if (!Xastir_RTreeDeleteRect2(r, tid, *nn, &reInsertList)) { /* found and deleted a data item */ /* reinsert any branches from eliminated nodes */ while (reInsertList) { tmp_nptr = reInsertList->node; for (i = 0; i < MAXKIDS(tmp_nptr); i++) { if (tmp_nptr->branch[i].child) { Xastir_RTreeInsertRect( &(tmp_nptr->branch[i].rect), tmp_nptr->branch[i].child, nn, tmp_nptr->level); } } e = reInsertList; reInsertList = reInsertList->next; Xastir_RTreeFreeNode(e->node); Xastir_RTreeFreeListNode(e); } /* check for redundant root (not leaf, 1 child) and eliminate */ if ((*nn)->count == 1 && (*nn)->level > 0) { for (i = 0; i < Xastir_NODECARD; i++) { tmp_nptr = (*nn)->branch[i].child; if(tmp_nptr) { break; } } assert(tmp_nptr); Xastir_RTreeFreeNode(*nn); *nn = tmp_nptr; } return 0; } else { return 1; } } Xastir-Release-2.2.2/src/rtree/index.h000066400000000000000000000104571501463444000175450ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #ifndef _INDEX_ #define _INDEX_ /* PGSIZE is normally the natural page size of the machine */ #define PGSIZE 512 #define NUMDIMS 2 /* number of dimensions */ #define NDEBUG // This is what GRASS does //typedef double RectReal; // but this is the original, and saves lots of RAM --- these indices are // huge for big shapefiles! typedef float RectReal; /*----------------------------------------------------------------------------- | Global definitions. -----------------------------------------------------------------------------*/ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define NUMSIDES 2*NUMDIMS struct Rect { RectReal boundary[NUMSIDES]; /* xmin,ymin,...,xmax,ymax,... */ }; struct Node; struct Branch { struct Rect rect; struct Node *child; }; /* max branching factor of a node */ #define MAXCARD (int)((PGSIZE-(2*sizeof(int))) / sizeof(struct Branch)) struct Node { int count; int level; /* 0 is leaf, others positive */ struct Branch branch[MAXCARD]; }; struct ListNode { struct ListNode *next; struct Node *node; }; /* * If passed to a tree search, this callback function will be called * with the ID of each data rect that overlaps the search rect * plus whatever user specific pointer was passed to the search. * It can terminate the search early by returning 0 in which case * the search will return the number of hits found up to that point. */ typedef int (*SearchHitCallback)(void *id, void* arg); extern int Xastir_RTreeSearch(struct Node*, struct Rect*, SearchHitCallback, void*); extern int Xastir_RTreeInsertRect(struct Rect*, void *, struct Node**, int depth); extern int Xastir_RTreeDeleteRect(struct Rect*, void *, struct Node**); extern struct Node * Xastir_RTreeNewIndex(void); extern struct Node * Xastir_RTreeNewNode(void); extern void Xastir_RTreeInitNode(struct Node*); extern void Xastir_RTreeFreeNode(struct Node *); extern void Xastir_RTreePrintNode(struct Node *, int); extern void Xastir_RTreeDestroyNode(struct Node*); extern void Xastir_RTreeTabIn(int); extern struct Rect Xastir_RTreeNodeCover(struct Node *); extern void Xastir_RTreeInitRect(struct Rect*); extern struct Rect Xastir_RTreeNullRect(void); extern RectReal Xastir_RTreeRectArea(struct Rect*); extern RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R); extern RectReal Xastir_RTreeRectVolume(struct Rect *R); extern struct Rect Xastir_RTreeCombineRect(struct Rect*, struct Rect*); extern int Xastir_RTreeOverlap(struct Rect*, struct Rect*); extern void Xastir_RTreePrintRect(struct Rect*, int); extern int Xastir_RTreeAddBranch(struct Branch *, struct Node *, struct Node **); extern int Xastir_RTreePickBranch(struct Rect *, struct Node *); extern void Xastir_RTreeDisconnectBranch(struct Node *, int); extern void Xastir_RTreeSplitNode(struct Node*, struct Branch*, struct Node**); extern int Xastir_RTreeSetNodeMax(int); extern int Xastir_RTreeSetLeafMax(int); extern int Xastir_RTreeGetNodeMax(void); extern int Xastir_RTreeGetLeafMax(void); #endif /* _INDEX_ */ Xastir-Release-2.2.2/src/rtree/node.c000066400000000000000000000157241501463444000173600ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include "card.h" //static int nnodes_alloced=0; //static long int bytes_malloced=0; // Initialize one branch cell in a node. // static void Xastir_RTreeInitBranch(struct Branch *b) { Xastir_RTreeInitRect(&(b->rect)); b->child = NULL; } // Initialize a Node structure. // void Xastir_RTreeInitNode(struct Node *N) { register struct Node *n = N; register int i; n->count = 0; n->level = -1; for (i = 0; i < MAXCARD; i++) { Xastir_RTreeInitBranch(&(n->branch[i])); } } // Make a new node and initialize to have all branch cells empty. // struct Node * Xastir_RTreeNewNode(void) { register struct Node *n; //n = new Node; n = (struct Node*)malloc(sizeof(struct Node)); assert(n); // nnodes_alloced++; // bytes_malloced+= sizeof(struct Node); // fprintf(stderr," Currently %d nodes (%ld bytes) in all rtrees\n",nnodes_alloced, bytes_malloced); Xastir_RTreeInitNode(n); return n; } void Xastir_RTreeFreeNode(struct Node *p) { assert(p); //delete p; // nnodes_alloced--; // bytes_malloced-= sizeof(struct Node); free(p); } static void Xastir_RTreePrintBranch(struct Branch *b, int depth) { Xastir_RTreePrintRect(&(b->rect), depth); Xastir_RTreePrintNode(b->child, depth); } extern void Xastir_RTreeTabIn(int depth) { int i; for(i=0; ilevel == 0) { printf(" LEAF"); } else if (n->level > 0) { printf(" NONLEAF"); } else { printf(" TYPE=?"); } // Original superliminal.com implementation had no cast before // n, gcc gripes about "int format, pointer arg" printf(" level=%d count=%d address=%lx\n", n->level, n->count, (unsigned long) n); for (i=0; icount; i++) { if(n->level == 0) { // Xastir_RTreeTabIn(depth); // printf("\t%d: data = %d\n", i, n->branch[i].child); } else { Xastir_RTreeTabIn(depth); printf("branch %d\n", i); Xastir_RTreePrintBranch(&n->branch[i], depth+1); } } } // Find the smallest rectangle that includes all rectangles in // branches of a node. // struct Rect Xastir_RTreeNodeCover(struct Node *N) { register struct Node *n = N; register int i, first_time=1; struct Rect r; assert(n); Xastir_RTreeInitRect(&r); for (i = 0; i < MAXKIDS(n); i++) if (n->branch[i].child) { if (first_time) { r = n->branch[i].rect; first_time = 0; } else { r = Xastir_RTreeCombineRect(&r, &(n->branch[i].rect)); } } return r; } // Pick a branch. Pick the one that will need the smallest increase // in area to accommodate the new rectangle. This will result in the // least total area for the covering rectangles in the current node. // In case of a tie, pick the one which was smaller before, to get // the best resolution when searching. // int Xastir_RTreePickBranch(struct Rect *R, struct Node *N) { register struct Rect *r = R; register struct Node *n = N; register struct Rect *rr; register int i, first_time=1; // Although it is impossible for bestArea and best to be used // unininitialized the way the code is structured, gcc complains // about possible uninitialized usage. Let's keep it happy. // Original superliminal.com had no initializers here. RectReal increase, bestIncr=(RectReal)-1, area, bestArea=0.0; int best=0; struct Rect tmp_rect; assert(r && n); for (i=0; ibranch[i].child) { rr = &n->branch[i].rect; area = Xastir_RTreeRectSphericalVolume(rr); tmp_rect = Xastir_RTreeCombineRect(r, rr); increase = Xastir_RTreeRectSphericalVolume(&tmp_rect) - area; if (increase < bestIncr || first_time) { best = i; bestArea = area; bestIncr = increase; first_time = 0; } else if (increase == bestIncr && area < bestArea) { best = i; bestArea = area; bestIncr = increase; } } } return best; } // Add a branch to a node. Split the node if necessary. // Returns 0 if node not split. Old node updated. // Returns 1 if node split, sets *new_node to address of new node. // Old node updated, becomes one of two. // int Xastir_RTreeAddBranch(struct Branch *B, struct Node *N, struct Node **New_node) { register struct Branch *b = B; register struct Node *n = N; register struct Node **new_node = New_node; register int i; assert(b); assert(n); if (n->count < MAXKIDS(n)) /* split won't be necessary */ { for (i = 0; i < MAXKIDS(n); i++) /* find empty branch */ { if (n->branch[i].child == NULL) { n->branch[i] = *b; n->count++; break; } } return 0; } else { assert(new_node); Xastir_RTreeSplitNode(n, b, new_node); return 1; } } // Disconnect a dependent node. // void Xastir_RTreeDisconnectBranch(struct Node *n, int i) { assert(n && i>=0 && ibranch[i].child); Xastir_RTreeInitBranch(&(n->branch[i])); n->count--; } // Destroy (free) node recursively. void Xastir_RTreeDestroyNode (struct Node *n) { int i; // fprintf(stderr," Freeing node %lx\n",(unsigned long int) n); if (n->level > 0) //it is not leaf -> destroy childs { for ( i = 0; i < Xastir_NODECARD; i++) { if ( n->branch[i].child ) { Xastir_RTreeDestroyNode ( n->branch[i].child ); } } } // Xastir_RTreeFreeNode( n ); } Xastir-Release-2.2.2/src/rtree/rect.c000066400000000000000000000272121501463444000173630ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include #include #define BIG_NUM (FLT_MAX/4.0) #define Undefined(x) ((x)->boundary[0] > (x)->boundary[NUMDIMS]) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) /*----------------------------------------------------------------------------- | Initialize a rectangle to have all 0 coordinates. -----------------------------------------------------------------------------*/ void Xastir_RTreeInitRect(struct Rect *R) { register struct Rect *r = R; register int i; for (i=0; iboundary[i] = (RectReal)0; } } /*----------------------------------------------------------------------------- | Return a rect whose first low side is higher than its opposite side - | interpreted as an undefined rect. -----------------------------------------------------------------------------*/ struct Rect Xastir_RTreeNullRect(void) { struct Rect r; register int i; r.boundary[0] = (RectReal)1; r.boundary[NUMDIMS] = (RectReal)-1; for (i=1; iboundary[i] = drand48() * (1000-width); /* low side */ r->boundary[i + NUMDIMS] = r->boundary[i] + width; // high side } } /*----------------------------------------------------------------------------- | Fill in the boundaries for a random search rectangle. | Pass in a pointer to a rect that contains all the data, | and a pointer to the rect to be filled in. | Generated rect is centered randomly anywhere in the data area, | and has size from 0 to the size of the data area in each dimension, | i.e. search rect can stick out beyond data area. -----------------------------------------------------------------------------*/ void Xastir_RTreeSearchRect(struct Rect *Search, struct Rect *Data) { register struct Rect *search = Search, *data = Data; register int i, j; register RectReal size, center; assert(search); assert(data); for (i=0; iboundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) { size = (drand48() * (data->boundary[j] - data->boundary[i] + 1)) / 2; center = data->boundary[i] + drand48() * (data->boundary[j] - data->boundary[i] + 1); search->boundary[i] = center - size/2; search->boundary[j] = center + size/2; } else // some open boundary, search entire dimension { search->boundary[i] = -BIG_NUM; search->boundary[j] = BIG_NUM; } } } #endif /*----------------------------------------------------------------------------- | Print out the data for a rectangle. -----------------------------------------------------------------------------*/ void Xastir_RTreePrintRect(struct Rect *R, int depth) { register struct Rect *r = R; register int i; assert(r); Xastir_RTreeTabIn(depth); printf("rect:\n"); for (i = 0; i < NUMDIMS; i++) { Xastir_RTreeTabIn(depth+1); printf("%f\t%f\n", r->boundary[i], r->boundary[i + NUMDIMS]); } } /*----------------------------------------------------------------------------- | Calculate the n-dimensional volume of a rectangle -----------------------------------------------------------------------------*/ RectReal Xastir_RTreeRectVolume(struct Rect *R) { register struct Rect *r = R; register int i; register RectReal volume = (RectReal)1; assert(r); if (Undefined(r)) { return (RectReal)0; } for(i=0; iboundary[i+NUMDIMS] - r->boundary[i]; } assert(volume >= 0.0); return volume; } /*----------------------------------------------------------------------------- | Define the NUMDIMS-dimensional volume the unit sphere in that dimension into | the symbol "Xastir_UnitSphereVolume" | Note that if the gamma function is available in the math library and if the | compiler supports static initialization using functions, this is | easily computed for any dimension. If not, the value can be precomputed and | taken from a table. The following code can do it either way. -----------------------------------------------------------------------------*/ #ifdef gamma /* computes the volume of an N-dimensional sphere. */ /* derived from formule in "Regular Polytopes" by H.S.M Coxeter */ static double sphere_volume(double dimension) { static const double log_pi = log(3.1415926535); double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } static const double Xastir_UnitSphereVolume = sphere_volume(NUMDIMS); #else /* Precomputed volumes of the unit spheres for the first few dimensions */ const double Xastir_UnitSphereVolumes[] = { 0.000000, /* dimension 0 */ 2.000000, /* dimension 1 */ 3.141593, /* dimension 2 */ 4.188790, /* dimension 3 */ 4.934802, /* dimension 4 */ 5.263789, /* dimension 5 */ 5.167713, /* dimension 6 */ 4.724766, /* dimension 7 */ 4.058712, /* dimension 8 */ 3.298509, /* dimension 9 */ 2.550164, /* dimension 10 */ 1.884104, /* dimension 11 */ 1.335263, /* dimension 12 */ 0.910629, /* dimension 13 */ 0.599265, /* dimension 14 */ 0.381443, /* dimension 15 */ 0.235331, /* dimension 16 */ 0.140981, /* dimension 17 */ 0.082146, /* dimension 18 */ 0.046622, /* dimension 19 */ 0.025807, /* dimension 20 */ }; #if NUMDIMS > 20 # error "not enough precomputed sphere volumes" #endif #define Xastir_UnitSphereVolume Xastir_UnitSphereVolumes[NUMDIMS] #endif /*----------------------------------------------------------------------------- | Calculate the n-dimensional volume of the bounding sphere of a rectangle -----------------------------------------------------------------------------*/ #if 0 /* * A fast approximation to the volume of the bounding sphere for the * given Rect. By Paul B. */ RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R) { register struct Rect *r = R; register int i; RectReal maxsize=(RectReal)0, c_size; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[i+NUMDIMS] - r->boundary[i]; if (c_size > maxsize) { maxsize = c_size; } } return (RectReal)(pow(maxsize/2, NUMDIMS) * Xastir_UnitSphereVolume); } #endif /* * The exact volume of the bounding sphere for the given Rect. */ RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R) { register struct Rect *r = R; register int i; register double sum_of_squares=0, radius; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[i+NUMDIMS] - r->boundary[i]) / 2; sum_of_squares += half_extent * half_extent; } radius = sqrt(sum_of_squares); return (RectReal)(pow(radius, NUMDIMS) * Xastir_UnitSphereVolume); } /*----------------------------------------------------------------------------- | Calculate the n-dimensional surface area of a rectangle -----------------------------------------------------------------------------*/ RectReal Xastir_RTreeRectSurfaceArea(struct Rect *R) { register struct Rect *r = R; register int i, j; register RectReal sum = (RectReal)0; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[j+NUMDIMS] - r->boundary[j]; face_area *= j_extent; } sum += face_area; } return 2 * sum; } /*----------------------------------------------------------------------------- | Combine two rectangles, make one that includes both. -----------------------------------------------------------------------------*/ struct Rect Xastir_RTreeCombineRect(struct Rect *R, struct Rect *Rr) { register struct Rect *r = R, *rr = Rr; register int i, j; struct Rect new_rect; assert(r && rr); if (Undefined(r)) { return *rr; } if (Undefined(rr)) { return *r; } for (i = 0; i < NUMDIMS; i++) { new_rect.boundary[i] = MIN(r->boundary[i], rr->boundary[i]); j = i + NUMDIMS; new_rect.boundary[j] = MAX(r->boundary[j], rr->boundary[j]); } return new_rect; } /*----------------------------------------------------------------------------- | Decide whether two rectangles overlap. -----------------------------------------------------------------------------*/ int Xastir_RTreeOverlap(struct Rect *R, struct Rect *S) { register struct Rect *r = R, *s = S; register int i, j; assert(r && s); for (i=0; iboundary[i] > s->boundary[j] || s->boundary[i] > r->boundary[j]) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- | Decide whether rectangle r is contained in rectangle s. -----------------------------------------------------------------------------*/ int Xastir_RTreeContained(struct Rect *R, struct Rect *S) { register struct Rect *r = R, *s = S; register int i, j, result; assert(r && s); // undefined rect is contained in any other // if (Undefined(r)) { return TRUE; } // no rect (except an undefined one) is contained in an undef rect // if (Undefined(s)) { return FALSE; } result = TRUE; for (i = 0; i < NUMDIMS; i++) { j = i + NUMDIMS; /* index for high sides */ result = result && r->boundary[i] >= s->boundary[i] && r->boundary[j] <= s->boundary[j]; } return result; } Xastir-Release-2.2.2/src/rtree/sources.htm000066400000000000000000000075551501463444000204670ustar00rootroot00000000000000 Free Source Code
Free Source Code

Xastir note: This file is intended to point you at the original sources of the rtree implementation used in xastir.]

Here are a few useful bits of free source code. You're completely free to use them for any purpose whatsoever. All I ask is that if you find one to be particularly valuable, then consider sending a brief thank you note to the email address in the code comments. Enjoy.



C & C++ Code

R-Trees

Straight "C" implementation of Tony Gutman's R-Tree method, R-Trees provide Log(n) speed rectangular indexing into multi-dimensional data. Based on his original implementation, I've brought it up to date with ANCI specifications and added a nice improvement based on sphere volumes.

    Download R-Tree code

Skiplists

Skiplists are fast associative collections invented by William Pugh. Key/Value pairs are added to skiplist containers and can then values looked up extremely quickly by key. The implementation is based on a fairly generic one originally in "C" by Bruno Grossniklaus which I converted into a C++ class library.

    Download SkipList code

Quaternions

Implementation of a simple C++ quaternion class called "Squat". Popularized by a seminal paper by Ken Shoemake, a quaternion represents a rotation about an axis.  Squats can be concatenated together via the * and *= operators and converted back and forth between transformation matrices. Implementation also includes a wonderful 3D vector macro library by Don Hatch.

    Download Squat code

Polygon-Cube Intersection Testing

"C" implementation of an extremely fast and robust polygon-cube intersection test by Don Hatch and myself as published in Graphics Gems V. Very useful for collision detection and view frustum visibility checking.

    View the readme file
    Download PCube code
 
 

Back to the Superliminal home page.

Xastir-Release-2.2.2/src/rtree/sphvol.c000066400000000000000000000055161501463444000177440ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /* * SPHERE VOLUME * by Melinda Green * melinda@superliminal.com * * Calculates and prints the volumes of the unit hyperspheres for * dimensions zero through the given value, or 9 by default. * Prints in the form of a C array of double called sphere_volumes. * * From formule in "Regular Polytopes" by H.S.M Coxeter, the volume * of a hypersphere of dimension d is: * Pi^(d/2) / gamma(d/2 + 1) * * This implementation works by first computing the log of the above * function and then returning the exp of that value in order to avoid * instabilities due to the huge values that the real gamma function * would return. * * Multiply the output volumes by R^n to get the volume of an n * dimensional sphere of radius R. */ #include #include #ifndef M_PI #define M_PI 3.1415926535 #endif static void print_volume(int dimension, double volume) { printf("\t%.6f, /* dimension %3d */\n", volume, dimension); } static double sphere_volume(double dimension) { const double log_pi = log(M_PI); double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } extern int main(int argc, char *argv[]) { int dim, max_dims=9; if(2 == argc) { max_dims = atoi(argv[1]); } printf("static const double sphere_volumes[] = {\n"); for(dim=0; dim #include "assert.h" #include "index.h" #include "card.h" #include "split_l.h" /*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void Xastir_RTreeGetBranches(struct Node *N, struct Branch *B) { register struct Node *n = N; register struct Branch *b = B; register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; ibranch[i].child); /* every entry should be full */ Xastir_BranchBuf[i] = n->branch[i]; } Xastir_BranchBuf[MAXKIDS(n)] = *b; Xastir_BranchCount = MAXKIDS(n) + 1; /* calculate rect containing all in the set */ Xastir_CoverSplit = Xastir_BranchBuf[0].rect; for (i=1; icount[0] = p->count[1] = 0; p->total = maxrects; p->minfill = minfill; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | Put a branch in one of the groups. -----------------------------------------------------------------------------*/ static void Xastir_RTreeClassify(int i, int group, struct PartitionVars *p) { assert(p); assert(!p->taken[i]); p->partition[i] = group; p->taken[i] = TRUE; if (p->count[group] == 0) { p->cover[group] = Xastir_BranchBuf[i].rect; } else p->cover[group] = Xastir_RTreeCombineRect(&Xastir_BranchBuf[i].rect, &p->cover[group]); p->area[group] = Xastir_RTreeRectSphericalVolume(&p->cover[group]); p->count[group]++; } /*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that are separated most along any dimension, or overlap least. | Distance for separation or overlap is measured modulo the width of the | space covered by the entire set along that dimension. -----------------------------------------------------------------------------*/ static void Xastir_RTreePickSeeds(struct PartitionVars *P) { register struct PartitionVars *p = P; register int i, dim, high; register struct Rect *r, *rlow, *rhigh; // Original superliminal.com implementation had no initializers here. // They are not strictly necessary, as the variables are initialized // in the first iteration of the first for loop, but GCC complains // anyway. Initializers added to keep it happy. register float w, separation, bestSep=0.0; RectReal width[NUMDIMS]; int leastUpper[NUMDIMS], greatestLower[NUMDIMS]; int seed0=0, seed1=0; assert(p); for (dim=0; dimboundary[dim] > Xastir_BranchBuf[greatestLower[dim]].rect.boundary[dim]) { greatestLower[dim] = i; } if (r->boundary[high] < Xastir_BranchBuf[leastUpper[dim]].rect.boundary[high]) { leastUpper[dim] = i; } } /* find width of the whole collection along this dimension */ width[dim] = Xastir_CoverSplit.boundary[high] - Xastir_CoverSplit.boundary[dim]; } /* pick the best separation dimension and the two seed rects */ for (dim=0; dim= 0); if (width[dim] == 0) { w = (RectReal)1; } else { w = width[dim]; } rlow = &Xastir_BranchBuf[leastUpper[dim]].rect; rhigh = &Xastir_BranchBuf[greatestLower[dim]].rect; if (dim == 0) { seed0 = leastUpper[0]; seed1 = greatestLower[0]; separation = bestSep = (rhigh->boundary[0] - rlow->boundary[NUMDIMS]) / w; } else { separation = (rhigh->boundary[dim] - rlow->boundary[dim+NUMDIMS]) / w; if (separation > bestSep) { seed0 = leastUpper[dim]; seed1 = greatestLower[dim]; bestSep = separation; } } } if (seed0 != seed1) { Xastir_RTreeClassify(seed0, 0, p); Xastir_RTreeClassify(seed1, 1, p); } } /*----------------------------------------------------------------------------- | Put each rect that is not already in a group into a group. | Process one rect at a time, using the following hierarchy of criteria. | In case of a tie, go to the next test. | 1) If one group already has the max number of elements that will allow | the minimum fill for the other group, put r in the other. | 2) Put r in the group whose cover will expand less. This automatically | takes care of the case where one group cover contains r. | 3) Put r in the group whose cover will be smaller. This takes care of the | case where r is contained in both covers. | 4) Put r in the group with fewer elements. | 5) Put in group 1 (arbitrary). | | Also update the covers for both groups. -----------------------------------------------------------------------------*/ static void Xastir_RTreePigeonhole(struct PartitionVars *P) { register struct PartitionVars *p = P; struct Rect newCover[2]; register int i, group; RectReal newArea[2], increase[2]; for (i=0; itaken[i]) { /* if one group too full, put rect in the other */ if (p->count[0] >= p->total - p->minfill) { Xastir_RTreeClassify(i, 1, p); continue; } else if (p->count[1] >= p->total - p->minfill) { Xastir_RTreeClassify(i, 0, p); continue; } /* find areas of the two groups' old and new covers */ for (group=0; group<2; group++) { if (p->count[group]>0) newCover[group] = Xastir_RTreeCombineRect( &Xastir_BranchBuf[i].rect, &p->cover[group]); else { newCover[group] = Xastir_BranchBuf[i].rect; } newArea[group] = Xastir_RTreeRectSphericalVolume( &newCover[group]); increase[group] = newArea[group]-p->area[group]; } /* put rect in group whose cover will expand less */ if (increase[0] < increase[1]) { Xastir_RTreeClassify(i, 0, p); } else if (increase[1] < increase[0]) { Xastir_RTreeClassify(i, 1, p); } /* put rect in group that will have a smaller cover */ else if (p->area[0] < p->area[1]) { Xastir_RTreeClassify(i, 0, p); } else if (p->area[1] < p->area[0]) { Xastir_RTreeClassify(i, 1, p); } /* put rect in group with fewer elements */ else if (p->count[0] < p->count[1]) { Xastir_RTreeClassify(i, 0, p); } else { Xastir_RTreeClassify(i, 1, p); } } } assert(p->count[0] + p->count[1] == Xastir_NODECARD + 1); } /*----------------------------------------------------------------------------- | Method 0 for finding a partition: | First find two seeds, one for each group, well separated. | Then put other rects in whichever group will be smallest after addition. -----------------------------------------------------------------------------*/ static void Xastir_RTreeMethodZero(struct PartitionVars *p, int minfill) { Xastir_RTreeInitPVars(p, Xastir_BranchCount, minfill); Xastir_RTreePickSeeds(p); Xastir_RTreePigeonhole(p); } /*----------------------------------------------------------------------------- | Copy branches from the buffer into two nodes according to the partition. -----------------------------------------------------------------------------*/ static void Xastir_RTreeLoadNodes(struct Node *N, struct Node *Q, struct PartitionVars *P) { register struct Node *n = N, *q = Q; register struct PartitionVars *p = P; register int i; assert(n); assert(q); assert(p); for (i=0; ipartition[i] == 0) { Xastir_RTreeAddBranch(&Xastir_BranchBuf[i], n, NULL); } else if (p->partition[i] == 1) { Xastir_RTreeAddBranch(&Xastir_BranchBuf[i], q, NULL); } else { assert(FALSE); } } } /*----------------------------------------------------------------------------- | Split a node. | Divides the nodes branches and the extra one between two nodes. | Old node is one of the new ones, and one really new one is created. -----------------------------------------------------------------------------*/ void Xastir_RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; // This variable is declared, assigned a value, then never used. // Newer GCCs warn about that. Shut them up. // RectReal area; assert(n); assert(b); /* load all the branches into a buffer, initialize old node */ level = n->level; Xastir_RTreeGetBranches(n, b); /* find partition */ p = &Xastir_Partitions[0]; /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */ Xastir_RTreeMethodZero(p, level>0 ? MinNodeFill : MinLeafFill); /* record how good the split was for statistics */ // This variable is declared, assigned a value, then never used. // Newer GCCs warn about that. Shut them up. // area = p->area[0] + p->area[1]; /* put branches from buffer in 2 nodes according to chosen partition */ *nn = Xastir_RTreeNewNode(); (*nn)->level = n->level = level; Xastir_RTreeLoadNodes(n, *nn, p); assert(n->count + (*nn)->count == Xastir_NODECARD+1); } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ // This is not used at the moment, and because it's declared static gcc // warns us it's not used. Commented out to shut gcc up #if 0 static void Xastir_RTreePrintPVars(struct PartitionVars *p) { int i; assert(p); printf("\npartition:\n"); for (i=0; itaken[i]) { printf(" t\t"); } else { printf("\t"); } } printf("\n"); for (i=0; ipartition[i]); } printf("\n"); printf("count[0] = %d area = %f\n", p->count[0], p->area[0]); printf("count[1] = %d area = %f\n", p->count[1], p->area[1]); printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], Xastir_RTreeRectSphericalVolume(&Xastir_CoverSplit)/(p->area[0]+p->area[1])); printf("cover[0]:\n"); Xastir_RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); Xastir_RTreePrintRect(&p->cover[1], 0); } #endif // shut up GCC Xastir-Release-2.2.2/src/rtree/split_l.h000066400000000000000000000035771501463444000201110ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /*----------------------------------------------------------------------------- | Definitions and global variables used in linear split code. -----------------------------------------------------------------------------*/ #define METHODS 1 struct Branch Xastir_BranchBuf[MAXCARD+1]; int Xastir_BranchCount; struct Rect Xastir_CoverSplit; /* variables for finding a partition */ struct PartitionVars { int partition[MAXCARD+1]; int total, minfill; int taken[MAXCARD+1]; int count[2]; struct Rect cover[2]; RectReal area[2]; } Xastir_Partitions[METHODS]; Xastir-Release-2.2.2/src/rtree/split_q.c000066400000000000000000000236131501463444000201020ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include "assert.h" #include "index.h" #include "card.h" #include "split_q.h" /*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void RTreeGetBranches(struct Node *n, struct Branch *b) { register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; ibranch[i].child); /* n should have every entry full */ BranchBuf[i] = n->branch[i]; } BranchBuf[MAXKIDS(n)] = *b; BranchCount = MAXKIDS(n) + 1; /* calculate rect containing all in the set */ CoverSplit = BranchBuf[0].rect; for (i=1; itaken[i]); p->partition[i] = group; p->taken[i] = TRUE; if (p->count[group] == 0) { p->cover[group] = BranchBuf[i].rect; } else p->cover[group] = RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group]); p->area[group] = RTreeRectSphericalVolume(&p->cover[group]); p->count[group]++; } /*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that waste the most area if covered by a single rectangle. -----------------------------------------------------------------------------*/ static void RTreePickSeeds(struct PartitionVars *p) { register int i, j, seed0, seed1; RectReal worst, waste, area[MAXCARD+1]; for (i=0; itotal; i++) { area[i] = RTreeRectSphericalVolume(&BranchBuf[i].rect); } worst = -CoverSplitArea - 1; for (i=0; itotal-1; i++) { for (j=i+1; jtotal; j++) { struct Rect one_rect = RTreeCombineRect( &BranchBuf[i].rect, &BranchBuf[j].rect); waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j]; if (waste > worst) { worst = waste; seed0 = i; seed1 = j; } } } RTreeClassify(seed0, 0, p); RTreeClassify(seed1, 1, p); } /*----------------------------------------------------------------------------- | Copy branches from the buffer into two nodes according to the partition. -----------------------------------------------------------------------------*/ static void RTreeLoadNodes(struct Node *n, struct Node *q, struct PartitionVars *p) { register int i; assert(n); assert(q); assert(p); for (i=0; itotal; i++) { assert(p->partition[i] == 0 || p->partition[i] == 1); if (p->partition[i] == 0) { RTreeAddBranch(&BranchBuf[i], n, NULL); } else if (p->partition[i] == 1) { RTreeAddBranch(&BranchBuf[i], q, NULL); } } } /*----------------------------------------------------------------------------- | Initialize a PartitionVars structure. -----------------------------------------------------------------------------*/ static void RTreeInitPVars(struct PartitionVars *p, int maxrects, int minfill) { register int i; assert(p); p->count[0] = p->count[1] = 0; p->cover[0] = p->cover[1] = RTreeNullRect(); p->area[0] = p->area[1] = (RectReal)0; p->total = maxrects; p->minfill = minfill; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ static void RTreePrintPVars(struct PartitionVars *p) { register int i; assert(p); printf("\npartition:\n"); for (i=0; itotal; i++) { printf("%3d\t", i); } printf("\n"); for (i=0; itotal; i++) { if (p->taken[i]) { printf(" t\t"); } else { printf("\t"); } } printf("\n"); for (i=0; itotal; i++) { printf("%3d\t", p->partition[i]); } printf("\n"); printf("count[0] = %d area = %f\n", p->count[0], p->area[0]); printf("count[1] = %d area = %f\n", p->count[1], p->area[1]); if (p->area[0] + p->area[1] > 0) { printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], (float)CoverSplitArea / (p->area[0] + p->area[1])); } printf("cover[0]:\n"); RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); RTreePrintRect(&p->cover[1], 0); } /*----------------------------------------------------------------------------- | Method #0 for choosing a partition: | As the seeds for the two groups, pick the two rects that would waste the | most area if covered by a single rectangle, i.e. evidently the worst pair | to have in the same group. | Of the remaining, one at a time is chosen to be put in one of the two groups. | The one chosen is the one with the greatest difference in area expansion | depending on which group - the rect most strongly attracted to one group | and repelled from the other. | If one group gets too full (more would force other group to violate min | fill requirement) then other group gets the rest. | These last are the ones that can go in either group most easily. -----------------------------------------------------------------------------*/ static void RTreeMethodZero(struct PartitionVars *p, int minfill) { register int i; RectReal biggestDiff; register int group, chosen, betterGroup; assert(p); RTreeInitPVars(p, BranchCount, minfill); RTreePickSeeds(p); while (p->count[0] + p->count[1] < p->total && p->count[0] < p->total - p->minfill && p->count[1] < p->total - p->minfill) { biggestDiff = (RectReal)-1.; for (i=0; itotal; i++) { if (!p->taken[i]) { struct Rect *r, rect_0, rect_1; RectReal growth0, growth1, diff; r = &BranchBuf[i].rect; rect_0 = RTreeCombineRect(r, &p->cover[0]); rect_1 = RTreeCombineRect(r, &p->cover[1]); growth0 = RTreeRectSphericalVolume( &rect_0)-p->area[0]; growth1 = RTreeRectSphericalVolume( &rect_1)-p->area[1]; diff = growth1 - growth0; if (diff >= 0) { group = 0; } else { group = 1; diff = -diff; } if (diff > biggestDiff) { biggestDiff = diff; chosen = i; betterGroup = group; } else if (diff==biggestDiff && p->count[group]count[betterGroup]) { chosen = i; betterGroup = group; } } } RTreeClassify(chosen, betterGroup, p); } /* if one group too full, put remaining rects in the other */ if (p->count[0] + p->count[1] < p->total) { if (p->count[0] >= p->total - p->minfill) { group = 1; } else { group = 0; } for (i=0; itotal; i++) { if (!p->taken[i]) { RTreeClassify(i, group, p); } } } assert(p->count[0] + p->count[1] == p->total); assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill); } /*----------------------------------------------------------------------------- | Split a node. | Divides the nodes branches and the extra one between two nodes. | Old node is one of the new ones, and one really new one is created. | Tries more than one method for choosing a partition, uses best result. -----------------------------------------------------------------------------*/ extern void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; assert(n); assert(b); /* load all the branches into a buffer, initialize old node */ level = n->level; RTreeGetBranches(n, b); /* find partition */ p = &Partitions[0]; /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */ RTreeMethodZero(p, level>0 ? MinNodeFill : MinLeafFill); /* * put branches from buffer into 2 nodes * according to chosen partition */ *nn = RTreeNewNode(); (*nn)->level = n->level = level; RTreeLoadNodes(n, *nn, p); assert(n->count+(*nn)->count == p->total); } Xastir-Release-2.2.2/src/rtree/split_q.h000066400000000000000000000035411501463444000201050ustar00rootroot00000000000000/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /*----------------------------------------------------------------------------- | Definitions and global variables. -----------------------------------------------------------------------------*/ #define METHODS 1 struct Branch BranchBuf[MAXCARD+1]; int BranchCount; struct Rect CoverSplit; RectReal CoverSplitArea; /* variables for finding a partition */ struct PartitionVars { int partition[MAXCARD+1]; int total, minfill; int taken[MAXCARD+1]; int count[2]; struct Rect cover[2]; RectReal area[2]; } Partitions[METHODS]; Xastir-Release-2.2.2/src/shp_hash.c000066400000000000000000000237141501463444000171050ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #include #include "xastir.h" #include "util.h" #include "hashtable.h" #include "hashtable_itr.h" /// THIS ONLY FOR DEBUGGING! #include "hashtable_private.h" #include "shp_hash.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" #define PURGE_PERIOD 3600 // One hour, hard coded for now. // This should be in a slider in the timing // configuration instead. //#define PURGE_PERIOD 120 // debugging static struct hashtable *shp_hash=NULL; static time_t purge_time; #define SHP_HASH_SIZE 65535 #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } unsigned int shape_hash_from_key(void *key) { char *str=(char *)key; unsigned int shphash=5381; int c; int i=0; while (str[i]!='\0') { c=str[i++]; shphash = ((shphash << 5) + shphash)^c; } return (shphash); } int shape_keys_equal(void *key1, void *key2) { // fprintf(stderr,"Comparing %s to %s\n",(char *)key1,(char *)key2); if (strncmp((char *)key1,(char *)key2,strlen((char *)key1))==0) { // fprintf(stderr," match\n"); return(1); } else { // fprintf(stderr," no match\n"); return(0); } } void init_shp_hash(int clobber) { //fprintf(stderr," Initializing shape hash \n"); // make sure we don't leak if (shp_hash) { if (clobber) { hashtable_destroy(shp_hash, 1); shp_hash=create_hashtable(SHP_HASH_SIZE, shape_hash_from_key, shape_keys_equal); } } else { shp_hash=create_hashtable(SHP_HASH_SIZE, shape_hash_from_key, shape_keys_equal); } // Now set the static timer value to the next time we need to run the purge // routine purge_time = sec_now() + PURGE_PERIOD; } // destructor for a single shapeinfo structure void destroy_shpinfo(shpinfo *si) { if (si) { empty_shpinfo(si); // fprintf(stderr, // " Freeing shpinfo %lx\n", // (unsigned long int) si); free(si); } } // free the pointers in a shapinfo object void empty_shpinfo(shpinfo *si) { if (si) { if (si->root) { // fprintf(stderr," Freeing root\n"); Xastir_RTreeDestroyNode(si->root); si->root=NULL; } // This is a little annoying --- the hashtable functions free the // key, which is in our case the filename. So since we're only going // to empty the shpinfo when we're removing from the hashtable, we // must not free the filename ourselves. // if (si->filename) { // fprintf(stderr," Freeing filename\n"); // free(si->filename); // si->filename=NULL; // } } } void destroy_shp_hash(void) { struct hashtable_itr *iterator=NULL; shpinfo *si; int ret; if (shp_hash) { // walk through the hashtable, free any pointers in the values // that aren't null, or we'll leak like a sieve. // the hashtable functions always attempt to dereference iterator, // and don't check if you give it a null, but will return null if // there's nothing in the table. Grrrr. iterator=hashtable_iterator(shp_hash); do { ret=0; if (iterator) { si = hashtable_iterator_value(iterator); if (si) { empty_shpinfo(si); } ret=hashtable_iterator_advance(iterator); } } while (ret); hashtable_destroy(shp_hash, 1); // destroy the hashtable, freeing // what's left of the entries shp_hash=NULL; if (iterator) { free(iterator); } } } void add_shp_to_hash(char *filename, SHPHandle sHP) { // This function does NOT check whether there already is something in // the hashtable that matches. // Check that before calling this routine. shpinfo *temp; int filenm_len; filenm_len=strlen(filename); if (!shp_hash) // no table to add to { init_shp_hash(1); // so create one } temp = (shpinfo *)malloc(sizeof(shpinfo)); CHECKMALLOC(temp); // leave room for terminator temp->filename = (char *) malloc(sizeof(char)*(filenm_len+1)); CHECKMALLOC(temp->filename); strncpy(temp->filename,filename,filenm_len+1); temp->filename[filenm_len]='\0'; // just to be safe // xastir_snprintf(temp->filename,sizeof(shpinfo),"%s",filename); temp->root = Xastir_RTreeNewIndex(); temp->creation = sec_now(); temp->last_access = temp->creation; build_rtree(&(temp->root),sHP); //fprintf(stderr, " adding %s...",temp->filename); if (!hashtable_insert(shp_hash,temp->filename,temp)) { fprintf(stderr,"Insert failed on shapefile hash --- fatal\n"); free(temp->filename); free(temp); exit(1); } } shpinfo *get_shp_from_hash(char *filename) { shpinfo *result; if (!shp_hash) // no table to search { init_shp_hash(1); // so create one return NULL; } //fprintf(stderr," searching for %s...",filename); result=hashtable_search(shp_hash,filename); // if (result) { // fprintf(stderr," found it\n"); // } else { // fprintf(stderr," it is not there\n"); // } // If there is one, we have now accessed it, so bump the last access time if (result) { result->last_access = sec_now(); } return (result); } //CAREFUL: note how adding things to the tree can change the root // Must not ever use cache a value of the root pointer if there's any // chance that the tree needs to be expanded! void build_rtree (struct Node **root, SHPHandle sHP) { int nEntities; intptr_t i; SHPObject *psCShape; struct Rect bbox_shape; SHPGetInfo(sHP, &nEntities, NULL, NULL, NULL); for( i = 0; i < nEntities; i++ ) { psCShape = SHPReadObject ( sHP, i ); if (psCShape != NULL) { bbox_shape.boundary[0]=(RectReal) psCShape->dfXMin; bbox_shape.boundary[1]=(RectReal) psCShape->dfYMin; bbox_shape.boundary[2]=(RectReal) psCShape->dfXMax; bbox_shape.boundary[3]=(RectReal) psCShape->dfYMax; SHPDestroyObject ( psCShape ); // Only insert the rect if it will not fail the assertion in // Xastir_RTreeInsertRect --- this will cause us to ignore any shapes that // have invalid bboxes (or that return invalid bboxes from shapelib // for whatever reason if (bbox_shape.boundary[0] <= bbox_shape.boundary[2] && bbox_shape.boundary[1] <= bbox_shape.boundary[3]) { Xastir_RTreeInsertRect(&bbox_shape, (void *)(i+1), root, 0); } } } } void purge_shp_hash(time_t secs_now) { struct hashtable_itr *iterator=NULL; shpinfo *si; int ret; if (secs_now > purge_time) // Time to purge { //time_now = localtime(&secs_now); //(void)strftime(timestring,100,"%a %b %d %H:%M:%S %Z %Y",time_now); //fprintf(stderr,"Purging...%s\n",timestring); purge_time += PURGE_PERIOD; if (shp_hash) { // walk through the hash table and kill entries that are old iterator=hashtable_iterator(shp_hash); do { ret=0; if (iterator) // must check this, because could be null { // if the iterator malloc failed si=hashtable_iterator_value(iterator); if (si) { if (secs_now > si->last_access+PURGE_PERIOD) { // this is stale, hasn't been accessed in a while //fprintf(stderr, // "found stale entry for %s, deleting it.\n", // si->filename); //fprintf(stderr," Destroying si=%lx\n", // (unsigned long int) si); ret=hashtable_iterator_remove(iterator); // Important that we NOT do the // destroy first, because we've used // the filename pointer field of the // structure as the key, and the // remove function will free that. If // we clobber the struct first, we // invite segfaults destroy_shpinfo(si); //fprintf(stderr," removing from hashtable\n"); } else { ret=hashtable_iterator_advance(iterator); } } } } while (ret); // we're now done with the iterator. Free it to stop us from // leaking! if (iterator) { free(iterator); } } //fprintf(stderr," done Purging...\n"); } } #endif // HAVE_LIBSHP // To get rid of "-pedantic" compiler warning: int NON_EMPTY_SOURCE_FILE; Xastir-Release-2.2.2/src/shp_hash.h000066400000000000000000000015211501463444000171020ustar00rootroot00000000000000 // Copyright (C) 2000-2023 The Xastir Group #ifndef __XASTIR_SHP_HASH_H #define __XASTIR_SHP_HASH_H #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H typedef struct _shpinfo { char *filename; struct Node* root; time_t creation; time_t last_access; int num_accesses; } shpinfo; void init_shp_hash(int clobber); void add_shp_to_hash(char *filename,SHPHandle sHP); void build_rtree(struct Node **root, SHPHandle sHP); void destroy_shp_hash(void); void empty_shpinfo(shpinfo *si); void destroy_shpinfo(shpinfo *si); void purge_shp_hash(time_t secs_now); shpinfo *get_shp_from_hash(char *filename); #endif // __XASTIR_SHP_HASH_H Xastir-Release-2.2.2/src/snprintf.c000066400000000000000000000476051501463444000171600ustar00rootroot00000000000000/* * snprintf.c - a portable implementation of snprintf and vsnprintf * */ /* * Portions Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * * **************************************************************/ #include #include #include #ifndef HAVE_VSNPRINTF /* varargs declarations: */ #if defined(__STDC__) #ifdef HAVE_STDARG_H #include #else // HAVE_STDARG_H #ifdef HAVE_STD_ARGS_H #include #endif // HAVE_STD_ARGS_H #endif // HAVE_STDARG_H #include #define HAVE_STDARGS /* let's hope that works everywhere (mj) */ #define VA_LOCAL_DECL va_list ap #define VA_START(f) va_start(ap, f) #define VA_SHIFT(v,t); /* no-op for ANSI */ #define VA_END va_end(ap) #else // __STDC__ #include #undef HAVE_STDARGS #define VA_LOCAL_DECL va_list ap #define VA_START(f) va_start(ap) /* f is ignored! */ #define VA_SHIFT(v,t) v = va_arg(ap,t) #define VA_END va_end(ap) #endif // __STDC__ // Must be last include file #include "leak_detection.h" #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else // HAVE_LONG_DOUBLE #define LDOUBLE double #endif // HAVE_LONG_DOUBLE static void dopr(char *buffer, size_t maxlen, const char *format, va_list args); static void fmtstr(char *buffer, size_t * currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t * currlen, size_t maxlen, long value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t * currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c); /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_SHORT 1 #define DP_C_LONG 2 #define DP_C_LDOUBLE 3 #define char_to_int(p) (p - '0') #define MAX(p, q) ((p >= q) ? p : q) static void dopr(char *buffer, size_t maxlen, const char *format, va_list args) { char ch; long value; LDOUBLE fvalue; char *strvalue; int min; int max; int state; int flags; int cflags; size_t currlen; state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; max = -1; ch = *format++; while (state != DP_S_DONE) { if ((ch == '\0') || (currlen >= maxlen)) { state = DP_S_DONE; } switch (state) { case DP_S_DEFAULT: if (ch == '%') { state = DP_S_FLAGS; } else { dopr_outch(buffer, &currlen, maxlen, ch); } ch = *format++; break; case DP_S_FLAGS: switch (ch) { case '-': flags |= DP_F_MINUS; ch = *format++; break; case '+': flags |= DP_F_PLUS; ch = *format++; break; case ' ': flags |= DP_F_SPACE; ch = *format++; break; case '#': flags |= DP_F_NUM; ch = *format++; break; case '0': flags |= DP_F_ZERO; ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit(ch)) { min = 10 * min + char_to_int(ch); ch = *format++; } else if (ch == '*') { min = va_arg(args, int); ch = *format++; state = DP_S_DOT; } else { state = DP_S_DOT; } break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else { state = DP_S_MOD; } break; case DP_S_MAX: if (isdigit(ch)) { if (max < 0) { max = 0; } max = 10 * max + char_to_int(ch); ch = *format++; } else if (ch == '*') { max = va_arg(args, int); ch = *format++; state = DP_S_MOD; } else { state = DP_S_MOD; } break; case DP_S_MOD: /* Currently, we don't support Long Long, bummer */ switch (ch) { case 'h': cflags = DP_C_SHORT; ch = *format++; break; case 'l': cflags = DP_C_LONG; ch = *format++; break; case 'L': cflags = DP_C_LDOUBLE; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: switch (ch) { case 'd': case 'i': if (cflags == DP_C_SHORT) { value = va_arg(args, short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, long int); } else { value = va_arg(args, int); } fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; case 'x': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } /* um, floating point? */ fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; case 'e': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } break; case 'G': flags |= DP_F_UP; case 'g': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } break; case 'c': dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); break; case 's': strvalue = va_arg(args, char *); if (max < 0) { max = maxlen; /* ie, no max */ } fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); break; case 'p': strvalue = va_arg(args, void *); fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) { short int *num; num = va_arg(args, short int *); *num = currlen; } else if (cflags == DP_C_LONG) { long int *num; num = va_arg(args, long int *); *num = currlen; } else { int *num; num = va_arg(args, int *); *num = currlen; } break; case '%': dopr_outch(buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ ch = *format++; break; default: /* Unknown, skip */ break; } ch = *format++; state = DP_S_DEFAULT; flags = cflags = min = 0; max = -1; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } if (currlen < maxlen - 1) { buffer[currlen] = '\0'; } else { buffer[maxlen - 1] = '\0'; } } static void fmtstr(char *buffer, size_t * currlen, size_t maxlen, char *value, int flags, int min, int max) { int padlen, strln; /* amount to pad */ int cnt = 0; if (value == 0) { value = ""; } for (strln = 0; value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) { padlen = 0; } if (flags & DP_F_MINUS) { padlen = -padlen; /* Left Justify */ } while ((padlen > 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; ++cnt; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t * currlen, size_t maxlen, long value, int base, int min, int max, int flags) { int signvalue = 0; unsigned long uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; if (max < 0) { max = 0; } uvalue = value; if (!(flags & DP_F_UNSIGNED)) { if (value < 0) { signvalue = '-'; uvalue = -value; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ { signvalue = '+'; } else if (flags & DP_F_SPACE) { signvalue = ' '; } } if (flags & DP_F_UP) { caps = 1; /* Should characters be upper case? */ } do { convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [uvalue % (unsigned) base]; uvalue = (uvalue / (unsigned) base); } while (uvalue && (place < 20)); if (place == 20) { place--; } convert[place] = 0; zpadlen = max - place; spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) { zpadlen = 0; } if (spadlen < 0) { spadlen = 0; } if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) { spadlen = -spadlen; /* Left Justifty */ } #ifdef DEBUG_SNPRINTF dprint(1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place)); #endif // DEBUG_SNPRINTF /* Spaces */ while (spadlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); } /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) { dopr_outch(buffer, currlen, maxlen, convert[--place]); } /* Left Justified spaces */ while (spadlen < 0) { dopr_outch(buffer, currlen, maxlen, ' '); ++spadlen; } } static LDOUBLE abs_val(LDOUBLE value) { LDOUBLE result = value; if (value < 0) { result = -value; } return result; } static LDOUBLE pow10(int exp) { LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result; } static long round(LDOUBLE value) { long intpart; intpart = value; value = value - intpart; if (value >= 0.5) { intpart++; } return intpart; } static void fmtfp(char *buffer, size_t * currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags) { int signvalue = 0; LDOUBLE ufvalue; char iconvert[20]; char fconvert[20]; int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; long intpart; long fracpart; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) { max = 6; } ufvalue = abs_val(fvalue); if (fvalue < 0) { signvalue = '-'; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ { signvalue = '+'; } else if (flags & DP_F_SPACE) { signvalue = ' '; } #if 0 if (flags & DP_F_UP) { caps = 1; /* Should characters be upper case? */ } #endif // 0 intpart = ufvalue; /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) { max = 9; } /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ fracpart = round((pow10(max)) * (ufvalue - intpart)); if (fracpart >= pow10(max)) { intpart++; fracpart -= pow10(max); } /* Convert integer part */ do { iconvert[iplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10]; intpart = (intpart / 10); } while (intpart && (iplace < 20)); if (iplace == 20) { iplace--; } iconvert[iplace] = 0; /* Convert fractional part */ do { fconvert[fplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10]; fracpart = (fracpart / 10); } while (fracpart && (fplace < 20)); if (fplace == 20) { fplace--; } fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) { zpadlen = 0; } if (padlen < 0) { padlen = 0; } if (flags & DP_F_MINUS) { padlen = -padlen; /* Left Justifty */ } if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); } while (iplace > 0) { dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); } /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { dopr_outch(buffer, currlen, maxlen, '.'); while (fplace > 0) { dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); } } while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c) { if (*currlen < maxlen) { buffer[(*currlen)++] = c; } } int xastir_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { str[0] = 0; dopr(str, count, fmt, args); return (strlen(str)); } #endif /* !HAVE_VSNPRINTF */ #ifndef HAVE_SNPRINTF #ifdef HAVE_STDARGS int xastir_snprintf(char *str, size_t count, const char *fmt, ...) #else // HAVE_STDARGS int xastir_snprintf(va_alist) va_dcl #endif // HAVE_STDARGS { # ifndef HAVE_STDARGS char *str; size_t count; char *fmt; # endif // HAVE_STDARGS VA_LOCAL_DECL; VA_START(fmt); VA_SHIFT(str, char *); VA_SHIFT(count, size_t); VA_SHIFT(fmt, char *); (void) xastir_vsnprintf(str, count, fmt, ap); VA_END; return (strlen(str)); } #endif /* !HAVE_SNPRINTF */ Xastir-Release-2.2.2/src/snprintf.h000066400000000000000000000032421501463444000171520ustar00rootroot00000000000000/* * snprintf.h * header file for snprintf.c * */ /* * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _XASTIR_COMPAT_SNPRINTF_H_ #define _XASTIR_COMPAT_SNPRINTF_H_ #include #include "config.h" #ifdef HAVE_STDARG_H #include #endif // HAVE_STDARG_H /* Use the system libraries version of vsnprintf() if available. Otherwise * use our own. */ #ifndef HAVE_VSNPRINTF int xastir_vsnprintf(char *str, size_t count, const char *fmt, va_list ap); #else // HAVE_VSNPRINTF #define xastir_vsnprintf vsnprintf #endif // HAVE_VSNPRINTF /* Use the system libraries version of snprintf() if available. Otherwise * use our own. */ #ifndef HAVE_SNPRINTF #ifdef __STDC__ int xastir_snprintf(char *str, size_t count, const char *fmt, ...); #else // __STDC__ int xastir_snprintf(); #endif // __STDC__ #else // HAVE_SNPRINTF #define xastir_snprintf snprintf #endif // HAVE_SNPRINTF #endif /* !XASTIR_COMPAT_SNPRINTF_H_ */ Xastir-Release-2.2.2/src/sound.c000066400000000000000000000062161501463444000164360ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include "xastir.h" #include "main.h" // Must be last include file #include "leak_detection.h" pid_t play_sound(char *sound_cmd, char *soundfile) { pid_t sound_pid; char command[600]; sound_pid=0; if (strlen(sound_cmd)>3 && strlen(soundfile)>1) { if (last_sound_pid==0) { // Create a new process to run in sound_pid = fork(); if (sound_pid!=-1) { if(sound_pid==0) { // This is the child process // Go back to default signal handler instead of // calling restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So // far this only works for "ps" listings, not // for "top". This code only works on Linux. // For BSD use setproctitle(3), NetBSD can use // setprogname(2). #ifdef __linux__ init_set_proc_title(my_argc, my_argv, my_envp); set_proc_title("%s", "festival process (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); #endif // __linux__ xastir_snprintf(command, sizeof(command), "%s %s/%s", sound_cmd, SOUND_DIR, soundfile); if (system(command) != 0) {} // We don't care whether it succeeded exit(0); // Exits only this process, not Xastir itself } else { // This is the parent process last_sound_pid=sound_pid; } } else { fprintf(stderr,"Error! trying to play sound\n"); } } else { sound_pid=last_sound_pid; /*fprintf(stderr,"Sound already running\n");*/ } } return(sound_pid); } int sound_done(void) { int done; int *status; status=NULL; done=0; if(last_sound_pid!=0) { if(waitpid(last_sound_pid,status,WNOHANG)==last_sound_pid) { done=1; last_sound_pid=0; } } return(done); } Xastir-Release-2.2.2/src/symbols.h000066400000000000000000000020371501463444000170000ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_SYMBOLS_H #define XASTIR_SYMBOLS_H /* define Symbol Active */ #endif /* XASTIR_SYMBOLS_H */ Xastir-Release-2.2.2/src/testdbfawk.c000066400000000000000000000175001501463444000174420ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #ifdef HAVE_LIBSHP #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #include #include #include "awk.h" #include "dbfawk.h" // Must be last include file #include "leak_detection.h" /* * Sample test program */ void die(const char *s) { fprintf(stderr,"%s\n",s); exit(1); } /* * print_symtbl: debugging */ void print_symtbl(awk_symtab *this) { awk_symbol *s; char buf[1024]; int len; int i; // fprintf(stderr,"symtbl 0%0x dump:\n",(u_int)this); fprintf(stderr,"symtbl 0x%0lx dump:\n", (uintptr_t)this); for (i = 0; i < AWK_SYMTAB_HASH_SIZE; i++) { for (s = this->hash[i]; s; s = s->next_sym) { *buf = '\0'; awk_get_sym(s,buf,sizeof(buf),&len); fprintf(stderr,"%d %s = '%.*s'\n",i,s->name,len,buf); } } } awk_rule rules[] = { { 0, BEGIN, NULL, NULL, 0, 0, "key=\"\"; lanes=1; color=8; name=\"\"; filled=0; pattern=1; display_level=8192; label_level=32",0,0 }, { 0, REGEXP, "^TLID=(.*)$", NULL, 0, 0, "key=\"$1\"",0,0 }, { 0, REGEXP, "^FENAME=United States Highway (.*)$", NULL, 0, 0, "name=\"US $1\"; next",0,0 }, { 0, REGEXP, "^FENAME=(.*)$", NULL, 0, 0, "name=\"$1\"; next",0,0 }, { 0, REGEXP, "^CFCC=A1", NULL, 0, 0, "lanes=4; color=4; next",0,0 }, { 0, REGEXP, "^CFCC=A3", NULL, 0, 0, "lanes=2; color=8",0,0 }, { 0, REGEXP, "^CFCC=A3[1-6]", NULL, 0, 0, "display_level=256; next",0,0 }, }; int nrules = sizeof(rules)/sizeof(rules[0]); void usage(void) { fprintf(stderr,"Usage: testdbfawk [-f file.awk| -D dir] -d file.dbf\n"); fprintf(stderr," -D for dir containing *.dbfawk files.\n"); fprintf(stderr," or -f for file containing awk rules.\n"); fprintf(stderr," -d for dbf file to parse \n"); } int debug = 0; int main(int argc, char *argv[]) { awk_program *rs = NULL; // int args; awk_symtab *symtbl; /* variables to bind to: */ int color = 0; int lanes = 0; int font_size = 0; char dbfinfo[1024]; /* list of DBF field names */ char dbffields[1024]; /* subset we want to read */ char name[128]; char key[128]; char symbol[4]; int filled = 5; int pattern=0; int display_level = 1234; int label_level = 9; int label_color = 8; char *dir = NULL,*file = NULL,*dfile = NULL; dbfawk_sig_info *si = NULL, *sigs = NULL; // Allocates new memory! symtbl = awk_new_symtab(); if (argc >= 2 && (strcmp(argv[1],"--help") == 0 || strcmp(argv[1],"-?") == 0)) { usage(); exit(1); } if (argc > 2 && strcmp(argv[1],"-D") == 0) { dir = argv[2]; argv++; argv++; argc -= 2; sigs = dbfawk_load_sigs(dir,".dbfawk"); if (!sigs) { die("Couldn't find dbfawk sigs\n"); } } else if (argc > 2 && strcmp(argv[1],"-f") == 0) { file = argv[2]; argv++; argv++; argc -= 2; rs = awk_load_program_file(file); /* load up the program */ } else { rs = awk_load_program_array(rules,nrules); /* load up the program */ } if (argc > 2 && strcmp(argv[1],"-d") == 0) { dfile = argv[2]; argv++; argv++; argc -= 2; } /* declare/bind these symbols */ // Allocates new memory! awk_declare_sym(symtbl,"dbfinfo",STRING,dbfinfo,sizeof(dbfinfo)); awk_declare_sym(symtbl,"dbffields",STRING,dbffields,sizeof(dbffields)); awk_declare_sym(symtbl,"color",INT,&color,sizeof(color)); awk_declare_sym(symtbl,"lanes",INT,&lanes,sizeof(lanes)); awk_declare_sym(symtbl,"name",STRING,name,sizeof(name)); awk_declare_sym(symtbl,"key",STRING,key,sizeof(key)); awk_declare_sym(symtbl,"symbol",STRING,symbol,sizeof(symbol)); awk_declare_sym(symtbl,"filled",INT,&filled,sizeof(filled)); awk_declare_sym(symtbl,"pattern",INT,&pattern,sizeof(pattern)); awk_declare_sym(symtbl,"display_level",INT,&display_level,sizeof(display_level)); awk_declare_sym(symtbl,"label_level",INT,&label_level,sizeof(label_level)); awk_declare_sym(symtbl,"label_color",INT,&label_color,sizeof(label_color)); awk_declare_sym(symtbl,"font_size",INT,&font_size,sizeof(font_size)); if (dfile) /* parse dbf file */ { DBFHandle dbf = DBFOpen(dfile,"rb"); int i; char sig[sizeof(dbfinfo)]; /* write the signature here */ int nf; dbfawk_field_info *fi; if (!dbf) { die("DBFopen: could not open dbf file"); } nf = dbfawk_sig(dbf,sig,sizeof(sig)); fprintf(stderr,"%d Columns, %d Records in file\n",nf, DBFGetRecordCount(dbf)); fprintf(stderr,"sig: %s\n",sig); /* If -D then search for matching sig; else use the supplied awk_prog */ if (sigs) { si = dbfawk_find_sig(sigs,sig,dfile); if (!si) { die("No matching dbfawk signature found"); } rs = si->prog; } if (awk_compile_program(symtbl,rs) < 0) { die("couldn't compile rules"); } awk_exec_begin(rs); /* execute a BEGIN rule if any */ // print_symtbl(symtbl); if (strcmp(sig,dbfinfo) == 0) { fprintf(stderr,"DBF Signatures match!\n"); } else { fprintf(stderr,"DBF Signatures DON'T match\n"); } fi = dbfawk_field_list(dbf, dbffields); /* now actually read the whole file */ for (i = 0; i < DBFGetRecordCount(dbf); i++ ) { dbfawk_parse_record(rs,dbf,fi,i); fprintf(stderr,"name=%s, ",name); fprintf(stderr,"key=%s, ",key); fprintf(stderr,"symbol=%s, ",symbol); fprintf(stderr,"color=%d, ", color); fprintf(stderr,"lanes=%d, ", lanes); fprintf(stderr,"filled=%d, ",filled); fprintf(stderr,"pattern=%d, ",pattern); fprintf(stderr,"display_level=%d, ",display_level); fprintf(stderr,"font_size=%d, ", font_size); fprintf(stderr,"label_level=%d\n",label_level); fprintf(stderr,"label_color=%d\n",label_color); // print_symtbl(symtbl); } DBFClose(dbf); } else /* use cmdline args */ { usage(); exit(1); /* * remove this capability because it leads to * segfaults if user gives invalid command line arguments. * better to just print usage string awk_exec_begin_record(rs); for (args = 1; args < argc; args++) { fprintf(stderr,"==> %s\n",argv[args]); awk_exec_program(rs,argv[args],strlen(argv[args])); // print_symtbl(symtbl); } awk_exec_end_record(rs); */ } awk_exec_end(rs); /* execute an END rule if any */ // print_symtbl(symtbl); if (si) { dbfawk_free_sigs(si); } else if (rs) { awk_free_program(rs); } awk_free_symtab(symtbl); free(symtbl); exit(0); } #else /* HAVE_LIBSHP */ int main(int argc, char *argv[]) { fprintf(stderr,"DBFAWK support not compiled.\n"); exit(1); } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.2/src/tile_mgmnt.c000066400000000000000000000221111501463444000174350ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "fetch_remote.h" #include "util.h" #include "snprintf.h" #include "maps.h" #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL #include "tile_mgmnt.h" // Must be last include file #include "leak_detection.h" // OSM Minimum cache time #define SECONDS_7_DAYS (7 * 24 * 3600) /* * latLon2tileNum - calculate tile number * * The tile number is returned in in the structure pointed to by the * tilenum argument. */ void latLon2tileNum (double lon_deg, double lat_deg, int zoom, tileNum_t *tilenum) { unsigned long ntiles; double lat_rad; ntiles = 1 << zoom; if (lat_deg > MAX_LAT_OSM) { lat_deg = MAX_LAT_OSM; } else if (lat_deg < (-1.0 * MAX_LAT_OSM)) { lat_deg = -1.0 * MAX_LAT_OSM; } if (lon_deg > MAX_LON_OSM) { lon_deg = MAX_LON_OSM; } else if (lon_deg < (-1.0 * MAX_LON_OSM)) { lon_deg = -1.0 * MAX_LON_OSM; } lat_rad = (lat_deg * M_PI) / 180.0; tilenum->x = ((lon_deg + 180.0) / 360.0) * ntiles; tilenum->y = ((1 - (log(tan(lat_rad) + (1.0 / cos(lat_rad))) / M_PI)) / 2.0) * ntiles; if (tilenum->y >= ntiles) { tilenum->y = (ntiles - 1); } if (tilenum->x >= ntiles) { tilenum->x = (ntiles - 1); } return; } // latLon2tileNum() /* * tile2coord - calculate lat/lon of NW corner of tile * * Use tilex+1 and tiley+1 to get the coordinates of the SE corner. * * Based on example code at * http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames * */ void tile2coord (unsigned long tilex, unsigned long tiley, int zoom, coord_t *NWcorner) { unsigned long ntiles; double lat_rad; ntiles = 1 << zoom; lat_rad = M_PI - ((2.0 * M_PI) * ((double)(tiley) / (double)ntiles)); NWcorner->lat = (180.0 / M_PI) * atan(0.5 * (exp((double)lat_rad) - exp(-1.0 * (double)lat_rad))); NWcorner->lon = (((double)(tilex) / (double)ntiles) * 360.0) - 180.0; return; } // tile2coord() /* * calcTileArea - calculate the x and y range of tile numbers * * Returns the calculated values in the structure pointed to by the * tiles argument. */ void calcTileArea (double lon_upper_left, double lat_upper_left, double lon_lower_right, double lat_lower_right, int zoom, tileArea_t *tiles) { tileNum_t tilenum; latLon2tileNum(lon_upper_left, lat_upper_left, zoom, &tilenum); tiles->startx = tilenum.x; tiles->starty = tilenum.y; latLon2tileNum(lon_lower_right, lat_lower_right, zoom, &tilenum); tiles->endx = tilenum.x; tiles->endy = tilenum.y; return; } // calcTileArea() /* * tilesMissing - return the count of tiles that are missing from the cache */ int tilesMissing (unsigned long startx, unsigned long endx, unsigned long starty, unsigned long endy, int zoom, char *cacheDir, char *tileExt) { struct stat sb; char local_filename[1100]; unsigned long x, y; int numMissing = 0; for (x = startx; x <= endx; x++) { for (y = starty; y <= endy; y++) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/%u/%lu/%lu.%s", cacheDir, zoom, x, y, tileExt); if (stat(local_filename, &sb) == -1) { numMissing++; } } } return(numMissing); } // end of tilesMissing() /* * getOneTile - get one tile from the web * * The tile is fetched if it does not exist and 1 is returned. * * If the tile exists in the cache and it is older than 7 days, then it * will be refreshed from the server. * * Returns 1 if a tile did not exist and download was attempted. * Returns 0 if a tile exists in the cache (tile might be updated). * * Returns libcurl errors as a negative integer. * * WARNING: Download failures are not reported for wget. * */ #ifdef HAVE_LIBCURL int getOneTile (CURL *session, char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt) { CURLcode res; time_t cacheTimeout; #else int getOneTile (char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt) { #endif // HAVE_LIBCURL struct stat sb; char url[1100]; char local_filename[1100]; int result = 0; xastir_snprintf(url, sizeof(url), "%s/%u/%lu/%lu.%s", baseURL, zoom, x, y, tileExt); xastir_snprintf(local_filename, sizeof(local_filename), "%s/%u/%lu/%lu.%s", baseDir, zoom, x, y, tileExt); if (stat(local_filename, &sb) == -1) { if (debug_level & 512) { fprintf(stderr, "Fetching %s\n", url); } result = 1; // only count files that do not exist #ifdef HAVE_LIBCURL res = fetch_remote_tile(session, url, local_filename); } else { // Check for updated tiles after 7 days, per // OSM Tile Usage Policy, // http://wiki.openstreetmap.org/wiki/Tile_usage_policy, // 2010/07/29 cacheTimeout = sb.st_mtime + SECONDS_7_DAYS; if (cacheTimeout <= time(NULL)) { // tile exists in the cache, but is older than 7 days, so // check the server for a newer version. if (debug_level & 512) { fprintf(stderr, "Refreshing %s.\n", url); } res = fetch_remote_tile(session, url, local_filename); } else { if (debug_level & 512) { fprintf(stderr, "Skipping- %s\n", url); fprintf(stderr, " because cache time has not expired.\n"); fprintf(stderr, " cache expires %s", ctime(&cacheTimeout)); } res = CURLE_OK; } } if (CURLE_OK != res) { // return the curl error as a negative value to distinqusih it // successful values result = -1 * (int)res; } #else // don't HAVE_LIBCURL (void)fetch_remote_file(url, local_filename); } #endif // HAVE_LIBCURL return(result); } // getOneTile() /* * mkpath() - attempt to make each directory in a path */ static void mkpath(const char *dir) { char tmp[MAX_FILENAME]; char *p = NULL; size_t len; xastir_snprintf(tmp, sizeof(tmp),"%s", dir); len = strlen(tmp); if(tmp[len - 1] == '/') { tmp[len - 1] = 0; } for (p = tmp + 1; *p; p++) { if(*p == '/') { *p = 0; mkdir(tmp, S_IRWXU); *p = '/'; } } mkdir(tmp, S_IRWXU); return; } // end of mkpath() /* * mkOSMmapDirs - try to create all the directories needed for the tiles * * This is simply a best-effort attempt because there are valid reasons * for mkdir() to fail. For example, the tiles could be buffered in a RO * structure. */ void mkOSMmapDirs (char *baseDir, unsigned long startx, unsigned long endx, int zoom) { char fullPath[MAX_FILENAME]; #ifdef HAVE_POSIX_STRERROR_R char errmsg[1024]; #endif struct stat sb; unsigned long dnum; xastir_snprintf(fullPath, sizeof(fullPath), "%s/%u/", baseDir, zoom); mkpath(fullPath); for (dnum = startx; dnum <= endx; dnum++) { xastir_snprintf(fullPath, sizeof(fullPath), "%s/%u/%lu/", baseDir, zoom, dnum); mkdir(fullPath, S_IRWXU); if (debug_level & 512) { if (stat(fullPath, &sb) == -1) { #ifdef HAVE_POSIX_STRERROR_R strerror_r(errno, errmsg, sizeof(errmsg)); fprintf(stderr, "%s: %s\n", errmsg, fullPath); #else fprintf(stderr, "%s: %s\n", strerror(errno), fullPath); #endif } else if ((sb.st_mode & S_IWUSR) != S_IWUSR) { fprintf(stderr, "warning: directory %s is not writable\n", fullPath); } else if (!S_ISDIR(sb.st_mode)) { fprintf(stderr, "warning: %s is not a directory\n", fullPath); } } } return; } // mkOSMmapDirs() Xastir-Release-2.2.2/src/tile_mgmnt.h000066400000000000000000000042151501463444000174470ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __TILE_MGMNT_H #define __TILE_MGMNT_H #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL typedef struct tileNum_s { unsigned long x; unsigned long y; } tileNum_t; typedef struct coord_s { double lat; double lon; } coord_t; typedef struct tileArea_s { unsigned long startx; unsigned long endx; unsigned long starty; unsigned long endy; } tileArea_t; #define MAX_LAT_OSM 85.0511 #define MAX_LON_OSM 180.0 void latLon2tileNum(double lon_deg, double lat_deg, int zoom, tileNum_t *tilenum); void tile2coord(unsigned long tilex, unsigned long tiley, int zoom, coord_t *NWcorner); void calcTileArea(double lon_upper_left,double lat_upper_left,double lon_lower_right,double lat_lower_right,int zoom,tileArea_t *tiles); #ifdef HAVE_LIBCURL int getOneTile(CURL *session, char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt); #else int getOneTile(char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt); #endif // HAVE_LIBCURL void mkOSMmapDirs(char *baseDir, unsigned long startx, unsigned long endx, int zoom); int tilesMissing (unsigned long startx, unsigned long endx, unsigned long starty, unsigned long endy, int zoom, char *baseDir, char *tileExt); #endif // __TILE_MGMNT_H Xastir-Release-2.2.2/src/track_gui.c000066400000000000000000001152271501463444000172610ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "lang.h" #include "objects.h" #include "popup.h" #include "fetch_remote.h" #include "util.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget track_station_dialog = (Widget)NULL; Widget track_station_data = (Widget)NULL; Widget download_findu_dialog = (Widget)NULL; static xastir_mutex track_station_dialog_lock; static xastir_mutex download_findu_dialog_lock; // track values Widget track_case_data, track_match_data; // Download findu values Widget download_trail_station_data; Widget posit_start_value; Widget posit_length_value; int fetching_findu_trail_now = 0; int track_station_on = 0; /* used for tracking stations */ int track_me; int track_case; /* used for tracking stations */ int track_match; /* used for tracking stations */ char tracking_station_call[30]; /* Tracking station callsign */ char download_trail_station_call[30]; /* Trail station callsign */ //N0VH #define MAX_FINDU_DURATION 120 #define MAX_FINDU_START_TIME 336 // Make these two match, as that will be the most desired case: Snag // the track for as far back as possible up to the present in one // shot... int posit_start = MAX_FINDU_DURATION; int posit_length = MAX_FINDU_DURATION; void track_gui_init(void) { init_critical_section( &track_station_dialog_lock ); init_critical_section( &download_findu_dialog_lock ); if (temp_tracking_station_call[0] != '\0') { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", temp_tracking_station_call); track_station_on = 1; } else { tracking_station_call[0] = '\0'; } } /**** Track STATION ******/ void track_station_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&track_station_dialog_lock, "track_gui.c:track_station_destroy_shell" ); XtDestroyWidget(shell); track_station_dialog = (Widget)NULL; end_critical_section(&track_station_dialog_lock, "track_gui.c:track_station_destroy_shell" ); } void Track_station_clear(Widget w, XtPointer clientData, XtPointer callData) { /* clear station */ track_station_on=0; //track_station_data=NULL; //tracking_station_call[0] = '\0'; // Clear the TrackMe button as well XmToggleButtonSetState(trackme_button,FALSE,TRUE); track_station_destroy_shell(w, clientData, callData); display_zoom_status(); } void Track_station_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[MAX_CALLSIGN+1]; char temp2[200]; int found = 0; char *temp_ptr; temp_ptr = XmTextFieldGetString(track_station_data); xastir_snprintf(temp, sizeof(temp), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); (void)remove_trailing_dash_zero(temp); xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", temp); track_case = (int)XmToggleButtonGetState(track_case_data); track_match = (int)XmToggleButtonGetState(track_match_data); found = locate_station(da, temp, track_case, track_match, 0); if ( valid_object(tracking_station_call) // Name of object is legal || valid_call(tracking_station_call) || valid_item(tracking_station_call ) ) { track_station_on = 1; // Track it whether we've seen it yet or not if (!found) { xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00026"), temp); popup_message_always(langcode("POPEM00025"),temp2); } // Check for exact match, includes SSID if ( track_me & !is_my_call( tracking_station_call, 1) ) { XmToggleButtonSetState( trackme_button, FALSE, FALSE ); track_me = 0; } } else { tracking_station_call[0] = '\0'; // Empty it out again track_station_on = 0; xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00002"), temp); popup_message_always(langcode("POPEM00003"),temp2); } track_station_destroy_shell(w, clientData, callData); display_zoom_status(); } void Track_station( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_close, button_clear, call, sep; Atom delw; if (!track_station_dialog) { begin_critical_section(&track_station_dialog_lock, "track_gui.c:Track_station" ); track_station_dialog = XtVaCreatePopupShell(langcode("WPUPTSP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Track_station pane", xmPanedWindowWidgetClass, track_station_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Track_station my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPTSP002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); track_station_data = XtVaCreateManagedWidget("Track_station track locate data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); track_case_data = XtVaCreateManagedWidget(langcode("WPUPTSP003"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); track_match_data = XtVaCreateManagedWidget(langcode("WPUPTSP004"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,track_case_data, XmNrightOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Track_station sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,track_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPTSP005"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_clear = XtVaCreateManagedWidget(langcode("WPUPTSP006"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Track_station_now, track_station_dialog); XtAddCallback(button_close, XmNactivateCallback, track_station_destroy_shell, track_station_dialog); XtAddCallback(button_clear, XmNactivateCallback, Track_station_clear, track_station_dialog); XmToggleButtonSetState(track_case_data,FALSE,FALSE); XmToggleButtonSetState(track_match_data,TRUE,FALSE); pos_dialog(track_station_dialog); delw = XmInternAtom(XtDisplay(track_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(track_station_dialog, delw, track_station_destroy_shell, (XtPointer)track_station_dialog); // if (track_station_on==1) XmTextFieldSetString(track_station_data,tracking_station_call); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, track_station_dialog); end_critical_section(&track_station_dialog_lock, "track_gui.c:Track_station" ); XtPopup(track_station_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(track_station_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(track_station_dialog), XtWindow(track_station_dialog)); } } /***** DOWNLOAD FINDU TRAILS *****/ // Struct used for passing two parameters to findu_transfer_thread typedef struct { char *download_client_ptrs[2]; } track_ptrs_struct; track_ptrs_struct track_ptrs; // This is the separate execution thread that fetches the track from // findu. The thread is started up by the Download_trail_now() // function below. // static void* findu_transfer_thread(void *arg) { char *fileimg; char *log_filename; // char log_filename_tmp[210]; char **ptrs; char sys_cmd[128]; // Get fileimg and log_filename from parameters ptrs = arg; log_filename = ptrs[0]; fileimg = ptrs[1]; // Set global "busy" variable fetching_findu_trail_now = 1; if (fetch_remote_file(fileimg, log_filename)) { // Had trouble getting the file. Abort. // We may not be able to do any GUI stuff from multiple // threads/processes at the same time. If that is found to be the // case we can write to STDERR instead. // Dump a message to STDERR // fprintf(stderr, // "%s %s\n", // langcode("POPEM00035"), // langcode("POPEM00044")); // Fetch Findu Trail: Failed popup_message_always(langcode("POPEM00035"), langcode("POPEM00044")); // Reset global "busy" variable fetching_findu_trail_now = 0; // End the thread return(NULL); } // We need to move this message up to the main thread if possible so // that we don't have multiple threads writing to the GUI. This // sort of operation can cause segfaults. In practice I haven't // seen any segfaults due to this particular popup though. // Fetch Findu Trail: Complete popup_message_always(langcode("POPEM00036"), langcode("POPEM00045")); // Set permissions on the file so that any user can overwrite it. chmod(log_filename, 0666); #if defined(HAVE_SED) // Add three spaces before each "
" and axe the "
". This // is so that Base-91 compressed packets with no comment and no // speed/course/altitude will get decoded ok. Otherwise the // spaces that are critical to the Base-91 packets won't be // there due to findu.com filtering them out. // // "sed -i -e \"s/
/
/\" %s", sprintf(sys_cmd, "%s -i -e \"s/
/ /\" %s", SED_PATH, log_filename); if (system(sys_cmd)) { fprintf(stderr,"Couldn't execute command: %s\n", sys_cmd); } // Greater-than symbol '>' sprintf(sys_cmd, "%s -i -e \"s/>/>/\" %s", SED_PATH, log_filename); if (system(sys_cmd)) { fprintf(stderr,"Couldn't execute command: %s\n", sys_cmd); } // Less-than symbol '<' sprintf(sys_cmd, "%s -i -e \"s/</Open Log File" routine. HTML // tags will be ignored just fine. read_file_ptr = fopen(log_filename, "r"); if (read_file_ptr != NULL) { read_file = 1; } else { fprintf(stderr,"Couldn't open file: %s\n", log_filename); } // Reset global "busy" variable fetching_findu_trail_now = 0; // End the thread return(NULL); } void Download_trail_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail_destroy_shell" ); XtDestroyWidget(shell); download_findu_dialog = (Widget)NULL; end_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail_destroy_shell" ); } void Download_trail_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[MAX_CALLSIGN+1]; static char fileimg[400]; static char log_filename[200]; char *temp_ptr; pthread_t download_trail_thread; static XtPointer download_client_data = NULL; char tmp_base_dir[MAX_VALUE]; get_user_base_dir("tmp",tmp_base_dir, sizeof(tmp_base_dir)); // If we're already fetching a trail, we shouldn't be calling // this callback function. Get out. if (fetching_findu_trail_now) { return; } // Pass two parameters to findu_transfer_thread via a struct track_ptrs.download_client_ptrs[0] = log_filename; track_ptrs.download_client_ptrs[1] = fileimg; download_client_data = &track_ptrs; // Check whether it's ok to do a download currently. if (read_file) { // No, we're already in the middle of reading in some file. // Skip trying to download yet another file. fprintf(stderr,"Processing another file. Wait a bit, then try again\n"); popup_message_always(langcode("POPEM00035"), langcode("POPEM00041")); return; } // busy_cursor(appshell); strcpy(log_filename, tmp_base_dir); log_filename[sizeof(log_filename)-1] = '\0'; // Terminate string strcat(log_filename, "/map.log"); log_filename[sizeof(log_filename)-1] = '\0'; // Terminate string // Erase any previously existing local file by the same name. // This avoids the problem of having an old tracklog here and // the code trying to display it when the download fails. unlink( log_filename ); XmScaleGetValue(posit_start_value, &posit_start); XmScaleGetValue(posit_length_value, &posit_length); temp_ptr = XmTextFieldGetString(download_trail_station_data); xastir_snprintf(temp, sizeof(temp), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); (void)remove_trailing_dash_zero(temp); xastir_snprintf(download_trail_station_call, sizeof(download_trail_station_call), "%s", temp); //Download_trail_destroy_shell(w, clientData, callData); // New URL's for findu. The second one looks very promising. //http://www.findu.com/cgi-bin/raw.cgi?call=k4hg-8&time=1 //http://www.findu.com/cgi-bin/rawposit.cgi?call=k4hg-8&time=1 // // The last adds this to the beginning of the line: // // "20030619235323," // // which is a date/timestamp. We'll need to do some extra stuff // here in order to actually use that date/timestamp though. // Setting the read_file_ptr to the downloaded file won't do it. // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d&time=1", // New, with timestamp xastir_snprintf(fileimg, sizeof(fileimg), // // Posits only: // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d", // // Posits plus timestamps (we can't handle timestamps yet): // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d&time=1", // New, with timestamp // // Download all packets, not just posits: "http://www.findu.com/cgi-bin/raw.cgi?call=%s&start=%d&length=%d", // download_trail_station_call,posit_start,posit_length); if (debug_level & 1024) { fprintf(stderr, "%s\n", fileimg); } //----- Start New Thread ----- if (pthread_create(&download_trail_thread, NULL, findu_transfer_thread, download_client_data)) { fprintf(stderr,"Error creating findu transfer thread\n"); } else { // We're off and running with the new thread! } display_zoom_status(); Download_trail_destroy_shell(w, clientData, callData); } void Reset_posit_length_max(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { XmScaleGetValue(posit_length_value, &posit_length); XmScaleGetValue(posit_start_value, &posit_start); // Check whether start hours is greater than max findu allows // for duration // if (posit_start > MAX_FINDU_DURATION) // Set the duration slider to { // findu's max duration hours XtVaSetValues(posit_length_value, XmNvalue, MAX_FINDU_DURATION, NULL); posit_length = MAX_FINDU_DURATION; } else // Not near the max, so set the duration slider to match { // the start hours XtVaSetValues(posit_length_value, XmNvalue, posit_start, NULL); posit_length = posit_start; } } void Download_findu_trail( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, call, sep; Atom delw; XmString x_str; if (!download_findu_dialog) { begin_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_findu_trail" ); download_findu_dialog = XtVaCreatePopupShell(langcode("WPUPTSP007"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Download_findu_trail pane", xmPanedWindowWidgetClass, download_findu_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Download_findu_trail my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPTSP008"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); download_trail_station_data = XtVaCreateManagedWidget("download_trail_station_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); x_str = XmStringCreateLocalized(langcode("WPUPTSP009")); posit_start_value = XtVaCreateManagedWidget("Start of Trail (hrs ago)", xmScaleWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, //XmNwidth, 190, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, XmNmaximum, MAX_FINDU_START_TIME, XmNshowValue, TRUE, XmNvalue, posit_start, // Note: Some versions of OpenMotif (distributed with Fedora, // perhaps others) don't work properly with XtVaTypedArg() as used // here, instead showing blank labels for the Scale widgets. // XtVaTypedArg, XmNtitleString, XmRString, langcode("WPUPTSP009"), 22, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); x_str = XmStringCreateLocalized(langcode("WPUPTSP010")); posit_length_value = XtVaCreateManagedWidget("Length of trail (hrs)", xmScaleWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, posit_start_value, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, //XmNwidth, 190, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, XmNmaximum, MAX_FINDU_DURATION, XmNshowValue, TRUE, XmNvalue, posit_length, // Note: Some versions of OpenMotif (distributed with Fedora, // perhaps others) don't work properly with XtVaTypedArg() as used // here, instead showing blank labels for the Scale widgets. // XtVaTypedArg, XmNtitleString, XmRString, langcode("WPUPTSP010"), 19, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); sep = XtVaCreateManagedWidget("Download_findu_trail sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,posit_length_value, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPTSP007"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); if (fetching_findu_trail_now) { XtSetSensitive(button_ok, FALSE); } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Download_trail_now, download_findu_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Download_trail_destroy_shell, download_findu_dialog); XtAddCallback(posit_start_value, XmNvalueChangedCallback, Reset_posit_length_max, download_findu_dialog); pos_dialog(download_findu_dialog); delw = XmInternAtom(XtDisplay(download_findu_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(download_findu_dialog, delw, Download_trail_destroy_shell, (XtPointer)download_findu_dialog); XmTextFieldSetString(download_trail_station_data,download_trail_station_call); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, download_findu_dialog); end_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail" ); XtPopup(download_findu_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(download_findu_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(download_findu_dialog), XtWindow(download_findu_dialog)); } } Xastir-Release-2.2.2/src/track_gui.h000066400000000000000000000025441501463444000172630ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * */ #ifndef __TRACK_GUI_H #define __TRACK_GUI_H /* from track_gui.c */ extern void track_gui_init(void); extern void Track_station(Widget w, XtPointer clientData, XtPointer callData); extern int track_station_on; extern int track_me; extern int track_case; extern int track_match; extern char tracking_station_call[30]; extern void Download_findu_trail(Widget w, XtPointer clientData, XtPointer callData); #endif // __TRACK_GUI_H Xastir-Release-2.2.2/src/util.c000066400000000000000000004757561501463444000163060ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "util.h" #include "main.h" #include "xa_config.h" #include "datum.h" #include "hashtable.h" #include "hashtable_itr.h" #include "maps.h" #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } // For mutex debugging with Linux threads only #ifdef MUTEX_DEBUG #include // // Newer pthread function #ifdef HAVE_PTHREAD_MUTEXATTR_SETTYPE extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); #endif // HAVE_PTHREAD_MUTEXATTR_SETTYPE // // Older, deprecated pthread function #ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP extern int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind); #endif // HAVE_PTHREAD_MUTEXATTR_SETKIND_NP // #endif // MUTEX_DEBUG #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL // Needed for size_t #include // Must be last include file #include "leak_detection.h" int position_amb_chars; char echo_digis[6][MAX_CALLSIGN+1]; #define ACCEPT_0N_0E /* set this to see stations at 0N/0E on the map */ struct timeval timer_start; struct timeval timer_stop; struct timezone tz; static struct hashtable *tactical_hash = NULL; #define TACTICAL_HASH_SIZE 1024 #define MAX_LOGFILE_SIZE 2048000 ///////////////////////////////////////////////////////////////////// // convert_from_xastir_coordinates() // // Converts from Xastir coordinate system to lat/lon. First two // parameters are the output floating point lat/lon values. 2nd two // are the input Xastir X/Y values. // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Returns 0 if error, 1 if good values were converted. // Errors are due to the x and/or y values exceeding the above // limits. In such cases the float values are set to appropriate // minimum or maximum values. ///////////////////////////////////////////////////////////////////// int convert_from_xastir_coordinates ( float *f_longitude, float *f_latitude, long x, long y ) { //fprintf(stderr,"convert_from_xastir_coordinates\n"); int result = 1; // assume the input values are in range if (x < 0l ) { fprintf(stderr, "convert_from_xastir_coordinates:X out-of-range (too low):%lu\n", x); x = 0; result = 0; } if (x > 129600000l) { fprintf(stderr, "convert_from_xastir_coordinates:X out-of-range (too high):%lu\n", x); x = 129600000l; result = 0; } if (y < 0l) { fprintf(stderr, "convert_from_xastir_coordinates:Y out-of-range (too low):%lu\n", y); y = 0; result = 0; } if (y > 64800000l) { fprintf(stderr, "convert_from_xastir_coordinates:Y out-of-range (too high):%lu\n", y); y = 64800000l; result = 0; } *f_latitude = (float)( -((y - 32400000l) / 360000.0) ); *f_longitude = (float)( (x - 64800000l) / 360000.0 ); //fprintf(stderr,"input x: %lu\tinput y: %lu\n", // x, // y); //fprintf(stderr,"latitude: %f\tlongitude: %f\n", // *f_latitude, // *f_longitude); return(result); } ///////////////////////////////////////////////////////////////////// // convert_to_xastir_coordinates() // // Converts from lat/lon to Xastir coordinate system. // First two parameters are the output Xastir X/Y values, // 2nd two are the input floating point lat/lon values. // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Returns 0 if error, 1 if good values were converted. ///////////////////////////////////////////////////////////////////// int convert_to_xastir_coordinates ( unsigned long* x, unsigned long* y, float f_longitude, float f_latitude ) { int ok = 1; *y = (unsigned long)(32400000l + (360000.0 * (-f_latitude))); *x = (unsigned long)(64800000l + (360000.0 * f_longitude)); if (f_longitude < -180.0) { fprintf(stderr, "convert_to_xastir_coordinates:Longitude out-of-range (too low):%f\n", f_longitude); *x = 0; ok = 0; } if (f_longitude > 180.0) { fprintf(stderr, "convert_to_xastir_coordinates:Longitude out-of-range (too high):%f\n", f_longitude); *x = 129600000l; ok = 0; } if (f_latitude < -90.0) { fprintf(stderr, "convert_to_xastir_coordinates:Latitude out-of-range (too low):%f\n", f_latitude); *y = 0; ok = 0; } if (f_latitude > 90.0) { fprintf(stderr, "convert_to_xastir_coordinates:Latitude out-of-range (too high):%f\n", f_latitude); *y = 64800000l; ok =0; } return(ok); } // Multiply all the characters in the callsign, truncated to // TACTICAL_HASH_SIZE // unsigned int tactical_hash_from_key(void *key) { unsigned char *jj = key; unsigned int tac_hash = 1; while (*jj != '\0') { tac_hash = tac_hash * (unsigned int)*jj++; } tac_hash = tac_hash % TACTICAL_HASH_SIZE; // fprintf(stderr,"hash = %d\n", tac_hash); return (tac_hash); } int tactical_keys_equal(void *key1, void *key2) { //fprintf(stderr,"Comparing %s to %s\n",(char *)key1,(char *)key2); if (strlen((char *)key1) == strlen((char *)key2) && strncmp((char *)key1,(char *)key2,strlen((char *)key1))==0) { //fprintf(stderr," match\n"); return(1); } else { //fprintf(stderr," no match\n"); return(0); } } void init_tactical_hash(int clobber) { // fprintf(stderr," Initializing tactical hash \n"); // make sure we don't leak //fprintf(stderr,"init_tactical_hash\n"); if (tactical_hash) { //fprintf(stderr,"Already have one!\n"); if (clobber) { //fprintf(stderr,"Clobbering hash table\n"); hashtable_destroy(tactical_hash, 1); tactical_hash=create_hashtable(TACTICAL_HASH_SIZE, tactical_hash_from_key, tactical_keys_equal); } } else { //fprintf(stderr,"Creating hash table from scratch\n"); tactical_hash=create_hashtable(TACTICAL_HASH_SIZE, tactical_hash_from_key, tactical_keys_equal); } } char *get_tactical_from_hash(char *callsign) { char *result; if (callsign == NULL || *callsign == '\0') { fprintf(stderr,"Empty callsign passed to get_tactical_from_hash()\n"); return(NULL); } if (!tactical_hash) // no table to search { //fprintf(stderr,"Creating hash table\n"); init_tactical_hash(1); // so create one return NULL; } // fprintf(stderr," searching for %s...",callsign); result=hashtable_search(tactical_hash,callsign); if (result) { // fprintf(stderr,"\t\tFound it, %s, len=%d, %s\n", // callsign, // strlen(callsign), // result); } else { // fprintf(stderr,"\t\tNot found, %s, len=%d\n", // callsign, // strlen(callsign)); } return (result); } // This function checks whether there already is something in the // hashtable that matches. If a match found, it overwrites the // tactical call for that entry, else it inserts a new record. // void add_tactical_to_hash(char *callsign, char *tactical_call) { char *temp1; // tac-call char *temp2; // callsign char *ptr; // Note that tactical_call can be '\0', which means we're // getting rid of a previous tactical call. // if (callsign == NULL || *callsign == '\0' || tactical_call == NULL) { return; } if (!tactical_hash) // no table to add to { //fprintf(stderr,"init_tactical_hash\n"); init_tactical_hash(1); // so create one } // Remove any matching entry to avoid duplicates ptr = hashtable_remove(tactical_hash, callsign); if (ptr) // If value found, free the storage space for it as { // the hashtable_remove function doesn't. It does // however remove the key (callsign) ok. free(ptr); } temp1 = (char *)malloc(MAX_TACTICAL_CALL+1); CHECKMALLOC(temp1); temp2 = (char *)malloc(MAX_CALLSIGN+1); CHECKMALLOC(temp2); //fprintf(stderr, "\t\t\tAdding %s = %s...\n", callsign, tactical_call); xastir_snprintf(temp2, MAX_CALLSIGN+1, "%s", callsign); xastir_snprintf(temp1, MAX_TACTICAL_CALL+1, "%s", tactical_call); // (key) (value) // hash call tac-call if (!hashtable_insert(tactical_hash, temp2, temp1)) { fprintf(stderr,"Insert failed on tactical hash --- fatal\n"); free(temp1); free(temp2); exit(1); } // A check to see whether hash insert/update worked properly ptr = get_tactical_from_hash(callsign); if (!ptr) { fprintf(stderr,"***Failed hash insert/update***\n"); } else { //fprintf(stderr,"Current: %s -> %s\n", // callsign, // ptr); } } void destroy_tactical_hash(void) { struct hashtable_itr *iterator = NULL; char *value; if (tactical_hash && hashtable_count(tactical_hash) > 0) { iterator = hashtable_iterator(tactical_hash); do { if (iterator) { value = hashtable_iterator_value(iterator); if (value) { free(value); } } } while (hashtable_iterator_remove(iterator)); // Destroy the hashtable, freeing what's left of the // entries. hashtable_destroy(tactical_hash, 1); tactical_hash = NULL; if (iterator) { free(iterator); } } } // Prints string to STDERR only if "my_debug_level" bits are set in // the global "debug_level" variable. Used for getting extra debug // messages during various stages of debugging. // void xastir_debug(int my_debug_level, char *debug_string) { if (debug_level & my_debug_level) { fprintf(stderr, "%s", debug_string); } } char *remove_all_spaces(char *data) { char *ptr; int length = strlen(data); ptr = data; while ( (ptr = strpbrk(data, " ")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); length--; } // Terminate at the new string length data[length] = '\0'; return(data); } char *remove_leading_spaces(char *data) { int i,j; int count; if (data == NULL) { return NULL; } if (strlen(data) == 0) { return NULL; } count = 0; // Count the leading space characters for (i = 0; i < (int)strlen(data); i++) { if (data[i] == ' ') { count++; } else // Found a non-space { break; } } // Check whether entire string was spaces if (count == (int)strlen(data)) { // Empty the string data[0] = '\0'; } else if (count > 0) // Found some spaces { i = 0; for( j = count; j < (int)strlen(data); j++ ) { data[i++] = data[j]; // Move string left } data[i] = '\0'; // Terminate the new string } return(data); } char *remove_trailing_spaces(char *data) { int datalen; if (data != NULL) { datalen=strlen(data); for(datalen--; datalen>=0; datalen--) if(data[datalen] == ' ') { data[datalen] = '\0'; } else { break; } } // May end up with nothing left. return(data); } char *remove_trailing_asterisk(char *data) { int datalen; if (data != NULL) { datalen=strlen(data); for(datalen--; datalen>0; datalen--) { if(data[datalen] == '*') { data[datalen] = '\0'; } else { break; } } } // May end up with nothing left. return(data); } // Removes trailing "-0" from string. // // Modifies "data" variable. // char *remove_trailing_dash_zero(char *data) { char *ptr; char *ptr2; int len = strlen(data); // String too short? if (len < 2) { return(data); } ptr2 = data + len - 1; // Point to last char ptr = ptr2 - 1; // Point to next-to-last char // Check for "-0" at end. Remove if found. if (*ptr == '-' && *ptr2 == '0') { *ptr = '\0'; // Terminate } return(data); } // Save the current time, used for timing code sections. void start_timer(void) { gettimeofday(&timer_start,&tz); } // Save the current time, used for timing code sections. void stop_timer(void) { gettimeofday(&timer_stop,&tz); } // Print the difference in the two times saved above. void print_timer_results(void) { fprintf(stderr,"Total: %f sec\n", (float)(timer_stop.tv_sec - timer_start.tv_sec + ((timer_stop.tv_usec - timer_start.tv_usec) / 1000000.0) )); } // // Inserts localtime date/time in "timestring". Timestring // Should be at least 101 characters long. // void get_timestamp(char *timestring) { struct tm *time_now; time_t secs_now; secs_now=sec_now(); time_now = localtime(&secs_now); // %e is not implemented on all systems, but %d should be // (void)strftime(timestring,100,"%a %b %e %H:%M:%S %Z %Y",time_now); (void)strftime(timestring,100,"%a %b %d %H:%M:%S %Z %Y",time_now); } /* function get_iso_datetime converts time in seconds to an ISO date * time in the form yyyy-mm-dd hh:mm:ss utc_offset * @param aTime time in seconds since the begining of the unix epoch * @param timestring pointer to a char[101] into which the timestamp * is written in the format yyyy-mm-dd hh:mm:ss followed by a utc * offset for the timezone. * @param nowIfNotSet when true, if aTime is not set (int)aTime==0, * then return the current time rather than formatting aTime, when * false, returns formatted aTime even if it was zero. * @param nowIfInvalid when true, if aTime is invalid (int)aTime=-1, * then returns the formatted current time rather than formatting * aTime, otherwise returns formatted invalid time. * @returns 0 on when (int)aTime==-1 where time provided invalid * returns 1 otherwise. */ int get_iso_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid) { struct tm *time_now; time_t secs_now; int returnvalue = 1; if (((int)aTime==0 && nowIfNotSet) || ((int)aTime==-1 && nowIfInvalid)) { secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%F %H:%M:%S %z",time_now); } else { // will also end up here if time_t is -1 (void)strftime(timestring,100,"%F %H:%M:%S %z",localtime(&aTime)); } if ((int)aTime==-1) { returnvalue = 0; } return returnvalue; } /* function get_W3CDTF_datetime converts time in seconds to a W3CDTF date * time in the form yyyy-mm-ddThh:mm:ss-utc_offsethh:mm * See: http://www.w3.org/TR/NOTE-datetime * This is effectively an ISO date, with a T between the date and the * time, no space between the time and the utc offset, and a colon * separating utc offset hours from utc offset seconds. * Example: 2008-01-25T08:35:20-05:00 * @param aTime time in seconds since the begining of the unix epoch * @param timestring pointer to a char[101] into which the timestamp * is written in the format yyyy-mm-ddThh:mm:ss followed by a utc * offset for the timezone, (e.g. -05:00). * @param nowIfNotSet when true, if aTime is not set (int)aTime==0, * then return the current time rather than formatting aTime, when * false, returns formatted aTime even if it was zero. * @param nowIfInvalid when true, if aTime is invalid (int)aTime=-1, * then returns the formatted current time rather than formatting * aTime, otherwise returns formatted invalid time. * @returns 0 on when (int)aTime==-1 where time provided invalid * returns 1 otherwise. */ int get_w3cdtf_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid) { struct tm *time_now; time_t secs_now; int returnvalue = 1; if (((int)aTime==0 && nowIfNotSet) || ((int)aTime==-1 && nowIfInvalid)) { secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%FT%H:%M:%S %z",time_now); timestring[19] = timestring[20]; timestring[20] = timestring[21]; timestring[21] = timestring[22]; timestring[22] = ':'; } else { // will also end up here if time_t is -1 (void)strftime(timestring,100,"%FT%H:%M:%S %z",localtime(&aTime)); timestring[19] = timestring[20]; timestring[20] = timestring[21]; timestring[21] = timestring[22]; timestring[22] = ':'; } if ((int)aTime==-1) { returnvalue = 0; } return returnvalue; } /***********************************************************/ /* returns the hour (00..23), localtime */ /***********************************************************/ int get_hours(void) { struct tm *time_now; time_t secs_now; char shour[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(shour,4,"%H",time_now); return(atoi(shour)); } /***********************************************************/ /* returns the minute (00..59), localtime */ /***********************************************************/ int get_minutes(void) { struct tm *time_now; time_t secs_now; char sminute[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(sminute,4,"%M",time_now); return(atoi(sminute)); } /***********************************************************/ /* returns the second (00..61), localtime */ /***********************************************************/ int get_seconds(void) { struct tm *time_now; time_t secs_now; char sminute[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(sminute,4,"%S",time_now); return(atoi(sminute)); } /*************************************************************************/ /* output_lat - format position with position_amb_chars for transmission */ /*************************************************************************/ char *output_lat(char *in_lat, int comp_pos) { int i,j; //fprintf(stderr,"in_lat:%s\n", in_lat); if (!comp_pos) { // Don't do this as it results in truncation! //in_lat[7]=in_lat[8]; // Shift N/S down for transmission } else if (position_amb_chars>0) { in_lat[7]='0'; } j=0; if (position_amb_chars>0 && position_amb_chars<5) { for (i=6; i>(6-position_amb_chars-j); i--) { if (i==4) { i--; j=1; } if (!comp_pos) { in_lat[i]=' '; } else { in_lat[i]='0'; } } } if (!comp_pos) { in_lat[8] = '\0'; } return(in_lat); } /**************************************************************************/ /* output_long - format position with position_amb_chars for transmission */ /**************************************************************************/ char *output_long(char *in_long, int comp_pos) { int i,j; //fprintf(stderr,"in_long:%s\n", in_long); if (!comp_pos) { // Don't do this as it results in truncation! //in_long[8]=in_long[9]; // Shift e/w down for transmission } else if (position_amb_chars>0) { in_long[8]='0'; } j=0; if (position_amb_chars>0 && position_amb_chars<5) { for (i=7; i>(7-position_amb_chars-j); i--) { if (i==5) { i--; j=1; } if (!comp_pos) { in_long[i]=' '; } else { in_long[i]='0'; } } } if (!comp_pos) { in_long[9] = '\0'; } return(in_long); } /*********************************************************************/ /* PHG range calculation */ /* NOTE: Keep these calculations consistent with phg_decode! */ /* Yes, there is a reason why they both exist. */ /*********************************************************************/ double phg_range(char p, char h, char g) { double power, height, gain, range; if ( (p < '0') || (p > '9') ) // Power is outside limits { power = 0.0; } else { power = (double)( (p-'0')*(p-'0') ); // lclint said: "Assignment of char to double" here } if (h < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(h-'0')); } if ( (g < '0') || (g > '9') ) // Gain is outside limits { gain = 1.0; } else { gain = pow(10.0, (double)(g-'0') / 10.0); } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // if (range > 70.0) // fprintf(stderr,"PHG%c%c%c results in range of %f\n", p, h, g, range); // Note: Bob Bruninga, WB4APR, decided to cut PHG circles by // 1/2 in order to show more realistic mobile ranges. range = range / 2.0; return(range); } /*********************************************************************/ /* shg range calculation (for DF'ing) */ /* */ /*********************************************************************/ double shg_range(char s, char h, char g) { double power, height, gain, range; if ( (s < '0') || (s > '9') ) // Power is outside limits { s = '0'; } if (s == '0') // No signal strength { power = 10.0 / 0.8; // Preventing divide by zero (same as DOSaprs does it) } else { power = 10 / (s - '0'); // Makes circle smaller with higher signal strengths } if (h < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(h-'0')); } if ( (g < '0') || (g > '9') ) // Gain is outside limits { gain = 1.0; } else { gain = pow(10.0, (double)(g-'0') / 10.0); } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); range = (range * 40) / 51; // Present fudge factors used in DOSaprs //fprintf(stderr,"SHG%c%c%c results in range of %f\n", s, h, g, range); return(range); } /*********************************************************************/ /* PHG decode */ /* NOTE: Keep these calculations consistent with phg_range! */ /* Yes, there is a reason why they both exist. */ /*********************************************************************/ void phg_decode(const char *langstr, const char *phg, char *phg_decoded, int phg_decoded_length) { double power, height, gain, range; char directivity[6], temp[64]; int gain_db; if (strlen(phg) != 7) { xastir_snprintf(phg_decoded, phg_decoded_length, "%s %s", langstr, langcode("WPUPSTI073") ); // "BAD PHG" return; } if ( (phg[3] < '0') || (phg[3] > '9') ) // Power is outside limits { power = 0.0; } else { power = (double)( (phg[3]-'0')*(phg[3]-'0') ); } if (phg[4] < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(phg[4]-'0')); } if ( (phg[5] < '0') || (phg[5] > '9') ) // Gain is outside limits { gain = 1.0; gain_db = 0; } else { gain = pow(10.0, (double)(phg[5]-'0') / 10.0); gain_db = phg[5]-'0'; } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // Note: Bob Bruninga, WB4APR, decided to cut PHG circles by // 1/2 in order to show more realistic mobile ranges. range = range / 2.0; switch (phg[6]) { case '0': xastir_snprintf(directivity, sizeof(directivity), "%s", langcode("WPUPSTI071") ); // "omni" break; case '1': xastir_snprintf(directivity, sizeof(directivity), "%s", " NE"); break; case '2': xastir_snprintf(directivity, sizeof(directivity), "%s", " E"); break; case '3': xastir_snprintf(directivity, sizeof(directivity), "%s", " SE"); break; case '4': xastir_snprintf(directivity, sizeof(directivity), "%s", " S"); break; case '5': xastir_snprintf(directivity, sizeof(directivity), "%s", " SW"); break; case '6': xastir_snprintf(directivity, sizeof(directivity), "%s", " W"); break; case '7': xastir_snprintf(directivity, sizeof(directivity), "%s", " NW"); break; case '8': xastir_snprintf(directivity, sizeof(directivity), "%s", " N"); break; default: directivity[0] = '\0'; break; } if (english_units) xastir_snprintf(temp, sizeof(temp), "%.0fW @ %.0fft %s, %ddB%s, %s %.1fmi", power, height, langcode("WPUPSTI070"), // HAAT gain_db, directivity, langcode("WPUPSTI072"), // range range); else xastir_snprintf(temp, sizeof(temp), "%.0fW @ %.1fm %s, %ddB%s, %s %.1fkm", power, height*0.3048, langcode("WPUPSTI070"), // HAAT gain_db, directivity, langcode("WPUPSTI072"), // range range*1.609344); xastir_snprintf(phg_decoded, phg_decoded_length, "%s %s", langstr, temp); } /*********************************************************************/ /* SHG decode */ /* */ /*********************************************************************/ void shg_decode(const char *langstr, const char *shg, char *shg_decoded, int shg_decoded_length) { double power, height, gain, range; char directivity[6], temp[100], signal[64]; int gain_db; char s; if (strlen(shg) != 7) { xastir_snprintf(shg_decoded, shg_decoded_length, langstr, langcode("WPUPSTI074") ); // "BAD SHG" return; } s = shg[3]; if ( (s < '0') || (s > '9') ) // Signal is outside limits { s = '0'; // force to lowest legal value } switch (s) { case '0': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI076") ); // "No signal detected" break; case '1': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI077") ); // "Detectible signal (Maybe)" break; case '2': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI078") ); // "Detectible signal but not copyable)" break; case '3': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI079") ); // "Weak signal, marginally readable" break; case '4': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI080") ); // "Noisy but copyable signal" break; case '5': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI081") ); // "Some noise, easy to copy signal" break; case '6': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI082") ); // "Good signal w/detectible noise" break; case '7': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI083") ); // "Near full-quieting signal" break; case '8': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI084") ); // "Full-quieting signal" break; case '9': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI085") ); // "Extremely strong & full-quieting signal" break; default: signal[0] = '\0'; break; } if (s == '0') { power = (double)( 10 / 0.8 ); // Preventing divide by zero (same as DOSaprs does it) } else { power = (double)( 10 / (s - '0') ); } if (shg[4] < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(shg[4]-'0')); } if ( (shg[5] < '0') || (shg[5] > '9') ) // Gain is outside limits { gain = 1.0; gain_db = 0; } else { gain = pow(10.0, (double)(shg[5]-'0') / 10.0); gain_db = shg[5]-'0'; } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); range = range * 0.85; // Present fudge factor (used by DOSaprs) switch (shg[6]) { case '0': xastir_snprintf(directivity, sizeof(directivity), "%s ", langcode("WPUPSTI071") ); // "omni" break; case '1': xastir_snprintf(directivity, sizeof(directivity), "%s", " NE"); break; case '2': xastir_snprintf(directivity, sizeof(directivity), "%s", " E"); break; case '3': xastir_snprintf(directivity, sizeof(directivity), "%s", " SE"); break; case '4': xastir_snprintf(directivity, sizeof(directivity), "%s", " S"); break; case '5': xastir_snprintf(directivity, sizeof(directivity), "%s", " SW"); break; case '6': xastir_snprintf(directivity, sizeof(directivity), "%s", " W"); break; case '7': xastir_snprintf(directivity, sizeof(directivity), "%s", " NW"); break; case '8': xastir_snprintf(directivity, sizeof(directivity), "%s", " N"); break; default: directivity[0] = '\0'; break; } if (english_units) { xastir_snprintf(temp, sizeof(temp), "%.0fft %s, %ddB%s, %s: %.1fmi, %s", height, langcode("WPUPSTI070"), // "HAAT" gain_db, directivity, langcode("WPUPSTI075"), // "DF Range" range, signal); } else { xastir_snprintf(temp, sizeof(temp), "%.1fm %s, %ddB%s, %s: %.1fkm, %s", height*0.3048, langcode("WPUPSTI070"), // "HAAT" gain_db, directivity, langcode("WPUPSTI075"), // "DF Range" range*1.609344, signal); } xastir_snprintf(shg_decoded, shg_decoded_length, langstr, temp); } /*********************************************************************/ /* Bearing decode */ /* */ /*********************************************************************/ void bearing_decode(const char *langstr, const char *bearing_str, const char *NRQ, char *bearing_decoded, int bearing_decoded_length) { int bearing, range, width; char N,R,Q; char temp[64]; //fprintf(stderr,"bearing_decode incoming: bearing is %s, NRQ is %s\n", bearing_str, NRQ); if (strlen(bearing_str) != 3) { xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, langcode("WPUPSTI086") ); // "BAD BEARING" return; } if (strlen(NRQ) != 3) { xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, langcode("WPUPSTI087") ); // "BAD NRQ" return; } bearing = atoi(bearing_str); N = NRQ[0]; R = NRQ[1]; Q = NRQ[2]; range = 0; width = 0; if (N != 0) { //fprintf(stderr,"N != 0\n"); range = pow(2.0,R - '0'); switch (Q) { case('1'): width = 240; // Degrees of beam width. What's the point? break; case('2'): width = 120; // Degrees of beam width. What's the point? break; case('3'): width = 64; // Degrees of beam width. What's the point? break; case('4'): width = 32; // Degrees of beam width. Starting to be usable. break; case('5'): width = 16; // Degrees of beam width. Usable. break; case('6'): width = 8; // Degrees of beam width. Usable. break; case('7'): width = 4; // Degrees of beam width. Nice! break; case('8'): width = 2; // Degrees of beam width. Nice! break; case('9'): width = 1; // Degrees of beam width. Very Nice! break; default: width = 8; // Degrees of beam width break; } //fprintf(stderr,"Width = %d\n",width); if (english_units) { xastir_snprintf(temp, sizeof(temp), "%i%c, %s: %i%c, %s: %i mi", bearing, 0xb0, // Degree symbol langcode("WPUPSTI088"), // DF Beamwidth width, 0xb0, // Degree symbol langcode("WPUPSTI089"), // DF Length range); } else { xastir_snprintf(temp, sizeof(temp), "%i%c, %s: %i%c, %s: %0.2f km", bearing, 0xb0, // Degree symbol langcode("WPUPSTI088"), // DF Beamwidth width, 0xb0, // Degree symbol langcode("WPUPSTI089"), // DF Length range*1.609344); } } else { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI090") ); // "Not Valid" //fprintf(stderr,"N was 0\n"); } xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, temp); //fprintf(stderr,"bearing_decoded:%s\n", bearing_decoded); //fprintf(stderr,"temp:%s\n", temp); } //********************************************************************/ // get_line - read a line from a file */ // // NOTE: This routine will not work for binary files. It works only // for ASCII-format files, and terminates each line at the first // control-character found (unless it's a tab). Converts tab // character to 1 space character. // //********************************************************************/ /* char *get_line(FILE *f, char *linedata, int maxline) { char temp_line[32768]; int i; // Snag one string from the file. We'll end up with a // terminating zero at temp_line[32767] in any case, because the // max quantity we'll get here will be 32767 with a terminating // zero added after whatever quantity is read. (void)fgets(temp_line, 32768, f); // A newline may have been added by the above fgets call. // Change any newlines or other control characters to line-end // characters. for (i = 0; i < strlen(temp_line); i++) { // Change any control characters to '\0'; if (temp_line[i] < 0x20) { if (temp_line[i] == '\t') { // Found a tab char temp_line[i] = ' '; // Convert to a space char } else { // Not a tab if (temp_line[i] != '\n') { // LF if ( (i != (strlen(temp_line) - 2) ) // CRLF && (i != (strlen(temp_line) - 1) ) ) { // CR fprintf(stderr,"get_line: found control chars in: %s\n", temp_line); } } temp_line[i] = '\0'; // Terminate the string } } } xastir_snprintf(linedata, maxline, "%s", temp_line); return(linedata); } */ char *get_line(FILE *f, char *linedata, int maxline) { int length; // Write terminating chars throughout variable memset(linedata,0,maxline); // Get the data if (fgets(linedata, maxline, f) == 0) { return "\0"; // Couldn't read from file: Return empty string } // Change CR/LF to '\0' length = strlen(linedata); // Check the last two characters if (length > 0) { if ( (linedata[length - 1] == '\n') || (linedata[length - 1] == '\r') ) { linedata[length - 1] = '\0'; } } if (length > 1) { if ( (linedata[length - 2] == '\n') || (linedata[length - 2] == '\r') ) { linedata[length - 2] = '\0'; } } return(linedata); } // time_from_aprsstring() // // Called from alert.c:alert_build_list() only. Converts to // localtime if it's a zulu time string we're parsing. // time_t time_from_aprsstring(char *aprs_time) { int day, hour, minute; char tz[20]; struct tm *time_now, alert_time; time_t timenw; long zone; #ifndef HAVE_TM_GMTOFF #ifdef __CYGWIN__ // Use "_timezone" instead of timezone in Cygwin #define timezone _timezone #else // __CYGWIN__ extern time_t timezone; #endif // __CYGWIN__ #endif // HAVE_TM_GMTOFF #ifdef __CYGWIN__ // Must call tzset before using the _timezone variable in // Cygwin, else the timezone won't have been initialized. tzset(); #endif // __CYGWIN__ // Compute our current time and the offset from GMT. If // daylight savings time is in effect, factor that in as well. (void)time(&timenw); time_now = localtime(&timenw); #ifdef HAVE_TM_GMTOFF // tm_gmtoff is the GMT offset in seconds. Some Unix systems // have this extra field in the tm struct, some don't. // tm_gmtoff is seconds EAST of UTC. zone = time_now->tm_gmtoff; //fprintf(stderr,"gmtoff: %ld, tm_isdst: %d\n", //time_now->tm_gmtoff, //time_now->tm_isdst); #else // HAVE_TM_GMTOFF // Note: timezone is seconds WEST of UTC. Need to negate // timezone to have the offset occur in the correct direction. zone = -((int)timezone - 3600 * (int)(time_now->tm_isdst > 0)); //fprintf(stderr,"timezone: %d, tm_isdst: %d\n", //timezone, //time_now->tm_isdst); #endif // HAVE_TM_GMTOFF // zone should now be the number to subtract in order to get // localtime, in seconds. For PST, I get -28800 which equals -8 // hours. Summertime I should get -25200, or -7 hours. //fprintf(stderr,"Zone: %ld\n",zone); // Split the input time string into its component parts. tz[0] = tz[1] = '\0'; switch (sscanf(aprs_time, "%2d%2d%2d%19s", &day, &hour, &minute, tz)) { case 0: day = 0; /* Falls through. */ case 1: hour = 0; /* Falls through. */ case 2: minute = 0; /* Falls through. */ default: break; } if (day > 31) { day = 31; // Wierd, can't have too many days in the month! hour = 23; minute = 59; } // We set up our alert_time so that it points into the same // struct as time_now. We do this both so that we can get // automatically filled in pieces of the struct (year, etc), and // so that we have a more global struct to return the time in. // We'll have to adjust a few things like month/year if the time // is too far distant from our current time and crosses some // boundary. alert_time = *time_now; alert_time.tm_sec = 0; //fprintf(stderr,"alert_time: %d %d %d\n", // alert_time.tm_mday, // alert_time.tm_hour, // alert_time.tm_min); // Check to see how many parameters we parsed, and do our // computations accordingly. if (day) // If we parsed out the day { // Check whether our new day is more than ten days +/- from // the current day of the month. If so, assume it was from // the month previous or after. if (day < (time_now->tm_mday - 10)) { // Day of month went down drastically. Must be a date // in the next month. Bump up by one month and check // whether we overflowed into the next year. Note that // month ranges from 0 to 11. if (++alert_time.tm_mon > 11) { alert_time.tm_mon = 0; alert_time.tm_year++; } } else if (day > (time_now->tm_mday + 10)) { // Day of month went up drastically. Must be a date // during last month. Decrement by one month and check // whether we need to also decrement the year. if (--alert_time.tm_mon < 0) { alert_time.tm_mon = 11; alert_time.tm_year--; } } // Fill in the struct with our new values that we parsed. alert_time.tm_mday = day; alert_time.tm_min = minute; alert_time.tm_hour = hour; // Need to do conversions from zulu time? if ((char)tolower((int)tz[0]) == 'z') { // Yep, do the conversions. Note that the zone variable // already has the sign set correctly to get the correct // time by using addition (PDT zone = -28800). // Initialize daylight savings time to 0 in this // instance, 'cuz we're starting with Zulu time and we // want the localtime conversion to change it correctly. // Zulu time has no daylight savings time offset. // // WE7U: // No, it gave us an offset of 6 hours from UTC when we set this to // zero, 7 hours (correct) when we set it to one, during the summer. // Hopefully it will give us an 8-hour offset during the wintertime // but that remains to be seen... // // FYI: We're in daylight savings time during the summer, when // we're at a 7-hour offset. Winter is actual time and a -8 hour // offset. // // One on-line resource suggested setting it to -1 for automatic // determination of DST. This works too, during the summer. Again, // check during the wintertime too when we're at normal time. // alert_time.tm_isdst = -1; // Do the hour offset alert_time.tm_hour += zone/3600; // Now check whether we have any offsets left to do. zone %= 3600; if (zone) { alert_time.tm_min += zone/60; } // Now check whether we have any overflows. According // to the "mktime()" man page, we probably don't need to // do this for overflow (It normalizes the time itself), // but I think we still need to for underflow. //WE7U: Check this stuff carefully! if (alert_time.tm_min > 59) { alert_time.tm_hour++; alert_time.tm_min -= 60; } if (alert_time.tm_hour > 23) { alert_time.tm_mday++; alert_time.tm_hour -= 24; if (mktime(&alert_time) == -1) { alert_time.tm_mday = 1; alert_time.tm_mon++; if (mktime(&alert_time) == -1) { alert_time.tm_mon = 0; alert_time.tm_year++; } } } else if (alert_time.tm_hour < 0) { alert_time.tm_hour += 24; if (--alert_time.tm_mday <= 0) { if (--alert_time.tm_mon < 0) { alert_time.tm_year--; alert_time.tm_mon = 11; alert_time.tm_mday = 31; } else if (alert_time.tm_mon == 3 || alert_time.tm_mon == 5 || alert_time.tm_mon == 8 || alert_time.tm_mon == 10) { alert_time.tm_mday = 30; } else if (alert_time.tm_mon == 1) { alert_time.tm_mday = (alert_time.tm_year%4 == 0) ? 29: 28; } else { alert_time.tm_mday = 31; } } } } } else // We didn't parse out the day from the input string. { // What's this all about??? Different format of APRS // time/date string? alert_time.tm_year--; } if ( debug_level & 2 ) { time_t a_time,now_time,diff; fprintf(stderr,"\n Input: %s\n",aprs_time); fprintf(stderr,"Output: %02d%02d%02d\n\n", alert_time.tm_mday, alert_time.tm_hour, alert_time.tm_min); a_time = mktime(&alert_time); fprintf(stderr,"Alert: %ld\n", (long)a_time); now_time = sec_now(); fprintf(stderr," Now: %ld\n", (long)now_time); diff = now_time - a_time; if (diff >= 0) { fprintf(stderr,"Expired by %ld minutes\n", (long)(diff/60) ); } else { fprintf(stderr,"%ld minutes until expiration\n", (long)((-diff)/60) ); } if (alert_time.tm_isdst > 0) { fprintf(stderr,"Daylight savings time is in effect\n"); } } return(mktime(&alert_time)); } // Note: last_speed should be in knots. // // Input format for lat/long is DDMM.MM or DDMM.MMM format, like: // 4722.93N 12244.17W or // 4722.938N 12244.177W // char *compress_posit(const char *input_lat, const char group, const char *input_lon, const char symbol, const unsigned int last_course, const unsigned int last_speed, const char *phg) { static char pos[100]; char lat[5], lon[5]; char c, s, t, ext; int temp, deg; double minutes; char temp_str[20]; //fprintf(stderr,"lat:%s, long:%s, symbol:%c%c, course:%d, speed:%d, phg:%s\n", // input_lat, // input_lon, // group, // symbol, // last_course, // last_speed, // phg); // Fetch degrees (first two chars) temp_str[0] = input_lat[0]; temp_str[1] = input_lat[1]; temp_str[2] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) xastir_snprintf(temp_str, sizeof(temp_str), "%s", input_lat); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for North latitude if (strstr(input_lat, "N") || strstr(input_lat, "n")) { ext = 'N'; } else { ext = 'S'; } //fprintf(stderr,"ext:%c\n", ext); temp = 380926 * (90 - (deg + minutes / 60.0) * ( ext=='N' ? 1 : -1 )); //fprintf(stderr,"temp: %d\t",temp); lat[3] = (char)(temp%91 + 33); temp /= 91; lat[2] = (char)(temp%91 + 33); temp /= 91; lat[1] = (char)(temp%91 + 33); temp /= 91; lat[0] = (char)(temp + 33); lat[4] = '\0'; //fprintf(stderr,"%s\n",lat); // Fetch degrees (first three chars) temp_str[0] = input_lon[0]; temp_str[1] = input_lon[1]; temp_str[2] = input_lon[2]; temp_str[3] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) xastir_snprintf(temp_str, sizeof(temp_str), "%s", input_lon); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees temp_str[2] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for West longitude if (strstr(input_lon, "W") || strstr(input_lon, "w")) { ext = 'W'; } else { ext = 'E'; } //fprintf(stderr,"ext:%c\n", ext); temp = 190463 * (180 + (deg + minutes / 60.0) * ( ext=='W' ? -1 : 1 )); //fprintf(stderr,"temp: %d\t",temp); lon[3] = (char)(temp%91 + 33); temp /= 91; lon[2] = (char)(temp%91 + 33); temp /= 91; lon[1] = (char)(temp%91 + 33); temp /= 91; lon[0] = (char)(temp + 33); lon[4] = '\0'; //fprintf(stderr,"%s\n",lon); // Set up csT bytes for course/speed if either are non-zero c = s = t = ' '; if (last_course > 0 || last_speed > 0) { if (last_course >= 360) { c = '!'; // 360 would be past 'z'. Set it to zero. } else { c = (char)(last_course/4 + 33); } s = (char)(log(last_speed + 1.0) / log(1.08) + 33.5); // Poor man's rounding + ASCII t = 'C'; } // Else set up csT bytes for PHG if within parameters else if (strlen(phg) >= 6) { double power, height, gain, range, s_temp; c = '{'; if ( (phg[3] < '0') || (phg[3] > '9') ) // Power is out of limits { power = 0.0; } else { power = (double)((int)(phg[3]-'0')); power = power * power; // Lowest possible value is 0.0 } if (phg[4] < '0') // Height is out of limits (no upper limit according to the spec) { height = 10.0; } else { height= 10.0 * pow(2.0,(double)phg[4] - (double)'0'); // Lowest possible value is 10.0 } if ( (phg[5] < '0') || (phg[5] > '9') ) // Gain is out of limits { gain = 1.0; } else { gain = pow(10.0,((double)(phg[5]-'0') / 10.0)); // Lowest possible value is 1.0 } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // Lowest possible value is 0.0 // Check for range of 0, and skip log10 if so if (range != 0.0) { s_temp = log10(range/2) / log10(1.08) + 33.0; } else { s_temp = 0.0 + 33.0; } s = (char)(s_temp + 0.5); // Cheater's way of rounding, add 0.5 and truncate t = 'C'; } // Note that we can end up with three spaces at the end if no // course/speed/phg were supplied. Do not knock this down, as // the compressed posit has a fixed 13-character length // according to the spec! // xastir_snprintf(pos, sizeof(pos), "%c%s%s%c%c%c%c", group, lat, lon, symbol, c, s, t); //fprintf(stderr,"New compressed pos: (%s)\n",pos); return pos; } /* * See if position is defined * 90N 180W (0,0 in internal coordinates) is our undefined position * 0N/0E is excluded from trails, could be excluded from map (#define ACCEPT_0N_0E) */ int position_defined(long lat, long lon, int UNUSED(strict)) { if (lat == 0l && lon == 0l) { return(0); // undefined location } #ifndef ACCEPT_0N_0E if (strict) #endif // ACCEPT_0N_0E if (lat == 90*60*60*100l && lon == 180*60*60*100l) // 0N/0E { return(0); // undefined location } return(1); } // Function to convert from screen (pixel) coordinates to the Xastir // coordinate system. // void convert_screen_to_xastir_coordinates(int x, int y, long *lat, long *lon) { *lon = (center_longitude - ((screen_width * scale_x)/2) + (x * scale_x)); *lat = (center_latitude - ((screen_height * scale_y)/2) + (y * scale_y)); if (*lon < 0) { *lon = 0l; // 180W } if (*lon > 129600000l) { *lon = 129600000l; // 180E } if (*lat < 0) { *lat = 0l; // 90N } if (*lat > 64800000l) { *lat = 64800000l; // 90S } } // Convert Xastir lat/lon to UTM printable string void convert_xastir_to_UTM_str(char *str, int str_len, long x, long y) { double utmNorthing; double utmEasting; char utmZone[10]; ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), &utmNorthing, &utmEasting, utmZone, sizeof(utmZone) ); utmZone[9] = '\0'; //fprintf(stderr,"%s %07.0f %07.0f\n", utmZone, utmEasting, //utmNorthing ); xastir_snprintf(str, str_len, "%s %07.0f %07.0f", utmZone, utmEasting, utmNorthing); } // To produce MGRS coordinates, we'll call ll_to_utm_ups() // [?? Earlier text: "the above function" ??] // then convert the result to the 2-letter digraph format used // for MGRS. The ll_to_utm_ups() function switches to the special // irregular UTM zones for the areas near Svalbard and SW Norway // if the "coordinate_system" variable is set to "USE_MGRS", // so we'll be using the correct zone boundaries for MGRS if that // variable is set when we make the call. // // If "nice_format" == 1, we add leading spaces plus spaces between // the easting and northing in order to line up more nicely with the // UTM output format. // // convert_xastir_to_MGRS_str is a wrapper around the components // function below that returns the MGRS coordinate of x and y as a // single MGRS string. // /* convert_xastir_to_MGRS_str_components returns each of the components of the MGRS string separately. Example MGRS string: 18T VK 66790 55998 Parameters: utmZone Returns the UTM zone: e.g. 18T utmZone_len length of the utmZone char[] EastingL Returns the first letter of the MGRS digraph: e.g. V EastingL_len length of the EastingL char[] NorthingL Returns the second letter of the MGRS digraph: e.g. K NorthingL_len length of the NorthingL char[] int_utmEasting returns the MGRS easting: e.g. 66790 int_utmNorthing returns the MGRS northing: e.g. 55998 x xastir x coordinate to obtain MGRS coordinate for. y xastir x coordinate to obtain MGRS coordinate for. nice_format 1 for populate space_string with three spaces 0 to make space_string and empty string, see above. space_string Returned string that can be used to make MGRS strings allign more cleanly with UTM strings. space_string_len length of the space_string char[] */ void convert_xastir_to_MGRS_str_components(char *utmZone, int UNUSED(utmZone_len), char *EastingL, int EastingL_len, char *NorthingL, int NorthingL_len, unsigned int *int_utmEasting, unsigned int *int_utmNorthing, long x, long y, int nice_format, char *space_string, int UNUSED(space_string_len) ) { double utmNorthing; double utmEasting; //char utmZone[10]; int start; int my_east, my_north; //unsigned int int_utmEasting, int_utmNorthing; int UPS = 0; int North_UPS = 0; int coordinate_system_save = coordinate_system; //char space_string[4] = " "; // Three spaces // Set for correct zones coordinate_system = USE_MGRS; ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), &utmNorthing, &utmEasting, utmZone, sizeof(utmZone) ); utmZone[9] = '\0'; // Restore it coordinate_system = coordinate_system_save; //fprintf(stderr,"%s %07.0f %07.0f\n", utmZone, utmEasting, //utmNorthing ); //xastir_snprintf(str, str_len, "%s %07.0f %07.0f", // utmZone, utmEasting, utmNorthing ); // Convert the northing and easting values to the digraph letter // format. Letters 'I' and 'O' are skipped for both eastings // and northings. Letters 'W' through 'Z' are skipped for // northings. // // N/S letters alternate in a cycle of two. Begins at the // equator with A and F in alternate zones. Odd-numbered zones // use A-V, even-numbered zones use F-V, then A-V. // // E/W letters alternate in a cycle of three. Each E/W zone // uses an 8-letter block. Starts at A-H, then J-R, then S-Z, // then repeats every 18 degrees. // // N/S letters have a cycle of two, E/W letters have a cycle of // three. The same lettering repeats after six zones (2,000,000 // meter intervals). // // AA is at equator and 180W. // Easting: Each zone covers 6 degrees. Zone 1 = A-H, Zone 2 = // J-R, Zone 3 = S-Z, then repeat. So, take zone number-1, // modulus 3, multiple that number by 8. Modulus 24. That's // our starting letter for the zone. Take the easting number, // divide by 100,000, , add the starting number, compute modulus // 24, then use that index into our E_W array. // // Northing: Figure out whether even/odd zone number. Divide // by 100,000. If even, add 5 (starts at 'F' if even). Compute // modulus 20, then use that index into our N_S array. *int_utmEasting = (unsigned int)utmEasting; *int_utmNorthing = (unsigned int)utmNorthing; *int_utmEasting = *int_utmEasting % 100000; *int_utmNorthing = *int_utmNorthing % 100000; // Check for South Polar UPS area, set flags if found. if ( utmZone[0] == 'A' || utmZone[0] == 'B' || utmZone[1] == 'A' || utmZone[1] == 'B' || utmZone[2] == 'A' || utmZone[2] == 'B' ) { // We're in the South Polar UPS area UPS++; } // Check for North Polar UPS area, set flags if found. else if ( utmZone[0] == 'Y' || utmZone[0] == 'Z' || utmZone[1] == 'Y' || utmZone[1] == 'Z' || utmZone[2] == 'Y' || utmZone[2] == 'Z') { // We're in the North Polar UPS area UPS++; North_UPS++; } else { // We're in the UTM area. Set no flags. } if (UPS) // Special processing for UPS area (A/B/Y/Z bands) { // Note: Zone number isn't used for UPS, but zone letter is. if (nice_format) // Add two leading spaces { utmZone[2] = utmZone[0]; utmZone[0] = ' '; utmZone[1] = ' '; utmZone[3] = '\0'; } else { space_string[0] = '\0'; } if (North_UPS) // North polar UPS zone { char UPS_N_Easting[15] = "RSTUXYZABCFGHJ"; char UPS_N_Northing[15] = "ABCDEFGHJKLMNP"; // Calculate the index into the 2-letter digraph arrays. my_east = (int)(utmEasting / 100000.0); my_east = my_east - 13; my_north = (int)(utmNorthing / 100000.0); my_north = my_north - 13; /*xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, UPS_N_Easting[my_east], UPS_N_Northing[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL,EastingL_len, "%c", UPS_N_Easting[my_east]); xastir_snprintf(NorthingL,NorthingL_len, "%c", UPS_N_Northing[my_north]); } else // South polar UPS zone { char UPS_S_Easting[25] = "JKLPQRSTUXYZABCFGHJKLPQR"; char UPS_S_Northing[25] = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // Calculate the index into the 2-letter digraph arrays. my_east = (int)(utmEasting / 100000.0); my_east = my_east - 8; my_north = (int)(utmNorthing / 100000.0); my_north = my_north - 8; /* xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, UPS_S_Easting[my_east], UPS_S_Northing[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL,EastingL_len, "%c", UPS_S_Easting[my_east]); xastir_snprintf(NorthingL,NorthingL_len, "%c", UPS_S_Northing[my_north]); } } else // UTM Area { char E_W[25] = "ABCDEFGHJKLMNPQRSTUVWXYZ"; char N_S[21] = "ABCDEFGHJKLMNPQRSTUV"; if (!nice_format) { space_string[0] = '\0'; } // Calculate the indexes into the 2-letter digraph arrays. start = atoi(utmZone); start--; start = start % 3; start = start * 8; start = start % 24; // "start" is now an index into the starting letter for the // zone. my_east = (int)(utmEasting / 100000.0) - 1; my_east = my_east + start; my_east = my_east % 24; // fprintf(stderr, "Start: %c East (guess): %c ", // E_W[start], // E_W[my_east]); start = atoi(utmZone); start = start % 2; if (start) // Odd-numbered zone { start = 0; } else // Even-numbered zone { start = 5; } my_north = (int)(utmNorthing / 100000.0); my_north = my_north + start; my_north = my_north % 20; // fprintf(stderr, "Start: %c North (guess): %c\n", // N_S[start], // N_S[my_north]); /* xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, E_W[my_east], N_S[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL, EastingL_len, "%c", E_W[my_east]); xastir_snprintf(NorthingL, NorthingL_len, "%c", N_S[my_north]); } } /* Wrapper around convert_xastir_to_MGRS_str_components to return an MGRS coordinate as a single string. Parameters: str The character array to be populated with the MGRS string. str_len Length of str. x xastir x coordinate. y xastir y coordinate. If "nice_format" == 1, we add leading spaces plus spaces between the easting and northing in order to line up more nicely with the UTM output format. */ void convert_xastir_to_MGRS_str(char *str, int str_len, long x, long y, int nice_format) { char space_string[4] = " "; // Three spaces unsigned int intEasting = 0; unsigned int intNorthing = 0; char EastingL[3] = " "; char NorthingL[3] = " "; char utmZone[10]; convert_xastir_to_MGRS_str_components(utmZone, strlen(utmZone), EastingL, sizeof(EastingL), NorthingL, sizeof(NorthingL), &intEasting, &intNorthing, x, y, nice_format, space_string, strlen(space_string)) ; xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, EastingL[0], NorthingL[0], intEasting, space_string, intNorthing ); } // Convert Xastir lat/lon to UTM void convert_xastir_to_UTM(double *easting, double *northing, char *zone, int zone_len, long x, long y) { ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), northing, easting, zone, zone_len); zone[zone_len-1] = '\0'; } // Convert UTM to Xastir lat/lon void convert_UTM_to_xastir(double easting, double northing, char *zone, long *x, long *y) { double lat, lon; utm_ups_to_ll(E_WGS_84, northing, easting, zone, &lat, &lon); // Reverse latitude to fit our coordinate system then convert to // Xastir units. *y = (long)(lat * -360000.0) + 32400000l; // Convert longitude to xastir units *x = (long)(lon * 360000.0) + 64800000l; } // convert latitude from long to string // Input is in Xastir coordinate system // // CONVERT_LP_NOSP = DDMM.MMN // CONVERT_HP_NOSP = DDMM.MMMN // CONVERT_VHP_NOSP = DDMM.MMMMN // CONVERT_LP_NORMAL = DD MM.MMN // CONVERT_HP_NORMAL = DD MM.MMMN // CONVERT_UP_TRK = NDD MM.MMMM // CONVERT_DEC_DEG = DD.DDDDDN // CONVERT_DMS_NORMAL = DD MM SS.SN // CONVERT_DMS_NORMAL_FORMATED = DD'MM'SS.SN // CONVERT_HP_NORMAL_FORMATED = DD'MM.MMMMN // void convert_lat_l2s(long lat, char *str, int str_len, int type) { char ns; float deg, min, sec; int ideg, imin; long temp; str[0] = '\0'; deg = (float)(lat - 32400000l) / 360000.0; // Switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(deg * 100000); ns = 'S'; if (temp <= 0) { ns = 'N'; temp = labs(temp); } ideg = (int)temp / 100000; min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(min * 1000); imin = (int)(temp / 1000); sec = (temp % 1000) * 60.0 / 1000.0; switch (type) { case(CONVERT_LP_NOSP): /* do low P w/no space */ xastir_snprintf(str, str_len, "%02d%05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_LP_NORMAL): /* do low P normal */ xastir_snprintf(str, str_len, "%02d %05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_HP_NOSP): /* do HP w/no space */ xastir_snprintf(str, str_len, "%02d%06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_VHP_NOSP): /* do Very HP w/no space */ xastir_snprintf(str, str_len, "%02d%07.4f%c", ideg, // min+0.00001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_UP_TRK): /* for tracklog files */ xastir_snprintf(str, str_len, "%c%02d %07.4f", ns, ideg, // min+0.00001); // Correct possible unbiased rounding min); break; case(CONVERT_DEC_DEG): xastir_snprintf(str, str_len, "%08.5f%c", // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding ideg+min/60.0, ns); break; case(CONVERT_DMS_NORMAL): xastir_snprintf(str, str_len, "%02d %02d %04.1f%c", ideg, imin, // sec+0.01, // Correct possible unbiased rounding sec, ns); break; case(CONVERT_DMS_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%02d%c%02d\'%04.1f%c", ideg, 0xb0, // Degree symbol imin, // sec+0.01, // Correct possible unbiased rounding sec, ns); break; case(CONVERT_HP_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%02d%c%06.3f%c", ideg, 0xb0, // Degree symbol // min+0.0001, // Correct possible unbiased roundin min, ns); break; case(CONVERT_HP_NORMAL): default: /* do HP normal */ xastir_snprintf(str, str_len, "%02d %06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ns); break; } } // convert longitude from long to string // Input is in Xastir coordinate system // // CONVERT_LP_NOSP = DDDMM.MME // CONVERT_HP_NOSP = DDDMM.MMME // CONVERT_VHP_NOSP = DDDMM.MMMME // CONVERT_LP_NORMAL = DDD MM.MME // CONVERT_HP_NORMAL = DDD MM.MMME // CONVERT_UP_TRK = EDDD MM.MMMM // CONVERT_DEC_DEG = DDD.DDDDDE // CONVERT_DMS_NORMAL = DDD MM SS.SN // CONVERT_DMS_NORMAL_FORMATED = DDD'MM'SS.SN // void convert_lon_l2s(long lon, char *str, int str_len, int type) { char ew; float deg, min, sec; int ideg, imin; long temp; str[0] = '\0'; deg = (float)(lon - 64800000l) / 360000.0; // Switch to integer arithmetic to avoid floating-point rounding // errors. temp = (long)(deg * 100000); ew = 'E'; if (temp <= 0) { ew = 'W'; temp = labs(temp); } ideg = (int)temp / 100000; min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(min * 1000); imin = (int)(temp / 1000); sec = (temp % 1000) * 60.0 / 1000.0; switch(type) { case(CONVERT_LP_NOSP): /* do low P w/nospacel */ xastir_snprintf(str, str_len, "%03d%05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_LP_NORMAL): /* do low P normal */ xastir_snprintf(str, str_len, "%03d %05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_HP_NOSP): /* do HP w/nospace */ xastir_snprintf(str, str_len, "%03d%06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_VHP_NOSP): /* do Very HP w/nospace */ xastir_snprintf(str, str_len, "%03d%07.4f%c", ideg, // min+0.00001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_UP_TRK): /* for tracklog files */ xastir_snprintf(str, str_len, "%c%03d %07.4f", ew, ideg, // min+0.00001); // Correct possible unbiased rounding min); break; case(CONVERT_DEC_DEG): xastir_snprintf(str, str_len, "%09.5f%c", // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding ideg+min/60.0, ew); break; case(CONVERT_DMS_NORMAL): xastir_snprintf(str, str_len, "%03d %02d %04.1f%c", ideg, imin, // sec+0.01, // Correct possible unbiased rounding sec, ew); break; case(CONVERT_DMS_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%03d%c%02d\'%04.1f%c", ideg, 0xb0, // Degree symbol imin, // sec+0.01, // Correct possible unbiased rounding sec, ew); break; case(CONVERT_HP_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%03d%c%06.3f%c", ideg, 0xb0, // Degree symbol // min+0.0001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_HP_NORMAL): default: /* do HP normal */ xastir_snprintf(str, str_len, "%03d %06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ew); break; } } /* convert latitude from string to long with 1/100 sec resolution */ // // Input is in [D]DMM.MM[MM]N format (degrees/decimal // minutes/direction) // long convert_lat_s2l(char *lat) /* N=0, Ctr=90, S=180 */ { long centi_sec; char copy[15]; char n[15]; char *p; char offset; // Find the decimal point if present p = strstr(lat, "."); if (p == NULL) // No decimal point found { return(0l); } memset(copy, '\0', sizeof(copy)); offset = p - lat; // Arithmetic on pointers switch (offset) { case 0: // .MM[MM]N return(0l); // Bad, no degrees or minutes break; case 1: // M.MM[MM]N return(0l); // Bad, no degrees break; case 2: // MM.MM[MM]N return(0l); // Bad, no degrees break; case 3: // DMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "0%s", // Add a leading '0' lat); break; case 4: // DDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "%s", // Copy verbatim lat); break; default: break; } copy[14] = '\0'; centi_sec=0l; if (copy[4]=='.' && ( (char)toupper((int)copy[ 5])=='N' || (char)toupper((int)copy[ 6])=='N' || (char)toupper((int)copy[ 7])=='N' || (char)toupper((int)copy[ 8])=='N' || (char)toupper((int)copy[ 9])=='N' || (char)toupper((int)copy[10])=='N' || (char)toupper((int)copy[11])=='N' || (char)toupper((int)copy[ 5])=='S' || (char)toupper((int)copy[ 6])=='S' || (char)toupper((int)copy[ 7])=='S' || (char)toupper((int)copy[ 8])=='S' || (char)toupper((int)copy[ 9])=='S' || (char)toupper((int)copy[10])=='S' || (char)toupper((int)copy[11])=='S')) { substr(n, copy, 2); // degrees centi_sec=atoi(n)*60*60*100; substr(n, copy+2, 2); // minutes centi_sec += atoi(n)*60*100; substr(n, copy+5, 4); // fractional minutes // Keep the fourth digit if present, as it resolves to 0.6 // of a 1/100 sec resolution. Two counts make one count in // the Xastir coordinate system. // Extend the digits to full precision by adding zeroes on // the end. strncat(n, "0000", sizeof(n) - 1 - strlen(n)); // Get rid of the N/S character if (!isdigit((int)n[2])) { n[2] = '0'; } if (!isdigit((int)n[3])) { n[3] = '0'; } // Terminate substring at the correct digit n[4] = '\0'; //fprintf(stderr,"Lat: %s\n", n); // Add 0.5 (Poor man's rounding) centi_sec += (long)((atoi(n) * 0.6) + 0.5); if ( (char)toupper((int)copy[ 5])=='N' || (char)toupper((int)copy[ 6])=='N' || (char)toupper((int)copy[ 7])=='N' || (char)toupper((int)copy[ 8])=='N' || (char)toupper((int)copy[ 9])=='N' || (char)toupper((int)copy[10])=='N' || (char)toupper((int)copy[11])=='N') { centi_sec = -centi_sec; } centi_sec += 90*60*60*100; } return(centi_sec); } /* convert longitude from string to long with 1/100 sec resolution */ // // Input is in [DD]DMM.MM[MM]W format (degrees/decimal // minutes/direction). // long convert_lon_s2l(char *lon) /* W=0, Ctr=180, E=360 */ { long centi_sec; char copy[16]; char n[16]; char *p; char offset; // Find the decimal point if present p = strstr(lon, "."); if (p == NULL) // No decimal point found { return(0l); } memset(copy, '\0', sizeof(copy)); offset = p - lon; // Arithmetic on pointers switch (offset) { case 0: // .MM[MM]N return(0l); // Bad, no degrees or minutes break; case 1: // M.MM[MM]N return(0l); // Bad, no degrees break; case 2: // MM.MM[MM]N return(0l); // Bad, no degrees break; case 3: // DMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "00%s", // Add two leading zeroes lon); break; case 4: // DDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "0%s", // Add leading '0' lon); break; case 5: // DDDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "%s", // Copy verbatim lon); break; default: break; } copy[15] = '\0'; centi_sec=0l; if (copy[5]=='.' && ( (char)toupper((int)copy[ 6])=='W' || (char)toupper((int)copy[ 7])=='W' || (char)toupper((int)copy[ 8])=='W' || (char)toupper((int)copy[ 9])=='W' || (char)toupper((int)copy[10])=='W' || (char)toupper((int)copy[11])=='W' || (char)toupper((int)copy[12])=='W' || (char)toupper((int)copy[ 6])=='E' || (char)toupper((int)copy[ 7])=='E' || (char)toupper((int)copy[ 8])=='E' || (char)toupper((int)copy[ 9])=='E' || (char)toupper((int)copy[10])=='E' || (char)toupper((int)copy[11])=='E' || (char)toupper((int)copy[12])=='E')) { substr(n,copy,3); // degrees 013 centi_sec=atoi(n)*60*60*100; substr(n,copy+3,2); // minutes 26 centi_sec += atoi(n)*60*100; // 01326.66E 01326.660E substr(n,copy+6,4); // fractional minutes 66E 660E or 6601 // Keep the fourth digit if present, as it resolves to 0.6 // of a 1/100 sec resolution. Two counts make one count in // the Xastir coordinate system. // Extend the digits to full precision by adding zeroes on // the end. strncat(n, "0000", sizeof(n) - 1 - strlen(n)); // Get rid of the E/W character if (!isdigit((int)n[2])) { n[2] = '0'; } if (!isdigit((int)n[3])) { n[3] = '0'; } n[4] = '\0'; // Make sure substring is terminated //fprintf(stderr,"Lon: %s\n", n); // Add 0.5 (Poor man's rounding) centi_sec += (long)((atoi(n) * 0.6) + 0.5); if ( (char)toupper((int)copy[ 6])=='W' || (char)toupper((int)copy[ 7])=='W' || (char)toupper((int)copy[ 8])=='W' || (char)toupper((int)copy[ 9])=='W' || (char)toupper((int)copy[10])=='W' || (char)toupper((int)copy[11])=='W' || (char)toupper((int)copy[12])=='W') { centi_sec = -centi_sec; } centi_sec +=180*60*60*100;; } return(centi_sec); } /* * Convert latitude from Xastir format to radian */ double convert_lat_l2r(long lat) { double ret; double degrees; degrees = (double)(lat / (100.0*60.0*60.0)) -90.0; ret = (-1)*degrees*(M_PI/180.0); return(ret); } /* * Convert longitude from Xastir format to radian */ double convert_lon_l2r(long lon) { double ret; double degrees; degrees = (double)(lon / (100.0*60.0*60.0)) -180.0; ret = (-1)*degrees*(M_PI/180.0); return(ret); } // Distance calculation (Great Circle) using the Haversine formula // (2-parameter arctan version), which gives better accuracy than // the "Law of Cosines" for short distances. It should be // equivalent to the "Law of Cosines for Spherical Trigonometry" for // longer distances. Haversine is a great-circle calculation. // // // Inputs: lat1/long1/lat2/long2 in radians (double) // // Outputs: Distance in meters between them (double) // double calc_distance_haversine_radian(double lat1, double lon1, double lat2, double lon2) { double dlon, dlat; double a, c, d; double R = EARTH_RADIUS_METERS; #define square(x) (x)*(x) dlon = lon2 - lon1; dlat = lat2 - lat1; a = square((sin(dlat/2.0))) + cos(lat1) * cos(lat2) * square((sin(dlon/2.0))); c = 2.0 * atan2(sqrt(a), sqrt(1.0-a)); d = R * c; return(d); } // Distance calculation (Great Circle) using the Haversine formula // (2-parameter arctan version), which gives better accuracy than // the "Law of Cosines" for short distances. It should be // equivalent to the "Law of Cosines for Spherical Trigonometry" for // longer distances. Haversine is a great-circle calculation. // // // Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) // // Outputs: Distance in meters between them (double) // double calc_distance_haversine(long lat1, long lon1, long lat2, long lon2) { double r_lat1,r_lat2; double r_lon1,r_lon2; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); return(calc_distance_haversine_radian(r_lat1, r_lon1, r_lat2, r_lon2)); } /* * Calculate distance in meters between two locations * * What type of calculation is this, Rhumb Line distance or Great * Circle distance? * Answer: "Law of Cosines for Spherical Trigonometry", which is a * great-circle calculation. * * * Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) * * Outputs: Distance in meters between them (double) * */ double calc_distance_law_of_cosines(long lat1, long lon1, long lat2, long lon2) { double r_lat1,r_lat2; double r_lon1,r_lon2; double r_d; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); r_d = acos(sin(r_lat1) * sin(r_lat2) + cos(r_lat1) * cos(r_lat2) * cos(r_lon1-r_lon2)); //fprintf(stderr,"Law of Cosines Distance: %f\n", // r_d*180*60/M_PI*1852); //fprintf(stderr," Haversine Distance: %f\n\n", // calc_distance_haversine(lat1, lon1, lat2, lon2)); return(r_d*180*60/M_PI*1852); } // Here's where we choose which of the above two functions get used. // double calc_distance(long lat1, long lon1, long lat2, long lon2) { // return(calc_distance_law_of_cosines(lat1, lon1, lat2, lon2)); return(calc_distance_haversine(lat1, lon1, lat2, lon2)); } /* * Calculate distance between two locations in nautical miles and course from loc2 to loc1 * * What type of calculation is this, Rhumb Line distance or Great * Circle distance? * Answer: "Law of Cosines for Spherical Trigonometry", which is a * great-circle calculation, or Haversine, also a great-circle * calculation. * * NOTE: The angle returned is a separate calculation, but using * the unit sphere distance in it's calculation. A great circle * bearing is computed, not a Rhumb-line bearing. * * * Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) * Length of course_deg string (int) * * Outputs: Distance in nautical miles between them (double). * course_deg (string) * */ double calc_distance_course(long lat1, long lon1, long lat2, long lon2, char *course_deg, int course_deg_length) { double ret; double r_lat1, r_lat2; double r_lon1, r_lon2; double r_d, r_c, r_m; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); // Compute the distance. We have a choice between using Law of // Cosines or Haversine Formula here. // 1) Law of Cosines for Spherical Trigonometry. This is // unreliable for small distances because the inverse cosine is // ill-conditioned. A computer carrying seven significant // digits can't distinguish the cosines of distances smaller // than about one minute of arc. // r_d = acos(sin(r_lat1) * sin(r_lat2) + cos(r_lat1) * cos(r_lat2) * cos(r_lon1-r_lon2)); // 2) Haversine Formula. Returns answer in meters. r_m = calc_distance_haversine_radian(r_lat1, r_lon1, r_lat2, r_lon2); // // Conversion from distance in meters back to unit sphere. This // is needed for the course calculation below as well as the // later scaling up to feet/meters or miles/km. r_d = r_m / EARTH_RADIUS_METERS; // Compute the great-circle bearing if (cos(r_lat1) < 0.0000000001) { if (r_lat1>0.0) { r_c=M_PI; } else { r_c=0.0; } } else { if (sin((r_lon2-r_lon1))<0.0) { r_c = acos((sin(r_lat2)-sin(r_lat1)*cos(r_d))/(sin(r_d)*cos(r_lat1))); } else { r_c = (2*M_PI) - acos((sin(r_lat2)-sin(r_lat1)*cos(r_d))/(sin(r_d)*cos(r_lat1))); } } // Return the course xastir_snprintf(course_deg, course_deg_length, "%.1f", (180.0/M_PI)*r_c); // Return the distance (nautical miles?) ret = r_d*180*60/M_PI; /* // Convert from nautical miles to feet fprintf(stderr,"Law of Cosines Distance: %fft\t%fmi\n", ret*5280.0*1.15078, ret*1.15078); // Convert from meters to feet fprintf(stderr," Haversine Distance: %fft\t%fmi\n\n", calc_distance_haversine(lat1, lon1, lat2, lon2)*3.28084, calc_distance_haversine(lat1, lon1, lat2, lon2)/1000/1.609344); */ return(ret); } //***************************************************************** // distance_from_my_station - compute distance from my station and // course with a given call // // return distance and course // // Returns 0.0 for distance if station not found in database or the // station hasn't sent out a posit yet. //***************************************************************** double distance_from_my_station(char *call_sign, char *course_deg) { DataRow *p_station; double distance; float value; long l_lat, l_lon; distance = 0.0; l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); p_station = NULL; if (search_station_name(&p_station,call_sign,1)) { // Check whether we have a posit yet for this station if ( (p_station->coord_lat == 0l) && (p_station->coord_lon == 0l) ) { distance = 0.0; } else { value = (float)calc_distance_course(l_lat, l_lon, p_station->coord_lat, p_station->coord_lon, course_deg, sizeof(course_deg)); if (english_units) { distance = value * 1.15078; // nautical miles to miles } else { distance = value * 1.852; // nautical miles to km } } // fprintf(stderr,"DistFromMy: %s %s -> %f\n",temp_lat,temp_long,distance); } else // Station not found { distance = 0.0; } //fprintf(stderr,"Distance for %s: %f\n", call_sign, distance); return(distance); } /*********************************************************************/ /* convert_bearing_to_name - converts a bearing in degrees to */ /* name for the bearing. Expects the degrees as a text string */ /* since that's what the preceding functions output. */ /* Set the opposite flag true for the inverse bearing (from vs to) */ /*********************************************************************/ static struct { double low,high; char *dircode,*lang; } directions[] = { {327.5,360,"N","SPCHDIRN00"}, {0,22.5,"N","SPCHDIRN00"}, {22.5,67.5,"NE","SPCHDIRNE0"}, {67.5,112.5,"E","SPCHDIRE00"}, {112.5,157.5,"SE","SPCHDIRSE0"}, {157.5,202.5,"S","SPCHDIRS00"}, {202.5,247.5,"SW","SPCHDIRSW0"}, {247.5,292.5,"W","SPCHDIRW00"}, {292.5,327.5,"NW","SPCHDIRNW0"}, }; char *convert_bearing_to_name(char *bearing, int opposite) { double deg = atof(bearing); int i; if (opposite) { if (deg > 180) { deg -= 180.0; } else if (deg <= 180) { deg += 180.0; } } for (i = 0; i < (int)( sizeof(directions)/sizeof(directions[0]) ); i++) { if (deg >= directions[i].low && deg < directions[i].high) { return langcode(directions[i].lang); } } return "?"; } // Calculate new position based on distance and angle. // // Input: lat/long in Xastir coordinate system (100ths of seconds) // distance in nautical miles // angle in true // // Outputs: *x_long, *y_lat in Xastir coordinate system (100ths of // seconds) // // // From http://home.t-online.de/home/h.umland/Chapter12.pdf // // Dead-reckoning using distance in km, course C: // Lat_B = Lat_A + ( (360/40031.6) * distance * cos C ) // // Dead-reckoning using distance in nm, course C: // Lat_B = Lat_A + ( (distance/60) * cos C ) // // Average of two latitudes (required for next two equations) // Lat_M = (Lat_A + Lat_B) / 2 // // Dead-reckoning using distance in km, course C: // Lon_B = Lon_A + ( (360/40031.6) * distance * (sin C / cos // Lat_M) ) // // Dead-reckoning using distance in nm, course C: // Lon_B = Lon_A + ( (distance/60) * (sin C / cos Lat_M) ) // // If resulting longitude exceeds +/- 180, subtract/add 360. // void compute_DR_position(long x_long, // input long y_lat, // input double range, // input in nautical miles double course, // input in true long *x_long2, // output long *y_lat2) // output { double bearing_radians, lat_M_radians; float lat_A, lat_B, lon_A, lon_B, lat_M; int ret; unsigned long x_u_long, y_u_lat; //fprintf(stderr,"Distance:%fnm, Course:%f, Time:%d\n", // range, // course, // (int)(sec_now() - p_station->sec_heard)); // Bearing in radians bearing_radians = (double)((course/360.0) * 2.0 * M_PI); // Convert lat/long to floats ret = convert_from_xastir_coordinates( &lon_A, &lat_A, x_long, y_lat); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long2 = x_long; *y_lat2 = y_lat; return; } // Compute new latitude lat_B = (float)((double)(lat_A) + (range/60.0) * cos(bearing_radians)); // Compute mid-range latitude lat_M = (lat_A + lat_B) / 2.0; // Convert lat_M to radians lat_M_radians = (double)((lat_M/360.0) * 2.0 * M_PI); // Compute new longitude lon_B = (float)((double)(lon_A) + (range/60.0) * ( sin(bearing_radians) / cos(lat_M_radians)) ); // Test for out-of-bounds longitude, correct if so. if (lon_B < -360.0) { lon_B = lon_B + 360.0; } if (lon_B > 360.0) { lon_B = lon_B - 360.0; } //fprintf(stderr,"Lat:%f, Lon:%f\n", lat_B, lon_B); ret = convert_to_xastir_coordinates(&x_u_long, &y_u_lat, lon_B, lat_B); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long2 = x_long; *y_lat2 = y_lat; return; } // Convert from unsigned long to long *x_long2 = (long)x_u_long; *y_lat2 = (long)y_u_lat; } // Calculate new position based on speed/course/modified-time. // We'll call it from Create_object_item_tx_string() and from the // modify object/item routines to calculate a new position and stuff // it into the record along with the modification time before we // start off in a new direction. // // Input: *p_station // // Outputs: *x_long, *y_lat in Xastir coordinate system (100ths of // seconds) // // // From http://home.t-online.de/home/h.umland/Chapter12.pdf // // Dead-reckoning using distance in km, course C: // Lat_B = Lat_A + ( (360/40031.6) * distance * cos C ) // // Dead-reckoning using distance in nm, course C: // Lat_B = Lat_A + ( (distance/60) * cos C ) // // Average of two latitudes (required for next two equations) // Lat_M = (Lat_A + Lat_B) / 2 // // Dead-reckoning using distance in km, course C: // Lon_B = Lon_A + ( (360/40031.6) * distance * (sin C / cos // Lat_M) ) // // Dead-reckoning using distance in nm, course C: // Lon_B = Lon_A + ( (distance/60) * (sin C / cos Lat_M) ) // // If resulting longitude exceeds +/- 180, subtract/add 360. // // // Possible Problems/Changes: // -------------------------- // *) Change to using last_modified_time for DR. Also tweak the // code so that we don't do incremental DR and use our own // decoded objects to update everything. If we keep the // last_modified_time and the last_modified_position separate // DR'ed objects/items, we can always use those instead of the // other variables if we have a non-zero speed. // // *) Make sure not to corrupt our position of the object when we // receive the packet back via loopback/RF/internet. In // particular the position and the last_modified_time should stay // constant in this case so that dead-reckoning can continue to // move the object consistently, plus we won't compound errors as // we go. // // *) A server Xastir sees empty strings on it's server port when // these objects are transmitted to it. Investigate. It // sometimes does it when speed is 0, but it's not consistent. // // *) Get the last_modified_time embedded into the logfile so that // we don't "lose time" if we shut down for a bit. DR'ed objects // will be at the proper positions when we start back up. // void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat) { int my_course = 0; // In true double range = 0.0; double bearing_radians, lat_M_radians; float lat_A, lat_B, lon_A, lon_B, lat_M; int ret; unsigned long x_u_long, y_u_lat; time_t secs_now; secs_now=sec_now(); // Check whether we have course in the current data // if ( (strlen(p_station->course)>0) && (atof(p_station->course) > 0) ) { my_course = atoi(p_station->course); // In true } // // Else check whether the previous position had a course. Note // that newest_trackpoint if it exists should be the same as the // current data, so we have to go back one further trackpoint. // Make sure in this case that this trackpoint has occurred // within the dead-reckoning timeout period though, else ignore // it. // else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) && (p_station->newest_trackpoint->prev->course != -1) // Undefined && ( (secs_now-p_station->newest_trackpoint->prev->sec) < dead_reckoning_timeout) ) { // In true my_course = p_station->newest_trackpoint->prev->course; } // Get distance in nautical miles from the current data // if ( (strlen(p_station->speed)>0) && (atof(p_station->speed) >= 0) ) { // Speed is in knots (same as nautical miles/hour) range = (double)( (sec_now() - p_station->sec_heard) * ( atof(p_station->speed) / 3600.0 ) ); } // // Else check whether the previous position had speed. Note // that newest_trackpoint if it exists should be the same as the // current data, so we have to go back one further trackpoint. // else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) && (p_station->newest_trackpoint->prev->speed != -1) // Undefined && ( (secs_now-p_station->newest_trackpoint->prev->sec) < dead_reckoning_timeout) ) { // Speed is in units of 0.1km/hour. Different than above! range = (double)( (sec_now() - p_station->sec_heard) * ( p_station->newest_trackpoint->prev->speed / 10 * 0.5399568 / 3600.0 ) ); } //fprintf(stderr,"Distance:%fnm, Course:%d, Time:%d\n", // range, // my_course, // (int)(sec_now() - p_station->sec_heard)); // Bearing in radians bearing_radians = (double)((my_course/360.0) * 2.0 * M_PI); // Convert lat/long to floats ret = convert_from_xastir_coordinates( &lon_A, &lat_A, p_station->coord_lon, p_station->coord_lat); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long = p_station->coord_lon; *y_lat = p_station->coord_lat; return; } // Compute new latitude lat_B = (float)((double)(lat_A) + (range/60.0) * cos(bearing_radians)); // Compute mid-range latitude lat_M = (lat_A + lat_B) / 2.0; // Convert lat_M to radians lat_M_radians = (double)((lat_M/360.0) * 2.0 * M_PI); // Compute new longitude lon_B = (float)((double)(lon_A) + (range/60.0) * ( sin(bearing_radians) / cos(lat_M_radians)) ); // Test for out-of-bounds longitude, correct if so. if (lon_B < -360.0) { lon_B = lon_B + 360.0; } if (lon_B > 360.0) { lon_B = lon_B - 360.0; } //fprintf(stderr,"Lat:%f, Lon:%f\n", lat_B, lon_B); ret = convert_to_xastir_coordinates(&x_u_long, &y_u_lat, lon_B, lat_B); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long = p_station->coord_lon; *y_lat = p_station->coord_lat; return; } // Convert from unsigned long to long *x_long = (long)x_u_long; *y_lat = (long)y_u_lat; } int filethere(char *fn) { FILE *f; int ret; ret =0; f=fopen(fn,"r"); if (f != NULL) { ret=1; (void)fclose(f); } return(ret); } int filecreate(char *fn) { FILE *f; int ret; if (! filethere(fn)) // If no file { ret = 0; fprintf(stderr,"Making user %s file\n", fn); f=fopen(fn,"w+"); // Create it if (f != NULL) { ret=1; // We were successful (void)fclose(f); } return(ret); // Couldn't create file for some reason } return(1); // File already exists } time_t file_time(char *fn) { struct stat file_status; if(stat(fn,&file_status)==0) { return((time_t)file_status.st_ctime); } return(-1); } // Function written by Adam Hahn, AI4QB. Contributed to the public // domain. We've modified it from his initial code so any bugs are // our fault. int copy_file(char *infilename, char *outfilename) { FILE *infile, *outfile; char *buffer; size_t numread = 0; if ((infile = fopen(infilename,"rb")) > (FILE *)0) { if ((outfile = fopen(outfilename,"wb")) > (FILE *)0) { buffer = (char *)malloc(1024); while (!feof(infile)) { numread = fread(buffer, 1, 1024, infile); fwrite(buffer, 1, numread, outfile); } free(buffer); fflush(outfile); fclose(outfile); } else { fprintf(stderr,"Error opening destination file %s for writing", outfilename); fclose(infile); return(1); } fclose(infile); } else { fprintf(stderr,"Error opening source file %s for reading", infilename); return(1); } return 0; } // used by log_data void rotate_file(char *file, int max_keep ) { int i; char file_a[MAX_FILENAME]; char file_b[MAX_FILENAME]; struct stat file_status; if (debug_level & 1) { fprintf(stderr, "Rotating: %s. Will keep %d \n", file, max_keep); } for(i=max_keep; i>=1; i--) { if (debug_level & 1) { fprintf(stderr, "rotate: %s : %s\n", file_b, file_a); } xastir_snprintf(file_a,sizeof(file_a),"%s.%d",file,i); xastir_snprintf(file_b,sizeof(file_b),"%s.%d",file,i-1); unlink (file_a); if (stat(file_a, &file_status) == 0) { // We got good status. That means it didn't get deleted! fprintf(stderr, "Couldn't delete file '%s': %s", file_a,strerror(errno)); return; } // Rename previous to next // // Check whether file_b exists if (stat(file_b, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s\n", file_b); break; } if ( rename (file_b, file_a) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling log_rotate()\n", file_b, file_a); return; } } } if (debug_level & 1) { fprintf(stderr, "rotate: %s : %s\n", file, file_a); } if ( rename (file, file_a) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling log_rotate()\n", file, file_a); } return; } char *fetch_file_line(FILE *f, char *line) { char cin; int pos; pos = 0; line[0] = '\0'; while (!feof(f)) { // Read one character at a time if (fread(&cin,1,1,f) == 1) { if (pos < MAX_LINE_SIZE) { if (cin != (char)13) // CR { line[pos++] = cin; } } if (cin == (char)10) // Found LF as EOL char { line[pos++] = '\0'; // Always add a terminating zero after last char pos = 0; // start next line return(line); } } } // Must be end of file line[pos] = '\0'; return(line); } // Restore weather alerts so that we have a clear picture of the // current state. Check timestamps on the file. If relatively // current, read the file in. // void load_wx_alerts_from_log_working_sub(time_t time_now, char *filename) { time_t file_timestamp; int file_age; int expire_limit; // In seconds char line[MAX_LINE_SIZE+1]; FILE *f; expire_limit = 60 * 60 * 24 * 15; // 15 days // expire_limit = 60 * 60 * 24 * 1; // 1 day file_timestamp = file_time(filename); if (file_timestamp == -1) { // fprintf(stderr,"File %s doesn't exist\n", filename); return; } file_age = time_now - file_timestamp; if ( file_age > expire_limit) { // fprintf(stderr,"Old file: %s, skipping...\n", filename); return; } // fprintf(stderr,"File is current: %s\n", filename); // Read the file in, as it exists and is relatively new. // Check timestamps before each log line and skip those that are // old. Lines in the file should look about like this: // // # 1157027319 Thu Aug 31 05:28:39 PDT 2006 // OUNSWO>APRS::SKYOUN :OUN Check For Activation VCEAB // # 1157027319 Thu Aug 31 05:28:39 PDT 2006 // LZKFFS>APRS::NWS_ADVIS:311324z,FLOOD,ARC67-147 V1PAA // // We could try to use the regular read_file and read_file_ptr // scheme for reading in the log file, but we'd have to modify // it in two ways: We need to keep from bringing up the // interfaces so we'd need to set a flag when done reading and // then start them, plus we'd need to have it check the // timestamps and skip old ones. Instead we'll do it all on our // own here so that we can control everything ourselves. f = fopen(filename, "r"); if (!f) { fprintf(stderr,"Wx Alert log file could not be opened for reading\n"); return; } while (!feof(f)) // Read until end of file { (void)fetch_file_line(f, line); restart_sync: if (line[0] == '\0') { // Empty line found, skip } else if (line[0] == '#') // Timestamp line, check the date { time_t line_stamp; int line_age; if (strlen(line) < 3) // Line is too short, skip { goto restart_sync; } line_stamp = atoi(&line[2]); line_age = time_now - line_stamp; //fprintf(stderr, "Age: %d\t", line_age); if ( line_age < expire_limit) { // Age is good, read next line and process it (void)fetch_file_line(f, line); if (line[0] != '#') // It's a packet, not a timestamp line { //fprintf(stderr,"%s\n",line); decode_ax25_line(line,'F',-1, 1); // Decode the packet } else { goto restart_sync; } } } } if (feof(f)) // Close file if at the end { (void)fclose(f); } } // Restore weather alerts so that we have a clear picture of the // current state. Do this before we start the interfaces. Only // reload if the log files datestamps are relatively current. // // Check timestamps on each file in turn. If relatively // current, read them in the correct order: // wx_alert.log.3 // wx_alert.log.2 // wx_alert.log.1 // wx.alert.log // void load_wx_alerts_from_log(void) { time_t time_now; char filename[MAX_FILENAME]; char logfile_path[MAX_VALUE]; get_user_base_dir(LOGFILE_WX_ALERT,logfile_path, sizeof(logfile_path)); time_now = sec_now(); fprintf(stderr,"*** Reading WX Alert log files\n"); // wx_alert.log.3 xastir_snprintf(filename, sizeof(filename), "%s.3", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log.2 xastir_snprintf(filename, sizeof(filename), "%s.2", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log.1 xastir_snprintf(filename, sizeof(filename), "%s.1", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log xastir_snprintf(filename, sizeof(filename), "%s", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); fill_in_new_alert_entries(); fprintf(stderr,"*** Done with WX Alert log files\n"); } // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void log_data(char *file, char *line) { FILE *f; struct stat file_status; int reset_setuid = 0 ; // Check for "# Tickle" first, don't log it if found. // It's an idle string designed to keep the socket active. if ( (strncasecmp(line, "#Tickle", 7)==0) || (strncasecmp(line, "# Tickle", 8) == 0) ) { return; } else { char temp[200]; char timestring[100+1]; struct tm *time_now; time_t secs_now; // Fetch the current date/time string // get_timestamp(timestring); secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%a %b %d %H:%M:%S %Z %Y",time_now); xastir_snprintf(temp, sizeof(temp), "# %ld %s", (unsigned long)secs_now, timestring); // Change back to the base directory // This call corrupts the "file" variable. Commented it out as we // don't appear to need it anyway. The complete root-anchored // path/filename are passed to us in the "file" parameter. // // chdir(get_user_base_dir("")); // check size and rotate if too big if (stat(file, &file_status)==0) { // if (debug_level & 1) { // fprintf(stderr, "log_data(): logfile size: %ld \n",(long) file_status.st_size); // } if ((file_status.st_size + strlen(temp) + strlen(line) )> MAX_LOGFILE_SIZE) { if (debug_level & 1) { fprintf(stderr, "log_data(): calling rotate_file()\n"); } rotate_file(file,3); } } else { // ENOENT is ok -- we make the file below if (errno != ENOENT ) { fprintf(stderr,"Couldn't stat log file '%s': %s\n", file,strerror(errno)); return; } } if (getuid() != geteuid()) { reset_setuid=1; DISABLE_SETUID_PRIVILEGE; } f=fopen(file,"a"); if (f!=NULL) { fprintf(f,"%s\n", temp); // Write the timestamp line fprintf(f,"%s\n",line); // Write the data line (void)fclose(f); } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } if(reset_setuid) { ENABLE_SETUID_PRIVILEGE; } } } // // Tactical callsign logging // // Logging function called from the Assign Tactical Call right-click // menu option and also from db.c:fill_in_tactical_call. Each // tactical assignment is logged as one line. // // We need to check for identical callsigns in the file, deleting // lines that have the same name and adding new records to the end. // Actually BAD IDEA! We want to keep the history of the tactical // calls so that we can trace the changes later. // // Best method: Look for lines containing matching callsigns and // comment them out, adding the new tactical callsign at the end of // the file. // // Do we need to use a special marker to mean NO tactical callsign // is assigned? This is for when we had a tactical call but now // we're removing it. The reload_tactical_calls() routine below // would need to match. Since we're using comma-delimited files, we // can just check for an empty string instead. // void log_tactical_call(char *call_sign, char *tactical_call_sign) { char file[MAX_VALUE]; FILE *f; // Add it to our in-memory hash so that if stations expire and // then appear again they get assigned the same tac-call. add_tactical_to_hash(call_sign, tactical_call_sign); get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"a"); if (f!=NULL) { if (tactical_call_sign == NULL) { fprintf(f,"%s,\n",call_sign); } else { fprintf(f,"%s,%s\n",call_sign,tactical_call_sign); } (void)fclose(f); if (debug_level & 1) { fprintf(stderr, "Saving tactical call to file: %s:%s", call_sign, tactical_call_sign); } } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } } // // Function to load saved tactical calls back into xastir. This // is called on startup. This implements persistent tactical calls // across xastir restarts. // // Here we create a hash lookup and store one record for each valid // line read from the tactical calls log file. The key for each // hash entry is the callsign-SSID. Here we simply read them in and // create the hash. When a new station is heard on the air, it is // checked against this hash and the tactical call field filled in // if there is a match. // // Note that the length of "line" can be up to max_device_buffer, // which is currently set to 4096. // void reload_tactical_calls(void) { char file[MAX_VALUE]; FILE *f; char line[300+1]; get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"r"); if (f!=NULL) { while (fgets(line, 300, f) != NULL) { if (debug_level & 1) { fprintf(stderr,"loading tactical calls from file: %s",line); } if (line[0] != '#') // skip comment lines { char *ptr; // we're dealing with comma-separated files, so // break the two pieces at the comma. ptr = index(line,','); if (ptr != NULL) { char *ptr2; ptr[0] = '\0'; // terminate the callsign ptr++; // point to the tactical callsign // check for lf ptr2 = index(ptr,'\n'); if (ptr2 != NULL) { ptr2[0] = '\0'; } // check for cr ptr2 = index(ptr,'\r'); if (ptr2 != NULL) { ptr2[0] = '\0'; } if (debug_level & 1) { fprintf(stderr, "Call=%s,\tTactical=%s\n", line, ptr); } // call tac-call add_tactical_to_hash(line, ptr); } } } (void)fclose(f); } else { if (debug_level & 1) { fprintf(stderr,"couldn't open file for reading: %s\n", file); } } /* if (tactical_hash) { fprintf(stderr,"Stations w/tactical calls defined: %d\n", hashtable_count(tactical_hash)); } */ } // Returns time in seconds since the Unix epoch. // time_t sec_now(void) { time_t timenw; time_t ret; ret = time(&timenw); return(ret); } char *get_time(char *time_here) { struct tm *time_now; time_t timenw; (void)time(&timenw); time_now = localtime(&timenw); (void)strftime(time_here,MAX_TIME,"%m%d%Y%H%M%S",time_now); return(time_here); } /////////////////////////////////// Utilities //////////////////////////////////////////////////// /* * Check for valid path and change it to TAPR format * Add missing asterisk for stations that we must have heard via a digi * Extract port for KAM TNCs * Handle igate injection ID formats: "callsign-ssid,I" & "callsign-0ssid" * * TAPR-2 Format: * KC2ELS-1*>SX0PWT,RELAY,WIDE:`2`$l##>/>"4)} * * AEA Format: * KC2ELS-1*>RELAY>WIDE>SX0PWT:`2`$l##>/>"4)} */ int valid_path(char *path) { int i,len,hops,j; int type,ast,allast,ins; char ch; len = (int)strlen(path); type = 0; // 0: unknown, 1: AEA '>', 2: TAPR2 ',', 3: mixed hops = 1; ast = 0; allast = 0; // There are some multi-port TNCs that deliver the port at the end // of the path. For now we discard this information. If there is // multi-port TNC support some day, we should write the port into // our database. // KAM: /V /H // KPC-9612: /0 /1 /2 if (len > 2 && path[len-2] == '/') { ch = path[len-1]; if (ch == 'V' || ch == 'H' || ch == '0' || ch == '1' || ch == '2') { path[len-2] = '\0'; len = (int)strlen(path); } } // One way of adding igate injection ID is to add "callsign-ssid,I". // We need to remove the ",I" portion so it doesn't count as another // digi here. This should be at the end of the path. if (len > 2 && path[len-2] == ',' && path[len-1] == 'I') // Found ",I" { //fprintf(stderr,"%s\n",path); //fprintf(stderr,"Found ',I'\n"); path[len-2] = '\0'; len = (int)strlen(path); //fprintf(stderr,"%s\n\n",path); } // Now look for the same thing but with a '*' character at the end. // This should be at the end of the path. if (len > 3 && path[len-3] == ',' && path[len-2] == 'I' && path[len-1] == '*') // Found ",I*" { //fprintf(stderr,"%s\n",path); //fprintf(stderr,"Found ',I*'\n"); path[len-3] = '\0'; len = (int)strlen(path); //fprintf(stderr,"%s\n\n",path); } // Another method of adding igate injection ID is to add a '0' in front of // the SSID. For WE7U it would change to WE7U-00, for WE7U-15 it would // change to WE7U-015. Take out this zero so the rest of the decoding will // work. This should be at the end of the path. // Also look for the same thing but with a '*' character at the end. if (len > 6) { for (i=len-1; i>len-6; i--) { if (path[i] == '-' && path[i+1] == '0') { //fprintf(stderr,"%s\n",path); for (j=i+1; j' || ch == ',') // found digi call separator { // We're at the start of a callsign entry in the path if (ast > 1 || (ast == 1 && i-j > 10) || (ast == 0 && (i == j || i-j > 9))) { if (debug_level & 1) { fprintf(stderr, "valid_path(): Bad Path: More than one * in call or wrong call size\n"); } return(0); // more than one asterisk in call or wrong call size } ast = 0; // reset local asterisk counter j = i+1; // set to start of next call if (ch == ',') { type |= 0x02; // set TAPR2 flag } else { type |= 0x01; // set AEA flag (found '>') } hops++; // count hops } else // digi call character or asterisk { // We're in the middle of a callsign entry if (ch == '*') { ast++; // count asterisks in call allast++; // count asterisks in path } else if ((ch <'A' || ch > 'Z') // Not A-Z && (ch <'a' || ch > 'z') // Not a-z && (ch <'0' || ch > '9') // Not 0-9 && ch != '-') { // Note that Q-construct and internet callsigns can // have a-z in them, AX.25 callsigns cannot unless // they are in a 3rd-party packet. if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: Anti-loop stuff from aprsd or lower-case chars found\n"); } return(0); // wrong character in path } } } if (ast > 1 || (ast == 1 && i-j > 10) || (ast == 0 && (i == j || i-j > 9))) { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: More than one * or wrong call size (2)\n"); } return(0); // more than one asterisk or wrong call size } if (type == 0x03) { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: Wrong format, both > and , in path\n"); } return(0); // wrong format, both '>' and ',' in path } if (hops > 9) // [APRS Reference chapter 3] { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: hops > 9\n"); } return(0); // too much hops, destination + 0-8 digipeater addresses } if (type == 0x01) { int delimiters[20]; int k = 0; char dest[15]; char rest[100]; for (i=0; i') { path[i] = ','; // Exchange separator character delimiters[k++] = i; // Save the delimiter indexes } } // We also need to move the destination callsign to the end. // AEA has them in a different order than TAPR-2 format. // We'll move the destination address between delimiters[0] // and [1] to the end of the string. //fprintf(stderr,"Orig. Path:%s\n",path); // Save the destination xastir_snprintf(dest,sizeof(dest),"%s",&path[delimiters[--k]+1]); dest[strlen(path) - delimiters[k] - 1] = '\0'; // Terminate it dest[14] = '\0'; // Just to make sure path[delimiters[k]] = '\0'; // Delete it from the original path //fprintf(stderr,"Destination: %s\n",dest); // TAPR-2 Format: // KC2ELS-1*>SX0PWT,RELAY,WIDE:`2`$l##>/>"4)} // // AEA Format: // KC2ELS-1*>RELAY>WIDE>SX0PWT:`2`$l##>/>"4)} // 9 15 20 // We now need to insert the destination into the middle of // the string. Save part of it in another variable first. xastir_snprintf(rest, sizeof(rest), "%s", path); //fprintf(stderr,"Rest:%s\n",rest); xastir_snprintf(path,len+1,"%s,%s",dest,rest); //fprintf(stderr,"New Path:%s\n",path); } if (allast < 1) // try to insert a missing asterisk { ins = 0; hops = 0; for (i=0; i 0 && (j - i) == 5) // WIDE3 { if ( path[ i ] == 'W' && path[i+1] == 'I' && path[i+2] == 'D' && path[i+3] == 'E' && path[i+4] >= '0' && path[i+4] <= '9') { ins = j; } } /* Don't do this! It can mess up relay/wide1-1 digipeating by adding an asterisk later in the path than the first unused digi. if (hops > 0 && (j - i) == 7) { // WIDE3-2 if ( path[ i ] == 'W' && path[i+1] == 'I' && path[i+2] == 'D' && path[i+3] == 'E' && path[i+4] >= '0' && path[i+4] <= '9' && path[i+5] == '-' && path[i+6] >= '0' && path[i+6] <= '9' && (path[i+4] != path[i+6]) ) { ins = j; } } */ if (hops > 0 && (j - i) == 6) // TRACE3 { if ( path[ i ] == 'T' && path[i+1] == 'R' && path[i+2] == 'A' && path[i+3] == 'C' && path[i+4] == 'E' && path[i+5] >= '0' && path[i+5] <= '9') { if (hops == 1) { ins = j; } else { ins = i-1; } } } /* Don't do this! It can mess up relay/wide1-1 digipeating by adding an asterisk later in the path than the first unused digi. if (hops > 0 && (j - i) == 8) { // TRACE3-2 if ( path[ i ] == 'T' && path[i+1] == 'R' && path[i+2] == 'A' && path[i+3] == 'C' && path[i+4] == 'E' && path[i+5] >= '0' && path[i+5] <= '9' && path[i+6] == '-' && path[i+7] >= '0' && path[i+7] <= '9' && (path[i+5] != path[i+7]) ) { if (hops == 1) ins = j; else ins = i-1; } } */ hops++; i = j; // skip to start of next call } if (ins > 0) { for (i=len; i>=ins; i--) { path[i+1] = path[i]; // generate space for '*' // we work on a separate path copy which is long enough to do it } path[ins] = '*'; // and insert it } } return(1); // Path is good } /* * Check for a valid AX.25 call * Valid calls consist of up to 6 uppercase alphanumeric characters * plus optional SSID (four-bit integer) [APRS Reference, AX.25 Reference] * * We originally required at least one number so-as to get rid of calls like * "NOCALL", but got rid of that code. */ int valid_call(char *call) { int len, ok; int i, del, has_chr; char c; has_chr = 0; ok = 1; len = (int)strlen(call); if (len == 0) { return(0); // wrong size } while (call[0]=='c' && call[1]=='m' && call[2]=='d' && call[3]==':') { // Erase TNC prompts from beginning of callsign. This may // not be the right place to do this, but it came in handy // here, so that's where I put it. -- KB6MER if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call); makePrintable(filtered_data); fprintf(stderr,"valid_call: Command Prompt removed from: %s", filtered_data); } for(i=0; call[i+4]; i++) { call[i]=call[i+4]; } call[i++]=0; call[i++]=0; call[i++]=0; call[i++]=0; len=strlen(call); if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call); makePrintable(filtered_data); fprintf(stderr," result: %s", filtered_data); } } if (len > 9) { return(0); // Too long for valid call (6-2 max e.g. KB6MER-12) } del = 0; for (i=len-2; ok && i>0 && i>=len-3; i--) // search for optional SSID { if (call[i] =='-') { del = i; // found the delimiter } } if (del) // we have a SSID, so check it { if (len-del == 2) // 2 char SSID { if (call[del+1] < '1' || call[del+1] > '9') // -1 ... -9 { del = 0; } } else // 3 char SSID { if (call[del+1] != '1' || call[del+2] < '0' || call[del+2] > '5') // -10 ... -15 { del = 0; } } } if (del) { len = del; // length of base call } for (i=0; ok && i= 'A' && c <= 'Z') { has_chr = 1; // we need at least one char } else if (c >= '0' && c <= '9') { // We originally required at least one number } else { ok = 0; // wrong character in call } } // if (!has_num || !has_chr) // with this we also discard NOCALL etc. if (!has_chr) { ok = 0; } ok = (ok && strcmp(call,"NOCALL") != 0); // check for errors ok = (ok && strcmp(call,"ERROR!") != 0); ok = (ok && strcmp(call,"WIDE") != 0); ok = (ok && strcmp(call,"RELAY") != 0); ok = (ok && strcmp(call,"MAIL") != 0); return(ok); } /* * Check for a valid internet name. * Accept darned-near anything here as long as it is the proper * length and printable. */ int valid_inet_name(char *name, char *info, char *origin, int origin_size) { int len, i, ok, oknws, okbom; char *ptr; len = (int)strlen(name); if (len > 9 || len == 0) // max 9 printable ASCII characters { return(0); // wrong size } for (i=0; i= 5 && strncmp(name,"aprsd",5) == 0) { xastir_snprintf(origin, origin_size, "INET"); origin[4] = '\0'; // Terminate it return(1); // aprsdXXXX is ok } // Modifies "origin" if a match found if (len == 6) // check for NWS or BOM { ok = 1; oknws = 0; okbom = 0; for (i=0; i<6; i++) if (name[i] <'A' || name[i] > 'Z') // 6 uppercase characters { ok = 0; } ok = ok && (info != NULL); // check if we can test info if (ok) { ptr = strstr(info,":NWS-"); // "NWS-" in info field (non-compressed alert) oknws = (ptr != NULL); if (!oknws) { ptr = strstr(info,":NWS_"); // "NWS_" in info field (compressed alert) oknws = (ptr != NULL); } // If we've got here, it's not an NWS message, let's see if its a BOM message if (!oknws) { ptr = strstr(info,":BOM-"); // "BOM-" in info field (compressed alert) okbom = (ptr != NULL); } if (!okbom) { ptr = strstr(info,":BOM_"); // "BOM_" in info field (compressed alert) okbom = (ptr != NULL); } } // Depending on whether we had an NWS or BOM message, se the origin appropriately if (oknws) { xastir_snprintf(origin, origin_size, "INET-NWS"); origin[8] = '\0'; return(1); // weather alerts } if (okbom) { xastir_snprintf(origin, origin_size, "INET-BOM"); origin[8] = '\0'; return(1); // weather alerts } } return(1); // Accept anything else if we get to this point in // the code. After all, the message came from the // internet, not from RF. } /* * Keep track of last six digis that echo my transmission */ void upd_echo(char *path) { int i,j,len; if (echo_digis[5][0] != '\0') { for (i=0; i<5; i++) { xastir_snprintf(echo_digis[i], MAX_CALLSIGN+1, "%s", echo_digis[i+1]); } echo_digis[5][0] = '\0'; } for (i=0,j=0; i < (int)strlen(path); i++) { if (path[i] == '*') { break; } if (path[i] == ',') { j=i; } } if (j > 0) { j++; // first char of call } if (i > 0 && i-j <= 9) { len = i-j; for (i=0; i<5; i++) // look for free entry { if (echo_digis[i][0] == '\0') { break; } } substr(echo_digis[i],path+j,len); } } // dl9sau: // I liked to have xastir to compute the locator along with the normal coordinates. // The algorithm derives from dk5sg's util/qth.c (wampes) // // This computes Maidenhead grid coordinates and is used for both // the status line ("text2" widget) and the Coordinate Calculator at // present. // char *sec_to_loc(long longitude, long latitude) { static char buf[7]; char *loc = buf; // database.h: long coord_lon; // Xastir coordinates 1/100 sec, 0 = 180W // database.h: long coord_lat; // Xastir coordinates 1/100 sec, 0 = 90N longitude /= 100L; latitude = 2L * 90L * 3600L - 1L - (latitude / 100L); *loc++ = (char) (longitude / 72000L + 'A'); longitude = longitude % 72000L; *loc++ = (char) (latitude / 36000L + 'A'); latitude = latitude % 36000L; *loc++ = (char) (longitude / 7200L + '0'); longitude = longitude % 7200L; *loc++ = (char) (latitude / 3600L + '0'); latitude = latitude % 3600L; *loc++ = (char) (longitude / 300L + 'a'); *loc++ = (char) (latitude / 150L + 'a'); *loc = 0; // Terminate the string return buf; } /* * Substring function WITH a terminating NULL char, needs a string of at least size+1 */ void substr(char *dest, char *src, int size) { memcpy(dest, src, size+1); dest[size] = '\0'; // Terminate string } char *to_upper(char *data) { int i; for(i=strlen(data)-1; i>=0; i--) if(islower((int)data[i])) { data[i]=toupper((int)data[i]); } return(data); } char *to_lower(char *data) { int i; for(i=strlen(data)-1; i>=0; i--) if(isupper((int)data[i])) { data[i]=tolower((int)data[i]); } return(data); } int is_num_chr(char ch) { return((int)isdigit(ch)); } int is_num_or_sp(char ch) { return((int)((ch >= '0' && ch <= '9') || ch == ' ')); } int is_xnum_or_dash(char *data, int max) { int i; int ok; ok=1; for(i=0; i=0; i--) if(!isdigit((int)data[i])) { ok=0; break; } return(ok); } //-------------------------------------------------------------------- //Removes all control codes ( < 1Ch ) from a string and set the 8th bit to zero void removeCtrlCodes(char *cp) { int i,j; int len = (int)strlen(cp); unsigned char *ucp = (unsigned char *)cp; for (i=0, j=0; i<=len; i++) { ucp[i] &= 0x7f; // Clear 8th bit if ( (ucp[i] >= (unsigned char)0x1c) // Check for printable plus the Mic-E codes || ((char)ucp[i] == '\0') ) // or terminating 0 { ucp[j++] = ucp[i] ; // Copy to temp if printable } } } //-------------------------------------------------------------------- //Removes all control codes ( <0x20 or >0x7e ) from a string, including // CR's, LF's, tab's, etc. // void makePrintable(char *cp) { int i,j; int len = (int)strlen(cp); unsigned char *ucp = (unsigned char *)cp; for (i=0, j=0; i<=len; i++) { ucp[i] &= 0x7f; // Clear 8th bit if ( ((ucp[i] >= (unsigned char)0x20) && (ucp[i] <= (unsigned char)0x7e)) || ((char)ucp[i] == '\0') ) // Check for printable or terminating 0 { ucp[j++] = ucp[i] ; // Copy to (possibly) new location if printable } } } //---------------------------------------------------------------------- // Implements safer mutex locking. Posix-compatible mutex's will lock // up a thread if lock's/unlock's aren't in perfect pairs. They also // allow one thread to unlock a mutex that was locked by a different // thread. // Remember to keep this thread-safe. Need dynamic storage (no statics) // and thread-safe calls. // // In order to keep track of process ID's in a portable way, we probably // can't use the process ID stored inside the pthread_mutex_t struct. // There's no easy way to get at it. For that reason we'll create // another struct that contains both the process ID and a pointer to // the pthread_mutex_t, and pass pointers to those structs around in // our programs instead. The new struct is "xastir_mutex". // // Function to initialize the new xastir_mutex // objects before use. // void init_critical_section(xastir_mutex *lock) { #ifdef MUTEX_DEBUG pthread_mutexattr_t attr; // Note that this stuff is not POSIX, so is considered non-portable. // Exists in Linux Threads implementation only? # ifdef __LSB__ // LSB VERSION (Linux Standard Base) // Note that we _must_ use the newer pthread function in this // case per LSB specs. (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); # else // __LSB__ // NON_LSB VERSION // Check first for newer pthread function # ifdef HAVE_PTHREAD_MUTEXATTR_SETTYPE (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # else // Use older, deprecated pthread function (void)pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # endif // HAVE_PTHREAD_MUTEXATTR_SETTYPE # endif // __LSB__ (void)pthread_mutexattr_init(&attr); (void)pthread_mutex_init(&lock->lock, &attr); #else // MUTEX_DEBUG (void)pthread_mutex_init(&lock->lock, NULL); // Set to default POSIX-compatible type #endif // MUTEX_DEBUG lock->threadID = 0; // No thread has locked it yet } // Function which uses xastir_mutex objects to lock a // critical shared section of code or variables. Makes // sure that only one thread can access the critical section // at a time. If there are no problems, it returns zero. // int begin_critical_section(xastir_mutex *lock, char *text) { pthread_t calling_thread; int problems; #ifdef MUTEX_DEBUG int ret; #endif // MUTEX_DEBUG problems = 0; // Note that /usr/include/bits/pthreadtypes.h has the // definition for pthread_mutex_t, and it includes the // owner thread number: _pthread_descr pthread_mutex_t.__m_owner // It's probably not portable to use it though. // Get thread number we're currently running under calling_thread = pthread_self(); if (pthread_equal( lock->threadID, calling_thread )) { // We tried to lock something that we already have the lock on. fprintf(stderr,"%s:Warning:This thread already has the lock on this resource\n", text); problems++; return(0); // Return the OK code. Skip trying the lock. } //if (lock->threadID != 0) //{ // We tried to lock something that another thread has the lock on. // This is normal operation. The pthread_mutex_lock call below // will put our process to sleep until the mutex is unlocked. //} // Try to lock it. #ifdef MUTEX_DEBUG // Instead of blocking the thread, we'll loop here until there's // no deadlock, printing out status as we go. do { ret = pthread_mutex_lock(&lock->lock); if (ret == EDEADLK) // Normal operation. At least two threads want this lock. { fprintf(stderr,"%s:pthread_mutex_lock(&lock->lock) == EDEADLK\n", text); sched_yield(); // Yield the cpu to another thread } else if (ret == EINVAL) { fprintf(stderr,"%s:pthread_mutex_lock(&lock->lock) == EINVAL\n", text); fprintf(stderr,"Forgot to initialize the mutex object...\n"); problems++; sched_yield(); // Yield the cpu to another thread } } while (ret == EDEADLK); if (problems) { fprintf(stderr,"Returning %d to calling thread\n", problems); } #else // MUTEX_DEBUG pthread_mutex_lock(&lock->lock); #endif // MUTEX_DEBUG // Note: This can only be set AFTER we already have the mutex lock. // Otherwise there may be contention with other threads for setting // this variable. // lock->threadID = calling_thread; // Save the threadID that we used // to lock this resource return(problems); } // Function which ends the locking of a critical section // of code. If there are no problems, it returns zero. // int end_critical_section(xastir_mutex *lock, char *text) { pthread_t calling_thread; int problems; #ifdef MUTEX_DEBUG int ret; #endif // MUTEX_DEBUG problems = 0; // Get thread number we're currently running under calling_thread = pthread_self(); if (lock->threadID == 0) { // We have a problem. This resource hasn't been locked. fprintf(stderr,"%s:Warning:Trying to unlock a resource that hasn't been locked:%ld\n", text, (long int)lock->threadID); problems++; } if (! pthread_equal( lock->threadID, calling_thread )) { // We have a problem. We just tried to unlock a mutex which // a different thread originally locked. Not good. fprintf(stderr,"%s:Trying to unlock a resource that a different thread locked originally: %ld:%ld\n", text, (long int)lock->threadID, (long int)calling_thread); problems++; } // We need to clear this variable BEFORE we unlock the mutex, 'cuz // other threads might be waiting to lock the mutex. // lock->threadID = 0; // We're done with this lock. // Try to unlock it. Compare the thread identifier we used before to make // sure we should. #ifdef MUTEX_DEBUG // EPERM error: We're trying to unlock something that we don't have a lock on. ret = pthread_mutex_unlock(&lock->lock); if (ret == EPERM) { fprintf(stderr,"%s:pthread_mutex_unlock(&lock->lock) == EPERM\n", text); problems++; } else if (ret == EINVAL) { fprintf(stderr,"%s:pthread_mutex_unlock(&lock->lock) == EINVAL\n", text); fprintf(stderr,"Someone forgot to initialize the mutex object\n"); problems++; } if (problems) { fprintf(stderr,"Returning %d to calling thread\n", problems); } #else // MUTEX_DEBUG (void)pthread_mutex_unlock(&lock->lock); #endif // MUTEX_DEBUG return(problems); } #ifdef TIMING_DEBUG void time_mark(int start) { static struct timeval t_start; struct timeval t_cur; long sec, usec; if (start) { gettimeofday(&t_start, NULL); fprintf(stderr,"\nstart: 0.000000s"); } else { gettimeofday(&t_cur, NULL); sec = t_cur.tv_sec - t_start.tv_sec; usec = t_cur.tv_usec - t_start.tv_usec; if (usec < 0) { sec--; usec += 1000000; } fprintf(stderr,"time: %ld.%06lds\n", sec, usec); } } #endif // TIMING_DEBUG // Function which adds commas to callsigns (and other abbreviations?) // in order to make the text sound better when run through a Text-to- // Speech system. We try to change only normal amateur callsigns. // If we find a number in the text before a dash is found, we // consider it to be a normal callsign. We don't add commas to the // SSID portion of a call. void spell_it_out(char *text, int max_length) { char buffer[2000]; int i = 0; int j = 0; int number_found_before_dash = 0; int dash_found = 0; while (text[i] != '\0') { if (text[i] == '-') { dash_found++; } if (is_num_chr(text[i]) && !dash_found) { number_found_before_dash++; } buffer[j++] = text[i]; if (!dash_found) // Don't add commas to SSID { buffer[j++] = ','; } i++; } buffer[j] = '\0'; // Only use the new string if it kind'a looks like a callsign if (number_found_before_dash) { xastir_snprintf(text, max_length, "%s", buffer); } } #define kKey 0x73e2 // This is the seed for the key static short doHash(char *theCall) { char rootCall[10]; // need to copy call to remove ssid from parse char *p1 = rootCall; short hash; short i,len; char *ptr = rootCall; while ((*theCall != '-') && (*theCall != '\0')) { *p1++ = toupper((int)(*theCall++)); } *p1 = '\0'; hash = kKey; // Initialize with the key value i = 0; len = (short)strlen(rootCall); while (i MAX_WIDES) { // N is greater than MAX_WIDES bad_path = 1; } else if (prev > MAX_WIDES) { // n is greater than MAX_WIDES bad_path = 1; } else if (last == 0) { // N is 0, it's a used-up digipeater slot bad_path = 1; } if (debug_level & 1 && bad_path) { fprintf(stderr,"n-N wrong\n"); } return(bad_path); } // This function checks to make sure an unproto path falls within // the socially acceptable values, such as only one RELAY or // WIDE1-1 which may appear only as the first option, use of WIDE4-4 // and higher should be questioned, etc. // // "MAX_WIDES" is defined in util.h // // Returns: // 1 = bad path // 0 = good path // int check_unproto_path ( char *data ) { char *tmpdata; char *tmp; char *ViaCalls[10]; int bad_path, ii, have_relay, have_wide, have_widen; int have_trace, have_tracen; int lastp = 0; int prevp = 0; int last = 0; int prev = 0; int total_digi_length = 0; if (debug_level & 1) { fprintf(stderr, "Input string: %s\n", data); } bad_path = ii = have_relay = have_wide = 0; have_widen = have_trace = have_tracen = 0; // Remember to free() tmpdata before we return #ifdef HAVE_STRNDUP tmpdata = (char *)strndup(data, strlen(data)); #else tmpdata = (char *)strdup(data); #endif (void)to_upper(tmpdata); if ((tmp = strchr(tmpdata, '/'))) { *tmp ='\0'; // Only check VHF portion of path } split_string(tmpdata, ViaCalls, 10, ','); for (ii = 0; ii < 10; ii++) { lastp = 0; prevp = 0; last = 0; prev = 0; // Check for empty string in this slot if (ViaCalls[ii] == NULL) { // We're done. Exit the loop with whatever flags were // set in previous iterations. if (debug_level & 1) { fprintf(stderr,"NULL string, slot %d\n", ii); } break; } else { if (debug_level & 1) { fprintf(stderr,"%s string, slot %d\n", ViaCalls[ii], ii); } } lastp = strlen(ViaCalls[ii]) - 1; prevp = lastp - 2; // Snag the N character, convert to integer last = ViaCalls[ii][lastp] - 0x30; if (prevp >= 0) { // Snag the n character, convert to integer prev = ViaCalls[ii][prevp] - 0x30; } // Check whether RELAY appears later in the path if (!strncmp(ViaCalls[ii], "RELAY", 5)) { have_relay++; total_digi_length++; if (ii != 0) { // RELAY should not appear after the first item in a // path! bad_path = 1; if (debug_level & 1) { fprintf(stderr,"RELAY appears later in the path\n"); } break; } } // Check whether WIDE1-1 appears later in the path (the new // "RELAY") else if (!strncmp(ViaCalls[ii], "WIDE1-1", 7)) { have_relay++; total_digi_length++; if (ii != 0) { // WIDE1-1 should not appear after the first item in // a path! bad_path = 1; if (debug_level & 1) { fprintf(stderr,"WIDE1-1 appears later in the path\n"); } break; } } // Check whether WIDE2-1 appears first in the path. This is // fine, but don't trigger an error later because of another // WIDEn-N after an initial WIDE2-1. This is to allow paths // like "WIDE2-1,WIDE-2-2" or "WIDE2-1,MD2-2" else if ( (ii == 0) && (!strncmp(ViaCalls[ii], "WIDE2-1", 7)) ) { total_digi_length++; if (debug_level & 1) { fprintf(stderr,"Found initial WIDE2-1 (a good thing)\n"); } } // Check for WIDE/TRACE/WIDEn-N/TRACEn-N in the path else if (strstr(ViaCalls[ii], "WIDE") || strstr(ViaCalls[ii], "TRACE")) { // This is some variant of WIDE or TRACE, could be // WIDE/WIDEn-N/TRACE/TRACEn-N int is_wide = 0; if (strstr(ViaCalls[ii], "WIDE")) { is_wide++; } // Check for WIDEn-N or TRACEn-N if (strstr(ViaCalls[ii], "-")) { // This is a WIDEn-N or TRACEn-N callsign // Here we are adding the unused portion of the // WIDEn-N/TRACEn-N to the total_digi_length // variable. We use the unused portion because that // way we're not fooled if people start with a // number for N that is higher/lower than n. The // initial thought was to grab the higher of n or N, // but those lines are commented out here. // //if (last > prev) total_digi_length += last; //else // total_digi_length += prev; // Check for previous WIDEn-N/TRACEn-N if (have_widen || have_tracen) { // Already have a large area via bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Previous WIDEn-N or TRACEn-N\n"); } break; } // Perform WIDEn-N checks if (is_wide) { if (debug_level & 1) { fprintf(stderr,"Found wideN-n at slot %d\n", ii); } if (strcmp(ViaCalls[ii], "WIDE1-1") !=0) // Home station, RELAY replacement { have_widen++; // Note: We mark "have_relay" for } // "WIDE1-1" instead of "have_widen" // We know its a WIDEn-N, time to find out what n is if (strlen(ViaCalls[ii]) != 7) { // This should be WIDEn-N and should be // exactly 7 characters bad_path = 1; if (debug_level & 1) { fprintf(stderr,"String length of widen-N is not 7 characters, slot %d\n", ii); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In WIDEn-N checks, slot %d\n", ii); } break; } } // Perform similar checks for TRACEn-N else { if (debug_level & 1) { fprintf(stderr,"Found traceN-n, slot %d\n", ii); } have_tracen++; // We know its a TRACEn-N time to find out what // n is if (strlen(ViaCalls[ii]) != 8) { // This should be TRACEn-N and should be // exactly 8 characters bad_path = 1; if (debug_level & 1) { fprintf(stderr,"String length of tracen-N is not 8 characters, slot %d\n", ii); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In TRACEn-N checks, slot %d\n", ii); } break; } } } else { // We know we have a WIDE or TRACE in this callsign slot total_digi_length++; if (is_wide) { have_wide++; } else { have_trace++; } if (have_relay && (ii > MAX_WIDES)) { // RELAY and more than "MAX_WIDES" WIDE/TRACE calls // Here we could check have_wide/have_trace to see what the actual // count of WIDE/TRACE calls is at this point... bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Have relay and ii > MAX_WIDES\n"); } break; } else if (!have_relay && ii > (MAX_WIDES - 1)) { // More than WIDE,WIDE,WIDE or TRACE,TRACE,TRACE // Here we could check have_wide/have_trace to see what the actual // count of WIDE/TRACE calls is at this point... bad_path = 1; if (debug_level & 1) { fprintf(stderr,"No relay, but ii > MAX_WIDES-1\n"); } break; } else if (have_widen || have_tracen) { // WIDE/TRACE after something other than RELAY // or WIDE1-1 bad_path = 1; if (debug_level & 1) { fprintf(stderr,"WIDE or TRACE after something other than RELAY or WIDE1-1\n"); } break; } } } // Not RELAY/WIDE/TRACE/WIDEn-N/TRACEn-N call else { // Might as well stub this out, could be anything at // this point, a LINKn-N or LANn-N or a explicit // callsign if (!strstr(ViaCalls[ii], "-")) { /* // We do not have an SSID, treat it as a RELAY if (have_relay) { bad_path = 1; if (debug_level & 1) fprintf(stderr,"No SSID\n"); break; } */ have_relay++; } else { // Could be a LAN or LINK or explicit call, check // for a digit preceding the dash if (prev > 0 && prev <= 9) // Found a digit { // We've found an n-N */ if (have_widen || have_tracen) { // Already have a previous wide path bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Found n-N and previous WIDEn-N or TRACEn-N\n"); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In OTHER checks\n"); } break; } if (debug_level & 1) { fprintf(stderr,"Found wideN-n, slot %d\n", ii); } have_widen++; } else { /* // Must be an explicit callsign, treat as relay if (have_relay) { bad_path = 1; if (debug_level & 1) fprintf(stderr,"\n"); break; } */ have_relay++; } } } } // End of for loop if (debug_level & 1) { fprintf(stderr,"Total digi length: %d\n", total_digi_length); } if (total_digi_length > MAX_WIDES + 1) { if (debug_level & 1) { fprintf(stderr,"Total digi count is too high!\n"); } bad_path = 1; } // Free the memory we allocated with strndup() free(tmpdata); return(bad_path); } // End of check_unproto_path // Set string printed out by segfault handler void set_dangerous( char *ptr ) { xastir_snprintf(dangerous_operation, sizeof(dangerous_operation), "%s", ptr); } // Clear string printed out by segfault handler void clear_dangerous(void) { dangerous_operation[0] = '\0'; } // Write out a WKT file void xastirWriteWKT(char *filename) { // This "WKT" string describes the coordinate system we use in Xastir. // We'll use this string to write out ".prj" files to associate with // shapefiles we create from GPS or APRS tracks. char Xastir_WKT[] = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]"; FILE *f; f=fopen(filename,"w"); // open for write if (f != NULL) { fprintf(f,"%s\n",Xastir_WKT); fclose(f); } else { fprintf(stderr,"Could not open file %s for writing\n",filename); } } // makeMultiline // Create an APRS multiline string given an array of lat/lon pairs. // // Allocates memory that must be freed by the caller. // // lon and lat are arrays. lonObj, latObj are return values of object // location (point from which offsets are computed). // // lineType is 0 for a closed polygon, 1 for a polyline // // colorStyle is a character as defined in the wxsvr.net multiline protocol // web site at wxsvr.net. // // character | color | style // a red solid // b red dashed // c red double-dashed // d yellow solid // e yellow dashed // f yellow double-dashed // g blue solid // h blue dashed // i blue double-dashed // j green solid // k green dashed // l green double-dashed // Returns a null pointer if user requested too many vertices, or if scale // is out of range, or if we fail to malloc the string. // // One could pass only a list of lat/lons here and get back a point at which // to create an object (at the centroid) and a string representing the // multiline. #define minFun(a,b) ( ((a)<(b))?(a):(b)) #define maxFun(a,b) ( ((a)>(b))?(a):(b)) char * makeMultiline(int numPairs, double *lon, double *lat, char colorStyle, int lineType, char* sqnc, double *lonCentr, double *latCentr ) { char * returnString; // the APRS spec requires a max of 43 chars in the comment section of // objects, which leaves room for only so many vertices in a multiline // number allowed= (43-(6-5))/2=16 // 43chars - 6 for the sequence number- 5 for the starting pattern leaves // 32 characters for lat/lon pairs, or 16 pairs if ( numPairs > 16) { returnString = NULL; } else { double minLat, minLon; double maxLat, maxLon; int iPair; double scale1,scale2,scale; // find min/max of arrays minLat=minLon=180; maxLat=maxLon=-180; for ( iPair=0; iPair < numPairs; iPair++) { minLon = minFun(minLon,lon[iPair]); minLat = minFun(minLat,lat[iPair]); maxLon = maxFun(maxLon,lon[iPair]); maxLat = maxFun(maxLat,lat[iPair]); } *lonCentr = (maxLon+minLon)/2; *latCentr = (maxLat+minLat)/2; // Compute scale: // The scale is the value that makes the maximum or minimum offset // map to +44 or -45. Pick the scale factor that keeps the // offsets in that range: if (maxLat > maxLon) { scale1= (maxLat-*latCentr)/44.0; } else { scale1= (maxLon-*lonCentr)/44.0; } if (minLat < minLon) { scale2 = (minLat-*latCentr)/(-45.0); } else { scale2 = (minLon-*lonCentr)/(-45.0); } scale = maxFun(scale1,scale2); if (scale < .0001) { scale=0.0001; } if (scale > 1) { // Out of range, no shape returned returnString = NULL; } else { // Not all systems have a log10(), but they all have log() // So let's stick with natural logs double ln10=log(10.0); // KLUDGE: the multiline spec says we use // 20*(int)(log10(scale/.0001)) to generate the scale char, // but this means we'll often produce real scales that are smaller // than the one we just calculated, which means we'd produce // offsets outside the (-45,44) allowed range. So kludge and // add 1 to the value int lnscalefac=20*log(scale/.0001)/ln10+1; int rsMaxLen=numPairs*2+6+4+1; int stringOffset=0; // Now recompute the scale to be the one we actually transmitted // This pretty much means we'll never have the best precision // we could possibly have, but it'll be close enough scale=pow(10,(double)lnscalefac/20-4); // We're ready to produce the multiline string. So get on with it // multiline string is "}CTS" (literal "}" followed by // line Color-style specifier, followed by open/closed // Type specifier, followed by Scale character), followed // by even number of character pairs, followed by "{seqnc" // (sequence number). returnString=malloc(sizeof(char)*rsMaxLen); if (returnString != NULL) { returnString[stringOffset++]=' '; returnString[stringOffset++]='}'; returnString[stringOffset++]=colorStyle; returnString[stringOffset++]= (lineType == 0)?'0':'1'; returnString[stringOffset++] = lnscalefac+33; for ( iPair=0; iPair #include "hashtable.h" // Max number of WIDE digipeaters allowed #define MAX_WIDES 3 static __inline__ short l16(long val) { // This limits large integer values to the 16 bit range for X // drawing if (val < -32768) { val = -32768; } if (val > 32767) { val = 32767; } return (short)val; } static __inline__ unsigned short lu16(long val) { // This limits large unsigned integer values to the 16 bit range // for X drawing if (val < 0) { val = 0; } if (val > 65535) { val = 65535; } return (unsigned short)val; } extern int convert_from_xastir_coordinates ( float *f_longitude, float *f_latitude, long x, long y ); extern int convert_to_xastir_coordinates (unsigned long* x, unsigned long* y, float f_longitude, float f_latitude); extern char *get_tactical_from_hash(char *callsign); extern void destroy_tactical_hash(void); extern void xastir_debug(int my_debug_level, char *debug_string); extern char *remove_all_spaces(char *data); extern char *remove_leading_spaces(char *data); extern char *remove_trailing_spaces(char *data); extern char *remove_trailing_asterisk(char *data); extern char *remove_trailing_dash_zero(char *data); extern int position_amb_chars; extern void start_timer(void); extern void stop_timer(void); extern void print_timer_results(void); extern void get_timestamp(char *timestring); extern int get_iso_datetime(time_t aTime, char *timestring, int nowIfNotSet, int nowIfInvalid); extern int get_w3cdtf_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid); extern int get_hours(void); extern int get_minutes(void); extern int get_seconds(void); extern char *output_lat(char *in_lat, int comp_pos); extern char *output_long(char *in_long, int comp_pos); extern double phg_range(char p, char h, char g); extern double shg_range(char s, char h, char g); extern void phg_decode(const char *langstr, const char *phg, char *phg_decoded, int phg_decoded_length); extern void shg_decode(const char *langstr, const char *shg, char *shg_decoded, int shg_decoded_length); extern void bearing_decode(const char *langstr, const char *bearing_str, const char *NRQ, char *bearing_decoded, int bearing_decoded_length); extern char *get_line(FILE *f, char *linedata, int maxline); extern time_t time_from_aprsstring(char *timestamp); extern char *compress_posit(const char *lat, const char group, const char *lon, const char symbol, const unsigned int course, const unsigned int speed, const char *phg); extern int position_defined(long lat, long lon, int strict); extern void convert_screen_to_xastir_coordinates(int x, int y, long *lat, long *lon); extern void convert_xastir_to_UTM_str(char *str, int str_len, long x, long y); extern void convert_xastir_to_MGRS_str_components(char *utmZone, int utmZone_len, char *EastingL, int EastingL_len, char *NorthingL, int NorthingL_len, unsigned int *int_utmEasting, unsigned int *int_utmNorthing, long x, long y, int nice_format, char *space_string, int space_string_len); extern void convert_xastir_to_MGRS_str(char *str, int str_len, long x, long y, int nice_format); extern void convert_xastir_to_UTM(double *easting, double *northing, char *zone, int zone_len, long x, long y); extern void convert_UTM_to_xastir(double easting, double northing, char *zone, long *x, long *y); extern double convert_lat_l2r(long lat); extern double convert_lon_l2r(long lon); extern void convert_lat_l2s(long lat, char *str, int str_len, int type); extern void convert_lon_l2s(long lon, char *str, int str_len, int type); extern long convert_lat_s2l(char *lat); extern long convert_lon_s2l(char *lon); extern double calc_distance(long lat1, long lon1, long lat2, long lon2); extern double calc_distance_course(long lat1, long lon1, long lat2, long lon2, char *course_deg, int course_deg_length); extern double distance_from_my_station(char *call_sign, char *course_deg); extern char *convert_bearing_to_name(char *bearing, int opposite); extern void compute_DR_position(long x_long, long y_lat, double range, double course, long *x_long2, long *y_lat2); extern void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat); extern int filethere(char *fn); extern int filecreate(char *fn); extern int copy_file(char *infilename, char *outfilename); extern time_t file_time(char *fn); extern void load_wx_alerts_from_log(void); extern void log_data(char *file, char *line); extern void log_tactical_call(char *call_sign, char *tactical_call_sign); extern void reload_tactical_calls(void); extern time_t sec_now(void); extern char *get_time(char *time_here); extern void substr(char *dest, char *src, int size); extern int valid_path(char *path); extern int valid_call(char *call); extern int valid_inet_name(char *name, char *info, char *origin, int origin_size); extern char echo_digis[6][9+1]; extern void upd_echo(char *path); extern char *to_upper(char *data); extern char *to_lower(char *data); extern int is_num_chr(char ch); extern int is_num_or_sp(char ch); extern int is_xnum_or_dash(char *data, int max); extern void removeCtrlCodes(char *cp); extern void makePrintable(char *cp); extern void spell_it_out(char *text, int max_length); typedef struct { pthread_mutex_t lock; pthread_t threadID; } xastir_mutex; extern void init_critical_section(xastir_mutex *lock); extern int begin_critical_section(xastir_mutex *lock, char *text); extern int end_critical_section(xastir_mutex *lock, char *text); //#define TIMING_DEBUG #ifdef TIMING_DEBUG void time_mark(int start); #endif // TIMING_DEBUG // dl9sau extern char *sec_to_loc(long longitude, long latitude); extern short checkHash(char *theCall, short theHash); extern void split_string ( char *data, char *cptr[], int max, char search_char ); extern int check_unproto_path( char *data ); extern void set_dangerous( char *ptr ); extern void clear_dangerous(void); void xastirWriteWKT(char *name); char * makeMultiline(int numPairs, double *lon, double *lat, char colorStyle, int lineType, char* sqnc, double *lonCentr, double *latCentr ); #endif // __XASTIR_UTIL_H Xastir-Release-2.2.2/src/view_message_gui.c000066400000000000000000000630331501463444000206300ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "main.h" #include "util.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget All_messages_dialog = NULL; Widget view_messages_text = NULL; Widget vm_dist_data = NULL; static xastir_mutex All_messages_dialog_lock; int vm_range; int view_message_limit = 10000; int Read_messages_packet_data_type = 0; // 1=tnc_only, 2=net_only, 0=tnc&net int Read_messages_mine_only = 0; void view_message_gui_init(void) { init_critical_section( &All_messages_dialog_lock ); } void view_message_print_record(Message *m_fill) { int pos; char *temp; int i; int my_size = 200; char temp_my_course[10]; XmTextPosition drop_ptr; int distance; // Make sure it's within our distance range we have set distance = distance_from_my_station(m_fill->from_call_sign,temp_my_course); if (Read_messages_mine_only || (!Read_messages_mine_only && ( (vm_range == 0) || (distance <= vm_range) ) ) ) { // Check that it's coming from the correct type of interface // Compare Read_messages_packet_data_type against the port // type associated with data_port to determine whether or // not to display it. // // I = Internet // L = Local // T = TNC // F = File // switch (Read_messages_packet_data_type) { case 2: // Display NET data only // if not network_interface, return if (m_fill->data_via != 'I') { return; // Don't display it } break; case 1: // Display TNC data only // if not local_tnc_interface, return if (m_fill->data_via != 'T') { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // Check for my stations only if set if (Read_messages_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(m_fill->call_sign, short_call) && !strstr(m_fill->from_call_sign, short_call)) { return; } } if ((temp = malloc((size_t)my_size)) == NULL) { return; } sprintf(temp,"%-9s>%-9s %s:%5s %s:%c :%s\n", m_fill->from_call_sign, m_fill->call_sign, langcode("WPUPMSB013"), m_fill->seq, langcode("WPUPMSB014"), m_fill->type, m_fill->message_line); pos = (int)XmTextGetLastPosition(view_messages_text); XmTextInsert(view_messages_text, pos, temp); pos += strlen(temp); while (pos > view_message_limit) { for (drop_ptr = i = 0; i < 3; i++) { (void)XmTextFindString(view_messages_text, drop_ptr, "\n", XmTEXT_FORWARD, &drop_ptr); drop_ptr++; } XmTextReplace(view_messages_text, 0, drop_ptr, ""); pos = (int)XmTextGetLastPosition(view_messages_text); } XtVaSetValues(view_messages_text, XmNcursorPosition, pos, NULL); free(temp); } } void view_message_display_file(char msg_type) { int pos; if ((All_messages_dialog != NULL)) { mscan_file(msg_type, view_message_print_record); } pos = (int)XmTextGetLastPosition(view_messages_text); XmTextShowPosition(view_messages_text, pos); } void all_messages(char from, char *call_sign, char *from_call, char *message) { char temp_my_course[10]; char *temp; char data1[97]; char data2[97]; int pos; int i; int my_size = 200; XmTextPosition drop_ptr; if (Read_messages_mine_only || (!Read_messages_mine_only && ((vm_range == 0) || (distance_from_my_station(call_sign,temp_my_course) <= vm_range)) ) ) { // Check that it's coming from the correct type of interface // Compare Read_messages_packet_data_type against the port // type associated with data_port to determine whether or // not to display it. // // I = Internet // L = Local // T = TNC // F = File // switch (Read_messages_packet_data_type) { case 2: // Display NET data only // if not network_interface, return if (from != 'I') { return; // Don't display it } break; case 1: // Display TNC data only // if not local_tnc_interface, return if (from != 'T') { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // Check for my stations only if set if (Read_messages_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(call_sign, short_call) && !strstr(from_call, short_call)) { return; } } if ((temp = malloc((size_t)my_size)) == NULL) { return; } if (strlen(message)>95) { xastir_snprintf(data1, sizeof(data1), "%s", message); data1[95]='\0'; xastir_snprintf(data2, sizeof(data2), "\n\t%s", message+95); } else { xastir_snprintf(data1, sizeof(data1), "%s", message); data2[0] = '\0'; } if (strncmp(call_sign, "java",4) == 0) { xastir_snprintf(call_sign, MAX_CALLSIGN+1, "%s", langcode("WPUPMSB015") ); // Broadcast xastir_snprintf(temp, my_size, "%s %s\t%s%s\n", from_call, call_sign, data1, data2); } else if (strncmp(call_sign, "USER", 4) == 0) { xastir_snprintf(call_sign, MAX_CALLSIGN+1, "%s", langcode("WPUPMSB015") ); // Broadcast xastir_snprintf(temp, my_size, "%s %s\t%s%s\n", from_call, call_sign, data1, data2); } else { char from_str[10]; xastir_snprintf(from_str, sizeof(from_str), "%c", from); strcpy(temp, from_call); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " to "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, call_sign); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " via:"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, from_str); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "\t"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data1); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data2); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "\n"); temp[sizeof(temp)-1] = '\0'; // Terminate string } if ((All_messages_dialog != NULL)) { begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:all_messages" ); pos = (int)XmTextGetLastPosition(view_messages_text); XmTextInsert(view_messages_text, pos, temp); pos += strlen(temp); while (pos > view_message_limit) { for (drop_ptr = i = 0; i < 3; i++) { (void)XmTextFindString(view_messages_text, drop_ptr, "\n", XmTEXT_FORWARD, &drop_ptr); drop_ptr++; } XmTextReplace(view_messages_text, 0, drop_ptr, ""); pos = (int)XmTextGetLastPosition(view_messages_text); } XtVaSetValues(view_messages_text, XmNcursorPosition, pos, NULL); XmTextShowPosition(view_messages_text, pos); end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:all_messages" ); } free(temp); } } void All_messages_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; temp_ptr = XmTextFieldGetString(vm_dist_data); vm_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:All_messages_destroy_shell" ); XtDestroyWidget(shell); All_messages_dialog = (Widget)NULL; end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:All_messages_destroy_shell" ); } void All_messages_change_range( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; char *temp_ptr; temp_ptr = XmTextFieldGetString(vm_dist_data); vm_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); All_messages_destroy_shell(widget, clientData, callData); view_all_messages(widget, clientData, callData); } void Read_messages_packet_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Read_messages_packet_data_type = atoi(which); } else { Read_messages_packet_data_type = 0; } } Widget button_range; void Read_messages_mine_only_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Read_messages_mine_only = atoi(which); XtSetSensitive(vm_dist_data, FALSE); } else { Read_messages_mine_only = 0; XtSetSensitive(vm_dist_data, TRUE); } } void view_all_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close, dist, dist_units; Widget option_box, tnc_data, net_data, tnc_net_data, read_mine_only_button; unsigned int n; #define NCNT 50 #define IncN(n) if (n< NCNT) n++; else fprintf(stderr, "Oops, too many arguments for array!\a") Arg args[NCNT]; Atom delw; char temp[10]; if (!All_messages_dialog) { begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:view_all_messages" ); All_messages_dialog = XtVaCreatePopupShell(langcode("AMTMW00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("view_all_messages pane", xmPanedWindowWidgetClass, All_messages_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("view_all_messages my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); dist = XtVaCreateManagedWidget(langcode("AMTMW00002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); vm_dist_data = XtVaCreateManagedWidget("view_all_messages dist_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*7)+2), XmNmaxLength, 8, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); dist_units = XtVaCreateManagedWidget((english_units?langcode("UNIOP00004"):langcode("UNIOP00005")), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, vm_dist_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_range = XtVaCreateManagedWidget(langcode("BULMW00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_units, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_range, XmNactivateCallback, All_messages_change_range, All_messages_dialog); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_range, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, All_messages_destroy_shell, All_messages_dialog); n=0; XtSetArg(args[n],XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n],XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, dist); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; option_box = XmCreateRadioBox(my_form, "View Messages option box", args, n); XtVaSetValues(option_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, NULL); tnc_data = XtVaCreateManagedWidget(langcode("WPUPDPD002"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"1"); net_data = XtVaCreateManagedWidget(langcode("WPUPDPD003"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(net_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"2"); tnc_net_data = XtVaCreateManagedWidget(langcode("WPUPDPD004"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_net_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"0"); read_mine_only_button = XtVaCreateManagedWidget(langcode("WPUPDPD008"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dist, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, option_box, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(read_mine_only_button,XmNvalueChangedCallback,Read_messages_mine_only_toggle,"1"); n=0; XtSetArg(args[n], XmNrows, 15); IncN(n); XtSetArg(args[n], XmNcolumns, 85); IncN(n); XtSetArg(args[n], XmNeditable, FALSE); IncN(n); XtSetArg(args[n], XmNtraversalOn, TRUE); IncN(n); XtSetArg(args[n], XmNlistSizePolicy, XmVARIABLE); IncN(n); XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); IncN(n); XtSetArg(args[n], XmNwordWrap, TRUE); IncN(n); XtSetArg(args[n], XmNscrollHorizontal, TRUE); IncN(n); XtSetArg(args[n], XmNscrollVertical, TRUE); IncN(n); // XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); IncN(n); XtSetArg(args[n], XmNselectionPolicy, XmMULTIPLE_SELECT); IncN(n); XtSetArg(args[n], XmNcursorPositionVisible, FALSE); IncN(n); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); IncN(n); XtSetArg(args[n], XmNtopWidget, option_box); IncN(n); XtSetArg(args[n], XmNtopOffset, 5); IncN(n); XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNleftOffset, 5); IncN(n); XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNrightOffset, 5); IncN(n); XtSetArg(args[n], XmNforeground, MY_FG_COLOR); IncN(n); XtSetArg(args[n], XmNbackground, MY_BG_COLOR); IncN(n); XtSetArg(args[n], XmNfontList, fontlist1); n++; view_messages_text = XmCreateScrolledText(my_form, "view_all_messages text", args, n); // It's hard to get tab groups working with ScrolledText widgets. Tab'ing in is // fine, but then I'm stuck in insert mode and it absorbs the tabs and beeps. pos_dialog(All_messages_dialog); delw = XmInternAtom(XtDisplay(All_messages_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(All_messages_dialog, delw, All_messages_destroy_shell, (XtPointer)All_messages_dialog); sprintf(temp,"%d",vm_range); XmTextFieldSetString(vm_dist_data,temp); switch (Read_messages_packet_data_type) { case(0): XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; case(1): XmToggleButtonSetState(tnc_data,TRUE,FALSE); break; case(2): XmToggleButtonSetState(net_data,TRUE,FALSE); break; default: XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; } if (Read_messages_mine_only) { XmToggleButtonSetState(read_mine_only_button,TRUE,FALSE); XtSetSensitive(vm_dist_data, FALSE); } else { XmToggleButtonSetState(read_mine_only_button,FALSE,FALSE); XtSetSensitive(vm_dist_data, TRUE); } XtManageChild(option_box); XtManageChild(view_messages_text); XtVaSetValues(view_messages_text, XmNbackground, colors[0x0f], NULL); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, All_messages_dialog); redraw_on_new_packet_data=1; // Dump all currently active messages to the new window view_message_display_file('M'); end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:view_all_messages" ); XtPopup(All_messages_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(All_messages_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(All_messages_dialog), XtWindow(All_messages_dialog)); } } Xastir-Release-2.2.2/src/wx.c000066400000000000000000004141221501463444000157430ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // // The code currently supports these types of locally-connected or // network-connected weather stations: // // Peet Brothers Ultimeter 2000 (Set to Data logging mode) // Peet Brothers Ultimeter 2000 (Set to Packet mode) // Peet Brothers Ultimeter 2000 (Set to Complete Record Mode) // Peet Brothers Ultimeter-II // Qualimetrics Q-Net? // Radio Shack WX-200/Huger WM-918/Oregon Scientific WM-918 // Dallas One-Wire Weather Station (via OWW network daemon) // Davis Weather Monitor II/Wizard III/Vantage Pro (via meteo/db2APRS link) // // Need to modify code to use WX_rain_gauge_type. Peet brothers. // See http://www.peetbros.com, FAQ's and owner's manuals for // details: // // Peet Bros Ultimeter II: 0.1"/0.5mm or 0.01"/0.25mm // Divide by 10 or 100 from the serial output. // // Peet Bros Ultimeter 2000, 800, & 100: 0.01"/0.25mm or 0.1mm // If 0.01" gauge, divide by 100. If 0.1mm gauge, convert to // proper English units. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include "wx.h" #include "main.h" #include "xastir.h" #include "interface.h" #include "lang.h" #include "util.h" // Must be last include file #include "leak_detection.h" #define MAX_RAW_WX_STRING 800 char wx_station_type[100]; char raw_wx_string[MAX_RAW_WX_STRING+1]; #define MAX_WX_STRING 300 #define WX_TYPE 'X' /* rain totals */ float rain_minute[60]; // Total rain for each min. of last hour, hundredths of an inch float rain_minute_total = 0.0; // Total for last hour, hundredths of an inch int rain_minute_last_write = -1; // Write pointer for rain_minute[] array, set to an invalid number float rain_00 = 0.0; // hundredths of an inch float rain_24 = 0.0; // hundredths of an inch float rain_base[24]; // hundredths of an inch int rain_check = 0; // Flag for re-checking rain_total each hour float wind_chill = 0; // holder for wind chill calc // Gust totals float gust[60]; // High wind gust for each min. of last hour int gust_write_ptr = 0; int gust_read_ptr = 0; int gust_last_write = 0; /* Other WX station data */ char wx_dew_point[10]; char wx_dew_point_on; char wx_high_wind[10]; char wx_high_wind_on; char wx_wind_chill[10]; char wx_wind_chill_on; char wx_three_hour_baro[10]; // hPa char wx_three_hour_baro_on; char wx_hi_temp[10]; char wx_hi_temp_on; char wx_low_temp[10]; char wx_low_temp_on; char wx_heat_index[10]; char wx_heat_index_on; /***********************************************************/ /* clear rain data */ /***********************************************************/ void clear_rain_data(void) { int x; // Clear rain_base queue (starting rain total for each hour) for ( x = 0; x < 24; x++ ) { rain_base[x] = 0.0; } rain_00 = 0.0; rain_24 = 0.0; rain_check = 0; // Set flag so we'll recheck rain_total // a few times at start of each hour // Clear hourly rain queue for ( x = 0; x < 60; x++ ) { rain_minute[x] = 0.0; } rain_minute_total = 0.0; rain_minute_last_write = 70; // Invalid number so we'll know we're just starting. } /**************************************************************/ /* compute_rain_hour - rolling average for the last 59.x */ /* minutes of rain. I/O numbers are in hundredths of an inch.*/ /* Output is in "rain_minute_total", a global variable. */ /**************************************************************/ void compute_rain_hour(float rain_total) { int current, j; float lowest; // Deposit the _starting_ rain_total for each minute into a separate bucket. // Subtract lowest rain_total in queue from current rain_total to get total // for the last hour. current = get_minutes(); // Fetch the current minute value. Use this as an index // into our minute "buckets" where we store the data. rain_minute[ (current + 1) % 60 ] = 0.0; // Zero out the next bucket (probably have data in // there from the previous hour). if (rain_minute[current] == 0.0) // If no rain_total stored yet in this minute's bucket { rain_minute[current] = rain_total; // Write into current bucket } // Find the lowest non-zero value for rain_total. The max value is "rain_total". lowest = rain_total; // Set to maximum to get things going for (j = 0; j < 60; j++) { if ( (rain_minute[j] > 0.0) && (rain_minute[j] < lowest) ) // Found a lower non-zero value? { lowest = rain_minute[j]; // Snag it } } // Found it, subtract the two to get total for the last hour rain_minute_total = rain_total - lowest; if (debug_level & 2) { fprintf(stderr,"Rain_total:%0.2f Hourly:%0.2f (Low:%0.2f) ", rain_total, rain_minute_total, lowest); } } /***********************************************************/ /* compute_rain - compute rain totals from the total rain */ /* so far. rain_total (in hundredths of an inch) keeps on */ /* incrementing. */ /***********************************************************/ void compute_rain(float rain_total) { int current, i; float lower; // Skip the routine if input is outlandish (Negative value, zero, or 512 inches!). // We seem to get occasional 0.0 packets from wx200d. This makes them go away. if ( (rain_total <= 0.0) || (rain_total > 51200.0) ) { return; } compute_rain_hour(rain_total); current = get_hours(); // Set rain_base: The first rain_total for each hour. if (rain_base[current] == 0.0) // If we don't have a start value yet for this hour, { rain_base[current] = rain_total; // save it away. rain_check = 0; // Set up rain_check so we'll do the following // "else" clause a few times at start of each hour. } else // rain_base has been set, is it wrong? We recheck three times at start of hour. { if (rain_check < 3) { rain_check++; // Is rain less than base? It shouldn't be. if (rain_total < rain_base[current]) { rain_base[current] = rain_total; } // Difference greater than 10 inches since last reading? It shouldn't be. if (fabs(rain_total - rain_base[current]) > 1000.0) // Remember: Hundredths of an inch { rain_base[current] = rain_total; } } } rain_base[ (current + 1) % 24 ] = 0.0; // Clear next hour's index. // Compute total rain in last 24 hours: Really we'll compute the total rain // in the last 23 hours plus the portion of an hour we've completed (Sum up // all 24 of the hour totals). This isn't the perfect way to do it, but to // really do it right we'd need finer increments of time (to get closer to // the goal of 24 hours of rain). lower = rain_total; for ( i = 0; i < 24; i++ ) // Find the lowest non-zero rain_base value in last 24 hours { if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) ) { lower = rain_base[i]; } } rain_24 = rain_total - lower; // Hundredths of an inch // Compute rain since midnight. Note that this uses whatever local time was set // on the machine. It might not be local midnight if your box is set to GMT. lower = rain_total; for ( i = 0; i <= current; i++ ) // Find the lowest non-zero rain_base value since midnight { if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) ) { lower = rain_base[i]; } } rain_00 = rain_total - lower; // Hundredths of an inch // It is the responsibility of the calling program to save // the new totals in the data structure for our station. // We don't return anything except in global variables. if (debug_level & 2) { fprintf(stderr,"24hrs:%0.2f ", rain_24); fprintf(stderr,"rain_00:%0.2f\n", rain_00); } } /**************************************************************/ /* compute_gust - compute max wind gust during last 5 minutes */ /* */ /**************************************************************/ float compute_gust(float wx_speed, float UNUSED(last_speed), time_t *last_speed_time) { float computed_gust; int current, j; // Deposit max gust for each minute into a different bucket. // Check all buckets for max gust within the last five minutes // (Really 4 minutes plus whatever portion of a minute we've completed). current = get_minutes(); // Fetch the current minute value. We use this as an index // into our minute "buckets" where we store the data. // If we haven't started collecting yet, set up to do so if (gust_read_ptr == gust_write_ptr) // We haven't started yet { gust_write_ptr = current; // Set to write into current bucket gust_last_write = current; gust_read_ptr = current - 1; // Set read pointer back one, modulus 60 if (gust_read_ptr < 0) { gust_read_ptr = 59; } gust[gust_write_ptr] = 0.0; // Zero the max gust gust[gust_read_ptr] = 0.0; // for both buckets. //WE7U: Debug //gust[gust_write_ptr] = 45.9; } // Check whether we've advanced at least one minute yet if (current != gust_write_ptr) // We've advanced to a different minute { gust_write_ptr = current; // Start writing into a new bucket. gust[gust_write_ptr] = 0.0; // Zero the new bucket // Check how many bins of real data we have currently. Note that this '5' is // correct, as we just advanced "current" to the next minute. We're just pulling // along the read_ptr behind us if we have 5 bins worth of data by now. if ( ((gust_read_ptr + 5) % 60) == gust_write_ptr) // We have 5 bins of real data { gust_read_ptr = (gust_read_ptr + 1) % 60; // So advance the read pointer, } // Check for really bad pointers, perhaps the weather station got // unplugged for a while or it's just REALLY slow at sending us data? // We're checking to see if gust_last_write happened in the previous // minute. If not, we skipped a minute or more somewhere. if ( ((gust_last_write + 1) % 60) != current ) { // We lost some time somewhere: Reset the pointers, older gust data is // lost. Start over collecting new gust data. gust_read_ptr = current - 1; // Set read pointer back one, modulus 60 if (gust_read_ptr < 0) { gust_read_ptr = 59; } gust[gust_read_ptr] = 0.0; } gust_last_write = current; } // Is current wind speed higher than the current minute bucket? if (wx_speed > gust[gust_write_ptr]) { gust[gust_write_ptr] = wx_speed; // Save it in the bucket } // Read the last (up to) five buckets and find the max gust computed_gust=gust[gust_write_ptr]; j = gust_read_ptr; while (j != ((gust_write_ptr + 1) % 60) ) { if ( computed_gust < gust[j] ) { computed_gust = gust[j]; } j = (j + 1) % 60; } if (debug_level & 2) { j = gust_read_ptr; while (j != ((gust_write_ptr + 1) % 60) ) { fprintf(stderr,"%0.2f ", gust[j]); j = (j + 1) % 60; } fprintf(stderr,"gust:%0.2f\n", computed_gust); } *last_speed_time = sec_now(); return(computed_gust); } // // cycle_weather - keep the weather queues moving even if data from // weather station is scarce. This is called from main.c:UpdateTime() // on a periodic basis. This routine also does the 30 second timestamp // for the log files. // void cycle_weather(void) { DataRow *p_station; WeatherRow *weather; float last_speed, computed_gust; time_t last_speed_time; // Find my own local weather data if (search_station_name(&p_station,my_callsign,1)) { if (p_station->weather_data != NULL) // If station has WX data { weather = p_station->weather_data; // Cycle the rain queues, feed in the last rain total we had (void)compute_rain((float)atof(weather->wx_rain_total)); // Note: Some weather stations provide the per-hour, 24-hour, // and since-midnight rain rates already. Further, some stations // don't even provide total rain (Davis APRS DataLogger and the // db2APRS program), so anything we compute here is actually wrong. // Do NOT clobber these if so. This flag is set in fill_wx_data // when the station provides its data. if (weather->wx_compute_rain_rates) { // Hourly rain total xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); // Last 24 hour rain xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); // Rain since midnight xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { // LaCrosse stations don't provide the since-midnight // numbers and so this will be blank. // So if we have blanks here, fill it in. if ( weather->wx_prec_00[0] == '\0' && weather->wx_rain_total[0] != '\0') { // Rain since midnight xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } /* get last gust speed */ if (strlen(weather->wx_gust) > 0) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } else { last_speed = 0.0; } /* wind speed */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(computed_gust + 0.5)); // Cheater's way of rounding } } } /***********************************************************/ /* clear other wx data */ /***********************************************************/ void clear_local_wx_data(void) { memset(wx_dew_point,0,sizeof(wx_dew_point)); wx_dew_point_on = 0; memset(wx_high_wind,0,sizeof(wx_high_wind)); wx_high_wind_on = 0; memset(wx_wind_chill,0,sizeof(wx_wind_chill)); wx_wind_chill_on = 0; memset(wx_three_hour_baro,0,sizeof(wx_three_hour_baro)); wx_three_hour_baro_on = 0; memset(wx_hi_temp,0,sizeof(wx_hi_temp)); wx_hi_temp_on = 0; memset(wx_low_temp,0,sizeof(wx_low_temp)); wx_low_temp_on = 0; memset(wx_heat_index,0,sizeof(wx_heat_index)); wx_heat_index_on = 0; } /***************************************************/ /* Check last WX data received - clear data if old */ /***************************************************/ void wx_last_data_check(void) { DataRow *p_station; p_station = NULL; if (search_station_name(&p_station,my_callsign,1)) { if (p_station->weather_data != NULL) if (p_station->weather_data->wx_speed_sec_time+360 < sec_now()) if (p_station->weather_data->wx_gust[0] != 0) xastir_snprintf(p_station->weather_data->wx_gust, sizeof(p_station->weather_data->wx_gust), "%03d", 0); } } //********************************************************************* // Decode Peet Brothers Ultimeter 2000 weather data (Data logging mode) // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. // // The Ultimeter 2000 can be in any of three modes, Data Logging Mode, // Packet Mode, or Complete Record Mode. This routine handles only // the Data Logging Mode. //********************************************************************* void decode_U2000_L(int from, unsigned char *data, WeatherRow *weather) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; last_speed = 0.0; last_speed_time = 0; computed_gust = 0.0; if (debug_level & 1) { fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode): |%s|\n", data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } // 006B 00 58 // 00A4 00 46 01FF 380E 2755 02C1 03E8 ---- 0052 04D7 0001 007BM // ^ ^ ^ ^ ^ ^ ^ // 0 6 8 12 16 24 40 /* wind speed */ if (data[0] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)data,4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); // Cheater's way of rounding } } else { if (!from) { weather->wx_speed[0] = 0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may be FF // if a direction calibration has been entered. We should zero // them. // if (data[4] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+4),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", ((strtol(temp_data1,&temp_conv,16)/256.0)*360.0)); } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[8] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+8),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) { weather->wx_temp[0]=0; } } /* rain total long term */ if (data[12] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0]=0; } } /* baro */ if (data[16] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+16),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_baro[0]=0; } } /* outdoor humidity */ if (data[24] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+24),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", (strtol(temp_data1,&temp_conv,16)/10.0)); } else { if (!from) { weather->wx_hum[0]=0; } } /* todays rain total */ if (data[40] != '-') // '-' signifies invalid data { if (from) { substr(temp_data1,(char *)(data+40),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) { weather->wx_prec_00[0] = 0; } } } //******************************************************************** // Decode Peet Brothers Ultimeter 2000 weather data (Packet mode) // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. // // The Ultimeter 2000 can be in any of three modes, Data Logging Mode, // Packet Mode, or Complete Record Mode. This routine handles only // the Packet Mode. //******************************************************************** void decode_U2000_P(int from, unsigned char *data, WeatherRow *weather) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; int len; last_speed = 0.0; last_speed_time = 0; computed_gust = 0.0; len = (int)strlen((char *)data); if (debug_level & 1) { fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode): |%s|\n",data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } // $ULTW 0031 00 37 02CE 0069 ---- 0000 86A0 0001 ---- 011901CC 0000 0005 // ^ ^ ^ ^ ^ ^ ^ ^ // 0 6 8 12 16 32 44 48 /* wind speed peak over last 5 min */ if (data[0] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)data,4); if (from) { xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); /* this may be the only wind data */ xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { /* local station and may be the only wind data */ if (len < 51) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } } else { if (!from) { weather->wx_gust[0] = 0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may be FF // if a direction calibration has been entered. We should zero // them. // if (data[4] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+4),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) { weather->wx_course[0] = 0; } } /* outdoor temp */ if (data[8] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+8),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) { weather->wx_temp[0] = 0; } } /* todays rain total (on some units) */ if ((data[44]) != '-') // '-' signifies invalid data { if (from) { substr(temp_data1,(char *)(data+44),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) { weather->wx_prec_00[0] = 0; } } /* rain total long term */ if (data[12] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0] = 0; } } /* baro */ if (data[16] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+16),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_baro[0] = 0; } } /* outdoor humidity */ if (data[32] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+32),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_hum[0] = 0; } } /* 1 min wind speed avg */ if (len > 48 && (data[48]) != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+48),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) { if (len > 48) { weather->wx_speed[0] = 0; } } } } //***************************************************************** // Decode Peet Brothers Ultimeter-II weather data // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. //***************************************************************** void decode_Peet_Bros(int from, unsigned char *data, WeatherRow *weather, int type) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; last_speed = 0.0; computed_gust = 0.0; last_speed_time = 0; if (debug_level & 1) { fprintf(stderr,"APRS WX4 Peet Bros U-II: |%s|\n",data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "UII"); // '*' = MPH // '#' = km/h // // # 5 0B 75 0082 0082 // * 7 00 76 0000 0000 // ^ ^ ^ ^ // rain [1/100 inch ?] // outdoor temp // wind speed [mph / km/h] // wind dir /* wind direction */ // // 0x00 is N // 0x04 is E // 0x08 is S // 0x0C is W // substr(temp_data1,(char *)data,1); xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/16.0)*360.0); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } /* wind speed */ substr(temp_data1,(char *)(data+1),2); if (type == APRS_WX4) // '#' speed in km/h, convert to mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137))); } else // type == APRS_WX6, '*' speed in mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (1.0 * strtol(temp_data1,&temp_conv,16)) ); } if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } /* outdoor temp */ if (data[3] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+3),2); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03.0f", (float)(temp4-56) ); } else { if (!from) { weather->wx_temp[0] = 0; } } // Rain divided by 100 for readings in hundredth of an inch if (data[5] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+5),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0] = 0; } } } /**************************************************/ /* RSW num convert. For Radio Shack WX-200, */ /* converts two decimal nibbles into integer */ /* number. */ /**************************************************/ int rswnc(unsigned char c) { return( (int)( (c>>4) & 0x0f) * 10 + (int)(c&0x0f) ); } //********************************************************* // wx fill data field // from: 0=local station, 1=regular decode (other stations) // type: type of WX packet // data: the packet of WX data // fill: the station data to fill // // This function is called only by wx.c:wx_decode() // // It is always called with a first parameter of 0, so we // use this only for our own serially-connected or network // connected weather station, not for decoding other // people's weather packets. //********************************************************* // // Note that the length of "data" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void wx_fill_data(int from, int type, unsigned char *data, DataRow *fill) { time_t last_speed_time; float last_speed; float computed_gust; int temp1; int temp2; int temp3; float temp_temp; char temp[MAX_DEVICE_BUFFER+1]; char temp_data1[10]; char *temp_conv; int len; int t2; int hidx_temp; int rh2; int hi_hum; int heat_index; WeatherRow *weather; float tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp9,tmp10,tmp11,tmp12,tmp13,tmp14,tmp15,tmp16,tmp17,tmp18,tmp19; int tmp7,tmp8; int dallas_type = 19; last_speed=0.0; computed_gust=0.0; last_speed_time=0; len=(int)strlen((char*)data); weather = fill->weather_data; // should always be defined switch (type) { //WE7U ///////////////////////////////////// // Dallas One-Wire Weather Station // ///////////////////////////////////// // KB1MTS - Added values for T13 thru T19 for humidity and barometer, // however only current values (not min or max) are used. case (DALLAS_ONE_WIRE): if (debug_level & 1) { fprintf(stderr,"APRS WX Dallas One-Wire %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "OWW"); if (19 == sscanf((const char *)data, "%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &tmp8, &tmp9, &tmp10, &tmp11, &tmp12, &tmp13, &tmp14, &tmp15, &tmp16, &tmp17, &tmp18, &tmp19)) { dallas_type = 19; } else if (12 == sscanf((const char *)data, "%f %f %f %f %f %f %d %d %f %f %f %f", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &tmp8, &tmp9, &tmp10, &tmp11, &tmp12)) { dallas_type = 12; } else { fprintf(stderr,"wx_fill_data:sscanf parsing error\n"); } // The format of the data originates here: // http://weather.henriksens.net/ // tmp1: primary temp (C) // tmp2: temp max (C) // tmp3: temp min (C) // tmp4: anemometer (mps) // tmp5: anemometer gust (peak speed MS) // tmp6: anemometer speed max * 0.447040972 (max speed MS) // tmp7: vane bearing - 1 (current wind direction) // tmp8: vane mode (max dir) // tmp9: rain rate // tmp10: rain total today // tmp11: rain total week // tmp12: rain since month // tmp13: Current Humidity // tmp14: Max Humidity // tmp15: Min Humidity // tmp16: Current Barometer // tmp17: Max Barometer // tmp18: Min Barometer // tmp19: Barometer Rate // Temperature xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)(tmp1 * 9.0 / 5.0 + 32.0 + 0.5)); //fprintf(stderr,"Read: %2.1f C, Storing: %s F\n",tmp1,weather->wx_temp); // Wind direction. Each vane increment equals 22.5 degrees. xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03d", (int)(tmp7 * 22.5 + 0.5)); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } // Wind speed. We get it in meters per second, store it // in mph. tmp4 = tmp4 * 3600.0 / 1000.0; // kph tmp4 = tmp4 * 0.62137; // mph xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(tmp4 + 0.5)); if (dallas_type == 19) { // Humidity. This is received by percentage. xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%2.1f", (double)(tmp13)); // Barometer. Sent in inHg xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%4.4f", (float)(tmp16 * 33.864)); } // Rain: I don't have a rain gauge, and I couldn't tell from the // "OWW" docs exactly which of the four rain fields did what. If // someone can help me with that I'll add rain gauge code for the // Dallas One-Wire. break; //////////////////////////////// // Peet Brothers Ultimeter-II // //////////////////////////////// case (APRS_WX4): // '#', Wind speed in km/h case (APRS_WX6): // '*', Wind speed in mph // This one assumes 0.1" rain gauge. Must correct in software if // any other type is used. if (debug_level & 1) { fprintf(stderr,"APRS WX4 Peet Bros U-II %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "UII"); /* wind direction */ // // 0x00 is N // 0x04 is E // 0x08 is S // 0x0C is W // substr(temp_data1,(char *)(data+1),1); xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/16.0)*360.0); // Check for course == 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed */ substr(temp_data1,(char *)(data+2),2); if (type == APRS_WX4) // '#', Data is in km/h, convert to mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137))); } else // APRS_WX6 or '*', Data is in MPH { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)*1.0) ); } if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } /* outdoor temp */ if (data[4]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+4),2); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03.0f", (float)(temp4-56) ); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* rain div by 100 for readings 0.1 inch */ // What? Shouldn't this be /10? if (data[6]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+6),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } break; /////////////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in data logging mode // /////////////////////////////////////////////////////// case (APRS_WX3): if (debug_level & 1) { fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode) %s:<%s>\n",fill->call_sign,data+2); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed */ if (data[2]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+2),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + ((strtol(temp_data1,&temp_conv,16) /10.0)*0.62137)); if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) // From local station { weather->wx_speed[0]=0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may // be FF if a direction calibration has been entered. // We should zero them. // if (data[6]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+6),4); // Zero out the first two bytes temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) // From local station { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[10]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+10),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* rain total long term */ if (data[14]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+14),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } /* baro */ if (data[18]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+18),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } /* outdoor humidity */ if (data[26]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+26),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) // From local station { weather->wx_hum[0]=0; } } // Isn't this replaced by the above switch-case? // No, I don't think so. We can get these packets over // RF as well. /* todays rain total */ if (strlen((const char *)data) > 45) { if (data[42]!='-') // '-' signifies invalid data { if (from) // From remote station { substr(temp_data1,(char *)(data+42),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) // From local station { weather->wx_prec_00[0]=0; } } } break; ///////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in packet mode // ///////////////////////////////////////////////// case(APRS_WX5): if (debug_level & 1) { fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode) %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed peak over last 5 min */ if (data[5]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+5),4); if (from) // From remote station { xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); /* this may be the only wind data */ xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { /* local station and may be the only wind data */ if (len<56) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + ( strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } } else { if (!from) // From local station { weather->wx_gust[0]=0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may // be FF if a direction calibration has been entered. // We should zero them. // if (data[9]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+9),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) // From local station { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[13]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+13),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* todays rain total (on some units) */ if (data[49]!='-') // '-' signifies invalid data { if (from) // From remote station { substr(temp_data1,(char *)(data+49),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) // From local station { weather->wx_prec_00[0]=0; } } /* rain total long term */ if (data[17]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+17),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } /* baro */ if (data[21]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+21),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1, &temp_conv, 16)/10.0); } else { if (!from) // From local station { weather->wx_baro[0]=0; } } /* outdoor humidity */ if (data[37]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+37),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) // From local station { weather->wx_hum[0]=0; } } /* 1 min wind speed avg */ if (len>53 && (data[53]) != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+53),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) // From local station { if (len>53) { weather->wx_speed[0]=0; } } } break; ////////////////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in complete record mode // ////////////////////////////////////////////////////////// // // In this mode most fields are 4-bytes two's complement. A // few fields are 2-bytes wide. // // // case(PEET_COMPLETE): if (debug_level & 1) { fprintf(stderr,"Peet Bros U-2k Packet (Complete Record Mode) %s:<%s>\n",fill->call_sign,data); } if (!from) // From local station { int done_with_wx_speed = 0; /* decode only for local station */ weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); if (data[12]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { weather->wx_gust[0]=0; } // Check whether field 115 is available at bytes 452 // through 455. If so, that's the one-minute wind // speed average in 0.1kph, which matches the APRS // spec except for the units (which should be MPH). if ( (len >= 456) && (data[452] != '-') ) // '-' signifies invalid data { substr(temp_data1,(char *)(data+452),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); done_with_wx_speed++; } // Some Peet units don't have that particular wind // speed field, so snag what wind speed we can from // the other wind speed fields, which don't quite // match the APRS spec as they're instantaneous // values, not one-minute sustained speeds. // KG9AE // Peet Bros CR mode wind values should be selected based on which are highest. /* Wind Speed fields 1, 34, and 71. Wind direction fields 2, 35, 72. */ if (data[4] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+4, 4); temp1 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp1=0; } if (data[136] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+136, 4); temp2 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp2=0; } if (data[284] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+284, 4); temp3 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp3=0; } // fprintf(stderr,"WIND: wind1 %d, wind2 %d, wind3 %d\n", temp1, temp2, temp3); // Select wind speed and direction based on which // wind speed is the highest. Ugh, surely there's a // way to make this pretty. A function might be // better. if ( temp1 >= temp2 && temp1 >= temp3 ) { // fprintf(stderr,"WIND: ***\n"); /* wind speed */ if (!done_with_wx_speed) { substr(temp_data1,(char *)(data+4),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[8]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+8),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else if ( temp2 >= temp1 && temp2 >= temp3 ) { // fprintf(stderr,"WIND: ***\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+136),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[140]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+140),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else if ( temp3 >= temp2 && temp3 >= temp1 ) { // fprintf(stderr,"WIND: ***\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+284),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[288]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+288),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else /* Or default to the first value */ { // fprintf(stderr,"WIND: DEFAULTING!\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+4),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[8]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+8),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } /* outdoor temp */ if (data[24]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+24),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { weather->wx_temp[0]=0; } // We don't want to parse this here because compute_rain() // calculates this for us from the accumulating long-term rain // total. If we were to do it here as well, we'll get conflicting // results. Since only some units put out today's rain total, we'll // just rely on our own calculations for it instead. It'll work // across more units. /* // todays rain total (on some units) if (data[28]!='-') { // '-' signifies invalid data substr(temp_data1,(char *)(data+28),4); switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/254.0); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/100.0); break; } } else weather->wx_prec_00[0]=0; */ /* rain total long term */ if ((char)data[432]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+432),4); switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* Since local station only */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { weather->wx_rain_total[0]=0; } /* baro */ if (data[32]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+32),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { weather->wx_baro[0]=0; } /* outdoor humidity */ if (data[52]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+52),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { weather->wx_hum[0]=0; } /* dew point */ if (data[60]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+60),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_dew_point, sizeof(wx_dew_point), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_dew_point_on = 1; } /*high winds for today*/ if (data[248]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+248),4); xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); wx_high_wind_on = 1; } /*wind chill */ if (data[20]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+20),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_wind_chill_on = 1; } /*3-Hr Barometric Change */ if (data[36]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+36),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_three_hour_baro, sizeof(wx_three_hour_baro), "%0.2f", // Old code // (float)((strtol(temp_data1,&temp_conv,16)<<16)/65536)/100.0/3.38639); // New code, fix by Matt Werner, kb0kqa: (float)((temp4<<16)/65536)/10.0); wx_three_hour_baro_on = 1; } /* High Temp for Today*/ if (data[276]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+276),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_hi_temp_on = 1; } else { wx_hi_temp_on = 0; } /* Low Temp for Today*/ if (data[100]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+100),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_low_temp_on = 1; } else { wx_low_temp_on = 0; } /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2; xastir_snprintf (wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on = 1; } else { wx_heat_index_on = 0; } } break; //////////////////////// // Qualimetrics Q-Net // //////////////////////// case(QM_WX): if (debug_level & 1) { fprintf(stderr,"Qualimetrics Q-Net %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "Q-N"); // Can this sscanf overflow the "temp" buffer? I // changed the length of temp to MAX_DEVICE_BUFFER to // avoid this problem. if (6 != sscanf((char *)data,"%19s %d %19s %d %19s %d",temp,&temp1,temp,&temp2,temp,&temp3)) { fprintf(stderr,"wx_fill_data:sscanf parsing error\n"); } /* outdoor temp */ xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((temp2/10.0))); /* baro */ xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", ((float)temp3/100.0)*33.864); /* outdoor humidity */ xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d", temp1); if (!from) // From local station { weather->wx_gust[0]=0; weather->wx_course[0]=0; weather->wx_rain[0]=0; weather->wx_prec_00[0]=0; weather->wx_prec_24[0]=0; weather->wx_rain_total[0]=0; weather->wx_gust[0]=0; weather->wx_speed[0]=0; } break; /////////////////////////////////////////////////////////// // Radio Shack WX-200 or Huger/Oregon Scientific WM-918 // /////////////////////////////////////////////////////////// case(RSWX200): // Notes: Many people run the wx200d daemon connected to the weather station, // with Xastir then connected to wx200d. Note that wx200d changes the protocol // slightly: It only sends frames that have changed to the clients. This means // even if the weather station is sending regular packets, wx200d won't send // them along to Xastir if all the bits are the same as the last packet of that // type. To fix this I had to tie into the main.c:UpdateTime() function to do // regular updates at a 30 second rate, to keep the rain and gust queues cycling // on a regular basis. // // 2nd Note: Some WX-200 weather stations send bogus data. I had to add in a // bunch of filtering to keep the global variables from getting corrupted by // this data. More filtering may need to be done and/or the limits may need to // be changed. if (!from) // From local station { if (debug_level & 1) { fprintf(stderr,"RSWX200 WX (binary)\n"); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "RSW"); switch (data[0]) { case 0x8f: /* humidity */ if ( (rswnc(data[20]) <= 100) && (rswnc(data[2]) >= 0) ) xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d", rswnc(data[20])); else //sprintf(weather->wx_hum,"100"); { fprintf(stderr,"Humidity out-of-range, ignoring: %03d\n",rswnc(data[20]) ); } break; case 0x9f: /* temp */ /* all data in C ?*/ xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%0.1f", ((data[17]&0x08) ? '-' : '+'),(data[17]&0x7),rswnc(data[16])/10.0); /*fprintf(stderr,"temp data: <%s> %d %d %d\n", temp_data1,((data[17]&0x08)==0x08),(data[17]&0x7),rswnc(data[16]));*/ temp_temp = (float)((atof(temp_data1)*1.8)+32); if ( (temp_temp >= -99.0) && (temp_temp < 200.0) ) { xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); /*fprintf(stderr,"Temp %s C %0.2f %03d\n",temp_data1,atof(temp_data1),(int)atof(temp_data1)); fprintf(stderr,"Temp F %0.2f %03d\n",(atof(temp_data1)*1.8)+32,(int)(atof(temp_data1)*1.8)+32); */ } else // We don't want to save this one { fprintf(stderr,"Temp out-of-range, ignoring: %0.2f\n", temp_temp); } xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%d.%d", ((data[18]&0x80) ? '-' : '+'),(data[18]&0x70)>>4,(data[18]&0x0f),(data[17] & 0xf0) >> 4); xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); wx_hi_temp_on=1; xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%d.%d", ((data[23]&0x80) ? '-' : '+'),(data[23]&0x70)>>4,(data[23]&0x0f),(data[22] & 0xf0) >> 4); xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); wx_low_temp_on=1; break; case 0xaf: /* baro/dewpt */ // local baro pressure in mb? // sprintf(weather->wx_baro,"%02d%02d",rswnc(data[2]),rswnc(data[1])); // Sea Level Adjusted baro in mb xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0d%02d%0.1f", (data[5]&0x0f), rswnc(data[4]), rswnc(data[3])/10.0); /* dew point in C */ temp_temp = (int)((rswnc(data[18])*1.8)+32); if ( (temp_temp >= 32.0) && (temp_temp < 150.0) ) xastir_snprintf(wx_dew_point, sizeof(wx_dew_point), "%03d", (int)((rswnc(data[18])*1.8)+32)); else { fprintf(stderr,"Dew point out-of-range, ignoring: %0.2f\n", temp_temp); } break; case 0xbf: /* Rain */ // All data in mm. Convert to hundredths of an inch. xastir_snprintf(temp_data1, sizeof(temp_data1), "%02d%02d", rswnc(data[6]), rswnc(data[5])); temp_temp = (float)(atof(temp_data1) * 3.9370079); if ( (temp_temp >= 0) && (temp_temp < 51200.0) ) // Between 0 and 512 inches { xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", atof(temp_data1) * 3.9370079); /* Since local station only */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /* Last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /* Last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* Rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { fprintf(stderr,"Total Rain out-of-range, ignoring: %0.2f\n", temp_temp); } break; case 0xcf: /* Wind w/chill*/ /* get last gust speed */ if (strlen(weather->wx_gust) > 0) { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* all data in m/s */ /* average wind speed */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[5]&0xf), (float)( rswnc(data[4]) / 10 )); // Convert to mph xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (atof(temp_data1)*2.2369))); /* wind gust */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[2]&0xf), (float)( rswnc(data[1]) / 10 )); /*sprintf(weather->wx_gust,"%03d",(int)(0.5 + (atof(temp_data1)*2.2369)));*/ /* do computed gust, convert to mph */ computed_gust = compute_gust((int)(0.5 + (atof(temp_data1)*2.2369)), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); /* high wind gust */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[8]&0xf), (float)( rswnc(data[7]) / 10 )); xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%03d", (int)(0.5 + (atof(temp_data1)*2.2369))); wx_high_wind_on = 1; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03d", ( ((rswnc(data[3])*10) + ((data[2]&0xf0)>>4)) %1000 ) ); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } /* wind chill in C */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d", ((data[21]&0x20) ? '-' : '+'), rswnc(data[16])); temp_temp = (float)((atof(temp_data1)*1.8)+32); if ( (temp_temp > -200.0) && (temp_temp < 200.0) ) xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%03d", (int)((atof(temp_data1)*1.8)+32)); else { fprintf(stderr,"Wind_chill out-of-range, ignoring: %0.2f\n", temp_temp); } wx_wind_chill_on = 1; break; default: break; } if (strlen(weather->wx_hum) > 0 && strlen(weather->wx_temp) > 0) { /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=(-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2); xastir_snprintf(wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on=1; } else { wx_heat_index[0] = 0; } } // end of heat index calculation } // end of if (!from) break; // End of case for RSWX200 weather station /////////////////////////////////////////////////////////// // Davis WMII/WWIII/Vantage Pro via meteo & db2APRS // /////////////////////////////////////////////////////////// // Note: format is really APRS Spec 'positionless' WX string w/tag for X and Davis case(DAVISMETEO) : // todo - need to deal with lack of values, such as c...s...g...t045 string memset(weather->wx_course,0,4); // Keep out fradulent data... memset(weather->wx_speed,0,4); memset(weather->wx_temp,0,5); memset(weather->wx_rain,0,10); memset(weather->wx_prec_00,0,10); memset(weather->wx_prec_24,0,10); memset(weather->wx_rain_total,0,10); memset(weather->wx_hum,0,5); memset(weather->wx_baro,0,10); memset(weather->wx_station,0,MAX_WXSTATION); if ((temp_conv=strchr((char *)data,'c'))) // Wind Direction in Degrees { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%s", temp_conv+1); weather->wx_course[3] = '\0'; } // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } if ((temp_conv=strchr((char *)data,'s'))) // Wind Speed in MPH - not snowfall { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%s", temp_conv+1); weather->wx_speed[3] = '\0'; } if ((temp_conv=strchr((char *)data,'g'))) // Wind Gust in MPH { // Don't read if data is "..." (missing gust data) // If we aren't getting gust data from the station, don't clobber // the gust data we're computing! if (strncmp(temp_conv+1,"...",3) != 0) { memset(weather->wx_gust,0,4); // keep out fraudulent data xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%s", temp_conv+1); weather->wx_gust[3] = '\0'; // compute high wind if(wx_high_wind[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_gust) > atol(wx_high_wind))) // gust { xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%s", weather->wx_gust); } wx_high_wind_on=1; } } if ((temp_conv=strchr((char *)data,'t'))) // Temperature in Degrees F { xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%s", temp_conv+1); weather->wx_temp[3] = '\0'; // compute hi temp, since APRS doesn't send that if(wx_hi_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) > atol(wx_hi_temp))) { xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%s", weather->wx_temp); } wx_hi_temp_on=1; // compute low temp, since APRS doesn't send that if(wx_low_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) < atol(wx_low_temp))) { xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%s", weather->wx_temp); } wx_low_temp_on=1; } if ((temp_conv=strchr((char *)data,'r'))) // Rain per hour { xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%s", temp_conv+1); weather->wx_rain[3] = '\0'; } if ((temp_conv=strchr((char *)data,'p'))) // Rain per 24 hrs/total { xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%s", temp_conv+1); weather->wx_prec_24[3] = '\0'; } if ((temp_conv=strchr((char *)data,'P'))) // Rain since midnight { xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%s", temp_conv+1); weather->wx_prec_00[3] = '\0'; } if ((temp_conv=strchr((char *)data,'T'))) // Total Rain since { // wx station reset xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%s", temp_conv+1); weather->wx_rain_total[4] = '\0'; } // Ok, here's the deal --- if we got total rain AND we didn't get // rain-since-midnight, fix it up. // This is a problem with LaCrosse --- no rain-since-midnight // provided. Don't do anything at all if we didn't get total rain // from the station. compute_rain *depends* on "total rain" being // a strictly increasing number that is never reset to zero during // Xastir's run. if (strlen(weather->wx_rain_total) >0 ) { compute_rain((float)atof(weather->wx_rain_total)); if (weather->wx_prec_00[0] == '\0') { /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } // we are should be getting total rain from the station, but // we are also getting the rates. // Davis gives 24-hour, since-midnight, and 1-hour rates. // LaCrosse gives 24 and 1 hour. // Don't recompute what the station already gave us. weather->wx_compute_rain_rates=0; if ((temp_conv=strchr((char *)data,'h'))) // Humidity % { if (!strncmp(temp_conv+1,"00",2)) // APRS says 00 is { xastir_snprintf(weather->wx_hum, // 100% humidity sizeof(weather->wx_hum), "%s", "100"); weather->wx_hum[3] = '\0'; } else { xastir_snprintf(weather->wx_hum, // humidity less than sizeof(weather->wx_hum), // 100% "%s", temp_conv+1); weather->wx_hum[2] = '\0'; } } if ((temp_conv=strchr((char *)data,'b'))) // Air Pressure in 1/10 hPa { memset(temp_data1,0,sizeof(temp_data1)); xastir_snprintf(temp_data1, sizeof(temp_data1), "%s", temp_conv+1); temp_data1[5] = '\0'; temp_temp = (float)(atof(temp_data1))/10.0; xastir_snprintf(temp_data1, sizeof(temp_data1), "%0.1f", temp_temp); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%s", temp_data1); } if ((temp_conv=strchr((char *)data,'x'))) // WX Station Identifier { xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "%s", temp_conv+1); weather->wx_station[MAX_WXSTATION-1] = '\0'; } // now compute wind chill wind_chill = 35.74 + .6215 * atof(weather->wx_temp) - 35.75 * pow(atof(weather->wx_gust), .16) + .4275 * atof(weather->wx_temp) * pow(atof(weather->wx_gust), .16); if((wind_chill < atof(weather->wx_temp)) && (atof(weather->wx_temp) < 50)) { xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%.0f", wind_chill); wx_wind_chill_on = 1; } else { wx_wind_chill_on = 0; wx_wind_chill[0] = '\0'; } // The rest of the optional WX data is not used by // xastir (Luminosity, etc), except for snow, which // conflicts with wind speed (both are lower case 's') if (debug_level & 1) fprintf(stdout,"Davis Decode: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r00-%s,r24-%s,rt-%s,h-%s,ap-%s,station-%s\n", weather->wx_course,weather->wx_speed,weather->wx_gust, weather->wx_temp,weather->wx_rain,weather->wx_prec_00, weather->wx_prec_24,weather->wx_rain_total, weather->wx_hum,weather->wx_baro,weather->wx_station); break; // This is the output of the Davis APRS Data Logger. The format // is in fact exactly the same as a regular APRS weather packet, // complete with position information. Ignore that. // @xxxxxxzDDMM.mmN/DDDMM.mmW_CSE/SPDgGGGtTTTrRRRpRRRPRRRhXXbXXXXX.DsVP case (DAVISAPRSDL): memset(weather->wx_course,0,4); // Keep out fradulent data... memset(weather->wx_speed,0,4); memset(weather->wx_gust,0,4); memset(weather->wx_temp,0,5); memset(weather->wx_rain,0,10); memset(weather->wx_prec_00,0,10); memset(weather->wx_prec_24,0,10); memset(weather->wx_rain_total,0,10); memset(weather->wx_hum,0,5); memset(weather->wx_baro,0,10); memset(weather->wx_station,0,MAX_WXSTATION); if (sscanf((char *)data, "%*27s%3s/%3sg%3st%3sr%3sp%3sP%3sh%2sb%5s.DsVP", weather->wx_course, weather->wx_speed, weather->wx_gust, weather->wx_temp, weather->wx_rain, weather->wx_prec_24, weather->wx_prec_00, weather->wx_hum, weather->wx_baro) == 9) { // then we got all the data out of the packet... now process // First null-terminate all the strings: weather->wx_course[3]='\0'; weather->wx_speed[3]='\0'; weather->wx_gust[3]='\0'; weather->wx_temp[3]='\0'; weather->wx_rain[3]='\0'; weather->wx_prec_24[3]='\0'; weather->wx_prec_00[3]='\0'; weather->wx_hum[2]='\0'; weather->wx_baro[6]='\0'; // NOTE: Davis APRS Data Logger does NOT provide total rain, // and so data from compute_rain (which needs total rain) will // be wrong. Set this flag to stop that from clobbering our // good rain rate data. weather->wx_compute_rain_rates=0; // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } // compute high wind if(wx_high_wind[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_gust) > atol(wx_high_wind))) // gust { xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%s", weather->wx_gust); } wx_high_wind_on=1; // compute hi temp, since APRS doesn't send that if(wx_hi_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) > atol(wx_hi_temp))) { xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%s", weather->wx_temp); } wx_hi_temp_on=1; // compute low temp, since APRS doesn't send that if(wx_low_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) < atol(wx_low_temp))) { xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%s", weather->wx_temp); } wx_low_temp_on=1; // fix up humidity --- 00 in APRS means 100%: if (strncmp(weather->wx_hum,"00",2)==0) { weather->wx_hum[0]='1'; weather->wx_hum[1]=weather->wx_hum[2]='0'; weather->wx_hum[3]='\0'; } // fix up barometer. APRS sends in 10ths of millibars: temp_temp=(float)(atof(weather->wx_baro))/10.0; weather->wx_baro[0]='\0'; // zero out so snprintf doesn't append xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", temp_temp); // this should terminate Just Fine. // now compute wind chill wind_chill = 35.74 + .6215 * atof(weather->wx_temp) - 35.75 * pow(atof(weather->wx_gust), .16) + .4275 * atof(weather->wx_temp) * pow(atof(weather->wx_gust), .16); if((wind_chill < atof(weather->wx_temp)) && (atof(weather->wx_temp) < 50)) { xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%.0f", wind_chill); wx_wind_chill_on = 1; } else { wx_wind_chill_on = 0; wx_wind_chill[0] = '\0'; } xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "%s", (char *) &(data[63])); /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2; xastir_snprintf (wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on = 1; } else { wx_heat_index_on = 0; } if (debug_level & 1) fprintf(stdout,"Davis APRS DataLogger Decode $Revision$: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r24-%s,r00-%s,h-%s,ap-%s,station-%s\n", weather->wx_course,weather->wx_speed,weather->wx_gust, weather->wx_temp, weather->wx_rain, weather->wx_prec_24, weather->wx_prec_00,weather->wx_hum,weather->wx_baro, weather->wx_station); } break; } // End of big switch } // End of wx_fill_data() //********************************************************** // Decode WX data line // wx_line: raw wx data to decode // // This is called from main.c:UpdateTime() only. It // decodes data for serially-connected and network-connected // WX interfaces only. It calls wx_fill_data() to do the // real work once it figures out what type of data it has. //********************************************************** // // Note that the length of "wx_line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void wx_decode(unsigned char *wx_line, int data_length, int port) { DataRow *p_station; int decoded; int find; int i; int len; char time_data[MAX_TIME]; unsigned int check_sum; int max; WeatherRow *weather; float t1,t2,t3,t4,t5,t6,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19; int t7,t8; //fprintf(stderr,"wx_decode: %s\n",wx_line); //fprintf(stderr,"\nwx_decode: %d bytes\n", data_length); find=0; len = data_length; if (len == 0) { len=strlen((char *)wx_line); } if (len>10 || ((int)wx_line[0]!=0 && port_data[port].data_type==1)) { if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // DK7IN: only add record if we found something... { weather = p_station->weather_data; decoded=0; /* Ok decode wx data */ if (wx_line[0]=='!' && wx_line[1]=='!' && is_xnum_or_dash((char *)(wx_line+2),40) && port_data[port].data_type==0) { /* Found Peet Bros U-2k */ if (debug_level & 1) { fprintf(stderr,"Found Peet Bros U-2k WX:%s\n",wx_line+2); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI011")); xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,APRS_WX3,wx_line,p_station); decoded=1; } else if (((wx_line[0]=='#') || (wx_line[0]=='*')) && is_xnum_or_dash((char *)(wx_line+1),13) && port_data[port].data_type==0) { /* Found Peet Bros raw U2 data */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI012")); if (debug_level & 1) { fprintf(stderr,"Found Peet Bros raw U2 data WX#:%s\n",wx_line+1); } xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; if (wx_line[0]=='#') // Wind speed in km/h { wx_fill_data(0,APRS_WX4,wx_line,p_station); } else // '*', Wind speed in mph { wx_fill_data(0,APRS_WX6,wx_line,p_station); } decoded=1; } else if (strncmp("$ULTW",(char *)wx_line,5)==0 && is_xnum_or_dash((char *)(wx_line+5),44) && port_data[port].data_type==0) { /* Found Peet Bros raw U2 data */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI013")); if (debug_level & 1) { fprintf(stderr,"Found Peet Bros Ultimeter Packet data WX#:%s\n",wx_line+5); } xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,APRS_WX5,wx_line,p_station); decoded=1; } else if (wx_line[2]==' ' && wx_line[5]==' ' && wx_line[8]=='/' && wx_line[11]=='/' && wx_line[14]==' ' && wx_line[17]==':' && wx_line[20]==':' && strncmp(" #0:",(char *)wx_line+23,4)==0 && port_data[port].data_type==0) { find=0; for (i=len; i>23 && !find; i--) { if ((int)wx_line[i]==0x03) { find=1; wx_line[i] = 0; } } if (find) { /* found Qualimetrics Q-Net station */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI016")); if (debug_level & 1) { fprintf(stderr,"Found Qualimetrics Q-Net station data WX#:%s\n",wx_line+23); } xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,QM_WX,wx_line+24,p_station); decoded=1; } } //WE7U // else look for ten ASCII decimal point chars in the input, or do an // sscanf looking for the correct number and types of fields for the // OWW server in ARNE mode. 6 %f's, 2 %d's, 11 %f's. else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12,&t13,&t14,&t15,&t16,&t17,&t18,&t19) == 19) { // Found Dallas One-Wire Weather Station if (debug_level & 1) { fprintf(stderr,"Found OWW ARNE-mode(19) one-wire weather station data\n"); } weather->wx_sec_time=sec_now(); wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station); decoded=1; } else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12) == 12) { // Found Dallas One-Wire Weather Station if (debug_level & 1) { fprintf(stderr,"Found OWW ARNE-mode(12) one-wire weather station data\n"); } weather->wx_sec_time=sec_now(); wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station); decoded=1; } else if (strncmp("&CR&",(char *)wx_line,4)==0 && is_xnum_or_dash((char *)(wx_line+5),44) && port_data[port].data_type==0) { if (debug_level & 1) { fprintf(stderr,"Found Peet Complete station data\n"); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI017")); xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,PEET_COMPLETE,wx_line,p_station); decoded=1; } else if (port_data[port].data_type==1) { // int jj; /* binary data type */ if (debug_level & 1) { fprintf(stderr,"Found binary data: %d bytes\n", len); } /* clear raw string */ memset(raw_wx_string,0,sizeof(raw_wx_string)); max=0; switch (wx_line[0]) { case 0x8f: max=34; break; case 0x9f: max=33; break; case 0xaf: max=30; break; case 0xbf: max=13; break; case 0xcf: max=26; break; default: break; } // fprintf(stderr, "wx_decode binary: "); // for (jj = 0; jj < len+1; jj++) { // fprintf(stderr, "%02x ", wx_line[jj]); // } // fprintf(stderr, "\n"); // fprintf(stderr, "Integers: "); // for (jj = 0; jj < max+1; jj++) { // fprintf(stderr, "%0d ", wx_line[jj]); // } // fprintf(stderr, "\n"); if (len < (max+1)) { fprintf(stderr, " Short NET_WX packet, %d bytes\n", len); } if (max > 0 && len >= (max+1) ) { // Compute the checksum from the data check_sum = 0; for (i = 0; i < max; i++) { check_sum += wx_line[i]; } // fprintf(stderr," Checksum: 0x%02x ", 0x0ff & check_sum); if ( wx_line[max] == (0xff & check_sum) ) { /* good RS WX-200 data */ //fprintf(stderr,"GOOD RS WX-200 %0X data\n",wx_line[0]); /* found RS WX-200 */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI025")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,RSWX200,wx_line,p_station); decoded=1; } else { // fprintf(stderr, "bad"); } } } else if (wx_line[0]=='@' && strncmp((char *)&(wx_line[63]),".DsVP",5)==0) { // this is a Davis Vantage Pro with APRS Data Logger if (debug_level & 1) { fprintf(stdout,"Davis VP APRS Data Logger data found ... %s\n", wx_line); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI028")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); wx_fill_data(0,DAVISAPRSDL,wx_line,p_station); decoded=1; } else // ASCII data of undetermined type { // Davis Weather via meteo -> db2APRS -> TCP port if (strstr((const char *)wx_line, "xDvs")) // APRS 'postionless' WX data w/ Davis & X tag { if (debug_level & 1) { fprintf(stdout,"Davis Data found... %s\n",wx_line); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI026")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); wx_fill_data(0,DAVISMETEO,wx_line,p_station); decoded=1; } else if (debug_level & 1) { fprintf(stderr,"Unknown WX DATA:%s\n",wx_line); } } if (decoded) { /* save data back */ if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].decode_errors=0; if (end_critical_section(&port_data_lock, "wx.c:wx_decode(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } statusline(langcode("BBARSTA032"),1); // Decoded WX Data /* redraw now */ //redraw_on_new_data=2; redraw_on_new_data=1; fill_wx_data(); } else { /* Undecoded packet */ memset(raw_wx_string,0,sizeof(raw_wx_string)); if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].decode_errors++; // We have errors in decoding if (port_data[port].decode_errors>10) { /* wrong data type? */ port_data[port].data_type++; // Try another data type. 0=ascii, 1=wx binary port_data[port].data_type&=0x01; /*if (debug_level & 1)*/ fprintf(stderr,"Data type %d\n",port_data[port].data_type); port_data[port].decode_errors=0; } if (end_critical_section(&port_data_lock, "wx.c:wx_decode(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } } } } } /***********************************************************/ /* fill string with WX data for transmit */ /* */ /***********************************************************/ time_t wx_tx_data1(char *st, int st_size) { DataRow *p_station; time_t wx_time; char temp[100]; WeatherRow *weather; st[0] = '\0'; wx_time = 0; if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // station has wx data { weather = p_station->weather_data; //WE7U: For debugging purposes only //weather->wx_sec_time=sec_now(); //sprintf(weather->wx_course,"359"); // degrees //sprintf(weather->wx_speed,"001"); // mph //sprintf(weather->wx_gust,"010"); // mph //sprintf(weather->wx_temp,"069"); // Fahrenheit //if ( strlen(weather->wx_rain_total) == 0) // sprintf(weather->wx_rain_total,"1900.40"); //sprintf(weather->wx_rain_total,"1987.6"); // hundredths of an inch //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain_total,"1988.6"); //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain_total,"1990.6"); //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain,"%0.2f",rain_minute_total); //sprintf(weather->wx_prec_24,"%0.2f",rain_24); //sprintf(weather->wx_prec_00,"%0.2f",rain_00); //sprintf(weather->wx_rain,"0"); // hundredths of an inch //sprintf(weather->wx_prec_00,"0"); // hundredths of an inch //sprintf(weather->wx_prec_24,"0"); // hundredths of an inch //sprintf(weather->wx_hum,"92"); // % //sprintf(weather->wx_baro,"1013.0"); // hPa //weather->wx_type = WX_TYPE; //xastir_snprintf(weather->wx_station,sizeof(weather->wx_station),"RSW"); // 359/000g000t065r010P020p030h92b01000 if (strlen(weather->wx_course) > 0 && strlen(weather->wx_speed) > 0) { // We have enough wx_data wx_time=weather->wx_sec_time; xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_course); if (strlen(temp) > 3) { if (debug_level & 1) { fprintf(stderr,"wx_course too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "..."); } if ( (atoi(weather->wx_course) > 360) || (atoi(weather->wx_course) < 0) ) { if (debug_level & 1) { fprintf(stderr,"wx_course out-of-range: %s\n", weather->wx_course); } xastir_snprintf(temp, sizeof(temp), "..."); } //sprintf(st,"%s/%s",weather->wx_course,weather->wx_speed); strncat(st, temp, st_size - 1 - strlen(st)); strncat(st, "/", st_size - 1 - strlen(st)); xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_speed); if (strlen(temp) > 3) { if (debug_level & 1) { fprintf(stderr,"wx_speed too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "..."); } if ( (atoi(weather->wx_speed) < 0) || (atoi(weather->wx_speed) > 999) ) { if (debug_level & 1) { fprintf(stderr,"wx_speed out-of-range: %s\n", weather->wx_speed); } xastir_snprintf(temp, sizeof(temp), "..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // We don't have enough wx_data, may be from a Qualimetrics Q-Net? wx_time=weather->wx_sec_time; xastir_snprintf(st, st_size, ".../..."); if (debug_level & 1) { fprintf(stderr,"\n\nAt least one field was empty: Course: %s\tSpeed: %s\n", weather->wx_course, weather->wx_speed); fprintf(stderr,"Will be sending '.../...' instead of real values.\n\n\n"); } } if (strlen(weather->wx_gust) > 0) { xastir_snprintf(temp, sizeof(temp), "g%s", weather->wx_gust); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_gust too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "g..."); } if (atoi(weather->wx_gust) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_gust out-of-range: %s\n", weather->wx_gust); } xastir_snprintf(temp, sizeof(temp), "g..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { strncat(st, "g...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_temp) > 0) { xastir_snprintf(temp, sizeof(temp), "t%s", weather->wx_temp); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_temp too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "t..."); } if ( (atoi(weather->wx_temp) > 999) || (atoi(weather->wx_temp) < -99) ) { if (debug_level & 1) { fprintf(stderr,"wx_temp out-of-bounds: %s\n", weather->wx_temp); } xastir_snprintf(temp, sizeof(temp), "t..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { strncat(st, "t...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_rain) > 0) { xastir_snprintf(temp, sizeof(temp), "r%03d", (int)(atof(weather->wx_rain) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_rain too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "r "); } if (atoi(weather->wx_rain) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_rain out-of-bounds: %s\n", weather->wx_rain); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "r..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "r...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_prec_00) > 0) { xastir_snprintf(temp, sizeof(temp), "P%03d", (int)(atof(weather->wx_prec_00) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_prec_00 too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "P "); } if (atoi(weather->wx_prec_00) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_prec_00 out-of-bounds: %s\n", weather->wx_prec_00); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "P..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "P...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_prec_24) > 0) { xastir_snprintf(temp, sizeof(temp), "p%03d", (int)(atof(weather->wx_prec_24) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_prec_24 too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "p "); } if (atoi(weather->wx_prec_24) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_prec_24 out-of-bounds: %s\n", weather->wx_prec_24); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "p..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "p...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_hum) > 0) { if (atoi(weather->wx_hum)>99) { xastir_snprintf(temp, sizeof(temp), "h00"); } else xastir_snprintf(temp, sizeof(temp), "h%02d", atoi(weather->wx_hum)); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_hum too long: %s\n", temp); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"h.."); } if (atoi(weather->wx_hum) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_hum out-of-bounds: %s\n", weather->wx_hum); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"h.."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "h..", st_size - 1 - strlen(st)); } if (strlen(weather->wx_baro) > 0) { xastir_snprintf(temp, sizeof(temp), "b%05d", (int)((atof(weather->wx_baro) * 10.0)) ); if (strlen(temp)>6) { if (debug_level & 1) { fprintf(stderr,"wx_baro too long: %s\n", temp); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"b....."); } if ((int)((atof(weather->wx_baro) * 10.0) < 0)) { if (debug_level & 1) { fprintf(stderr,"wx_baro out-of-bounds: %s\n", weather->wx_baro); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"b....."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "b.....", st_size - 1 - strlen(st)); } xastir_snprintf(temp, sizeof(temp), "%c%s", weather->wx_type, weather->wx_station); strncat(st, temp, st_size - 1 - strlen(st)); } } if (debug_level & 1) { fprintf(stderr,"Weather String: %s\n", st); } return(wx_time); } /***********************************************************/ /* transmit raw wx data */ /* */ /***********************************************************/ void tx_raw_wx_data(void) { if (strlen(raw_wx_string)>10) { output_my_data(raw_wx_string,-1,0,0,0,NULL); if (debug_level & 1) { fprintf(stderr,"Sending Raw WX data <%s>\n",raw_wx_string); } } } Xastir-Release-2.2.2/src/wx.h000066400000000000000000000047651501463444000157600ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_WX_H #define __XASTIR_WX_H #include "database.h" extern void fill_wx_data(void); extern Widget GetTopShell(Widget w); extern void pos_dialog(Widget w); extern char wx_station_type[]; /* from wx.c */ extern char wx_dew_point[10]; extern char wx_dew_point_on; extern char wx_high_wind[10]; extern char wx_high_wind_on; extern char wx_wind_chill[10]; extern char wx_wind_chill_on; extern char wx_three_hour_baro[10]; // hPa extern char wx_three_hour_baro_on; // hPa extern char wx_hi_temp[10]; extern char wx_hi_temp_on; extern char wx_low_temp[10]; extern char wx_low_temp_on; extern char wx_heat_index[10]; extern char wx_heat_index_on; extern char wx_station_type[]; /* from wx.c */ extern time_t wx_tx_data1(char *st, int st_size); extern void wx_decode(unsigned char *wx_line, int data_length, int port); extern void fill_wx_data(void); extern void clear_rain_data(void); extern void tx_raw_wx_data(void); extern void clear_local_wx_data(void); extern void wx_last_data_check(void); extern void wx_fill_data(int from, int type, unsigned char *data, DataRow *fill); extern void decode_U2000_L(int from, unsigned char *data, WeatherRow *weather); extern void decode_U2000_P(int from, unsigned char *data, WeatherRow *weather); extern void decode_Peet_Bros(int from, unsigned char *data, WeatherRow *weather, int type); extern void cycle_weather(void); /* wx_gui.c */ extern void wx_alert_update_list(void); extern void WX_station(Widget w, XtPointer clientData, XtPointer callData); extern void wx_alert_finger_output( Widget widget, char *handle); #endif // __XASTIR_WX_H Xastir-Release-2.2.2/src/wx_gui.c000066400000000000000000002704441501463444000166160ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "wx.h" #include "main.h" #include "alert.h" #include "lang.h" #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist /************ Weather Alerts ****************/ Widget wx_alert_shell = (Widget)NULL; Widget wx_detailed_alert_shell = (Widget)NULL; static Widget wx_alert_list; static xastir_mutex wx_alert_shell_lock; static xastir_mutex wx_detailed_alert_shell_lock; static xastir_mutex wx_station_dialog_lock; void wx_gui_init(void) { init_critical_section( &wx_alert_shell_lock ); init_critical_section( &wx_detailed_alert_shell_lock ); init_critical_section( &wx_station_dialog_lock ); } void wx_detailed_alert_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_detailed_alert_destroy_shell" ); XtDestroyWidget(shell); wx_detailed_alert_shell = (Widget)NULL; end_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_detailed_alert_destroy_shell" ); } // This gets/displays the "finger" output from the WXSVR. Called // from both the Station Info "NWS" button and by double-clicking on // the view weather alerts window. // void wx_alert_finger_output( Widget UNUSED(widget), char *handle) { static Widget pane, scrollwindow, my_form, mess, button_cancel,wx_detailed_alert_list; Atom delw; Arg al[50]; // Arg List unsigned int ac = 0; // Arg Count char temp[1024]; XmString item; FILE *fd; int ret; int server_fd; struct sockaddr_in serv_addr; struct hostent *serverhost; if (debug_level & 1) { fprintf(stderr,"Handle: %s\n",handle); } if(!wx_detailed_alert_shell) { begin_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_alert_double_click_action" ); wx_detailed_alert_shell = XtVaCreatePopupShell(langcode("WPUPWXA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 600, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("wx_alert_double_click_action pane",xmPanedWindowWidgetClass, wx_detailed_alert_shell, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("wx_alert_double_click_action my_form", xmFormWidgetClass, scrollwindow, XmNtraversalOn, TRUE, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNwidth, 600, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); mess = XtVaCreateManagedWidget(langcode("WPUPWXA002"), xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNvisualPolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNscrollingPolicy,XmAUTOMATIC); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNscrollBarDisplayPolicy,XmAS_NEEDED); ac++; XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, mess); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomOffset, 45); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; wx_detailed_alert_list = XmCreateScrolledList(my_form, "wx_alert_double_click_action wx_detailed_alert_list", al, ac); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, wx_detailed_alert_destroy_shell, wx_detailed_alert_shell); end_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_alert_double_click_action" ); pos_dialog(wx_detailed_alert_shell); delw = XmInternAtom(XtDisplay(wx_detailed_alert_shell), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_detailed_alert_shell, delw, wx_detailed_alert_destroy_shell, (XtPointer)wx_detailed_alert_shell); XtManageChild(my_form); XtManageChild(wx_detailed_alert_list); XtVaSetValues(wx_detailed_alert_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, wx_detailed_alert_shell); XtPopup(wx_detailed_alert_shell, XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(wx_detailed_alert_shell); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(wx_detailed_alert_shell), XtWindow(wx_detailed_alert_shell)); } // Erase the entire list before we start writing to it in // case it was left up from a previous query. XmListDeleteAllItems(wx_detailed_alert_list); // Perform a "finger" command, which is really just a telnet // with a single line command sent to the remote host, then a // bunch of text sent back. We implement it here via our own // TCP code, as it's really very simple. // Allocate a socket for our use if ((server_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { // fprintf(stderr,"wx_alert_finger_output: can't get socket\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: can't get socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); return; } memset(&serv_addr, 0, sizeof(serv_addr)); // Changing Finger host because WXSVR.net has been down for a // month or more and Pete, AE5PL, has a replacement online that // performs this function. //serverhost = gethostbyname("wxsvr.net"); serverhost = gethostbyname("wx.aprs-is.net"); if (serverhost == (struct hostent *)0) { // fprintf(stderr,"wx_alert_finger_output: gethostbyname failed\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: gethostbyname failed"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } memmove(&serv_addr.sin_addr,serverhost->h_addr, (size_t)serverhost->h_length); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(79); // Finger protocol uses port 79 if (connect(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { // fprintf(stderr,"wx_alert_finger_output: connect to server failed\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: connect to server failed"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Create a file descriptor for the socket fd = fdopen(dup(server_fd),"wb"); if (fd == NULL) { // fprintf(stderr,"Couldn't create duplicate write socket\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't create duplicate write socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Set up the text we're going to send to the remote finger // server. xastir_snprintf(temp, sizeof(temp), "%s\r\n", handle); // Send the request text out the socket ret = fprintf(fd, "%s", temp); if (ret == 0 || ret == -1) { // fprintf(stderr,"Couldn't send finger command to wxsvr\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't send finger command to wxsvr"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)fclose(fd); (void)close(server_fd); // Close the socket return; } // Close the duplicate port we used for writing (void)fclose(fd); // // Read back the results from the socket // // Create a file descriptor for the socket fd = fdopen(dup(server_fd),"rb"); if (fd == NULL) { // fprintf(stderr,"Couldn't create duplicate read socket\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't create duplicate read socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Process the data we received from the remote finger server // while (fgets (temp, sizeof (temp), fd)) // While we have data to process { char *ptr; // Remove any linefeeds or carriage returns from each // string. ptr = temp; while ( (ptr = strpbrk(temp, "\n\r")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); } if (debug_level & 1) { fprintf(stderr,"%s\n",temp); } // Create an XmString for each line and add it to the // end of the list. item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); } // All done! fclose(fd); (void)close(server_fd); // Close the socket } void wx_alert_double_click_action( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { char *choice; XmListCallbackStruct *selection = callData; char handle[14]; char *ptr; XmStringGetLtoR(selection->item, XmFONTLIST_DEFAULT_TAG, &choice); //fprintf(stderr,"Selected item %d (%s)\n", selection->item_position, choice); // Grab the first 13 characters. Remove spaces. This is our handle // into the weather server for the full weather alert text. xastir_snprintf(handle, sizeof(handle), "%s", choice); XtFree(choice); // Release as soon as we're done! handle[13] = '\0'; // Terminate the string // Remove spaces ptr = handle; while ( (ptr = strpbrk(handle, " ")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); } handle[9] = '\0'; // Terminate after first 9 chars if (debug_level & 1) { fprintf(stderr,"Handle: %s\n",handle); } wx_alert_finger_output( widget, handle); } void wx_alert_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_destroy_shell" ); XtDestroyWidget(shell); wx_alert_shell = (Widget)NULL; end_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_destroy_shell" ); } static int alert_comp(const void *a, const void *b) { alert_entry *a_entry = *(alert_entry **)a; alert_entry *b_entry = *(alert_entry **)b; int a_active, b_active; if (a_entry->title[on_screen] && !b_entry->title[on_screen]) { return (-1); } if (!a_entry->title[0] && b_entry->title[0]) { return (1); } if (a_entry->flags[on_screen] == 'Y' && b_entry->flags[on_screen] != 'Y') { return (-1); } if (a_entry->flags[on_screen] != 'Y' && b_entry->flags[on_screen] == 'Y') { return (1); } if (a_entry->flags[on_screen] == '?' && b_entry->flags[on_screen] == 'N') { return (-1); } if (a_entry->flags[on_screen] == 'N' && b_entry->flags[on_screen] == '?') { return (1); } a_active = alert_active(a_entry, ALERT_ALL); b_active = alert_active(b_entry, ALERT_ALL); if (a_active && b_active) { if (a_active - b_active) { return (a_active - b_active); } } else if (a_active) { return (-1); } else if (b_active) { return (1); } return (strcmp(a_entry->title, b_entry->title)); } void wx_alert_update_list(void) { int nn; // index into alert table. Starts at 0 int ii; // index into dialog lines. Starts at 1 int max_item_count; // max dialog lines char temp[600]; XmString item; static alert_entry **alert_list; static int alert_list_limit; if (wx_alert_shell) { struct hashtable_itr *iterator; alert_entry *alert; begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_update_list" ); // Get the previous alert count from the alert list window XtVaGetValues(wx_alert_list, XmNitemCount, &max_item_count, NULL); if ((nn = alert_list_count()) > alert_list_limit) { alert_entry **tmp = realloc(alert_list, nn * sizeof(alert_entry *)); if (tmp) { alert_list = tmp; alert_list_limit = nn; } else { fprintf(stderr, "wx_gui: Alert list allocation error\n"); exit(1); } } // Iterate through the alert hash. Create a string for each // non-expired/non-blank entry. iterator = create_wx_alert_iterator(); for (nn = 0, alert = get_next_wx_alert(iterator); iterator != NULL && alert; alert = get_next_wx_alert(iterator)) { // Check whether alert record is empty/filled. This // code is from the earlier array implementation. If // we're expiring records from our hash properly we // probably don't need this anymore. // // if (alert->title[0] == '\0') { // It's empty // fprintf(stderr, "wx_gui:alert->title NULL\n"); // break; // } alert_list[nn++] = alert; } qsort(alert_list, nn, sizeof(alert_entry *), alert_comp); for (ii = 0; ii < nn; ) { alert = alert_list[ii]; // AFGNPW NWS-WARN Until: 191500z AK_Z213 WIND P7IAA // TSATOR NWS-ADVIS Until: 190315z OK_C127 TORNDO H2VAA //xastir_snprintf(temp, sizeof(temp), "%-9s %-9s Until: %-7s %-7s %-20s %s", xastir_snprintf(temp, sizeof(temp), "%-9s %-5s %-9s %c%c @%c%c%c%cz ==> %c%c @%c%c%c%cz %c%c %-7s %s %s%s%s%s", alert->from, alert->seq, alert->to, alert->issue_date_time[0], alert->issue_date_time[1], alert->issue_date_time[2], alert->issue_date_time[3], alert->issue_date_time[4], alert->issue_date_time[5], alert->activity[0], alert->activity[1], alert->activity[2], alert->activity[3], alert->activity[4], alert->activity[5], alert->flags[on_screen], alert->flags[source], alert->title, alert->alert_tag, alert->desc0, alert->desc1, alert->desc2, alert->desc3); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); ii++; // It looks like if we are higher than 'max_item_count', // it must be a new entry that we haven't written to the // window yet. Add it. if (max_item_count < ii) { XmListAddItemUnselected(wx_alert_list, item, 0); } else { // Replace it in the window. Note: This might re-order the list each time. XmListReplaceItemsPos(wx_alert_list, &item, 1, ii); } XmStringFree(item); } // End of for loop #ifndef USING_LIBGC //fprintf(stderr,"free iterator 9\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC // If we have fewer alerts now, delete the extras from the window if (ii < max_item_count) { XmListDeleteItemsPos(wx_alert_list, max_item_count - ii, ii+1); } end_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_update_list" ); } } void Display_Wx_Alert( Widget UNUSED(wdgt), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, mess, button_cancel; Atom delw; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ if(!wx_alert_shell) { begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:Display_Wx_Alert" ); wx_alert_shell = XtVaCreatePopupShell(langcode("WPUPWXA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 600, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Display_Wx_Alert pane",xmPanedWindowWidgetClass, wx_alert_shell, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Display_Wx_Alert my_form", xmFormWidgetClass, scrollwindow, XmNtraversalOn, TRUE, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNwidth, 600, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); mess = XtVaCreateManagedWidget(langcode("WPUPWXA002"), xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; // XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNvisualPolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNscrollingPolicy,XmAUTOMATIC); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNscrollBarDisplayPolicy,XmAS_NEEDED); ac++; // XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++; XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++; // XtSetArg(al[ac], XmNlistSizePolicy, XmVARIABLE); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, mess); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomOffset, 45); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; wx_alert_list = XmCreateScrolledList(my_form, "Display_Wx_Alert wx_alert_list", al, ac); end_critical_section(&wx_alert_shell_lock, "wx_gui.c:Display_Wx_Alert" ); wx_alert_update_list(); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, // XmNtopOffset, 265, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, wx_alert_destroy_shell, wx_alert_shell); XtAddCallback(wx_alert_list, XmNdefaultActionCallback, wx_alert_double_click_action, NULL); pos_dialog(wx_alert_shell); delw = XmInternAtom(XtDisplay(wx_alert_shell), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_alert_shell, delw, wx_alert_destroy_shell, (XtPointer)wx_alert_shell); XtManageChild(my_form); XtManageChild(wx_alert_list); XtVaSetValues(wx_alert_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, wx_alert_shell); XtPopup(wx_alert_shell, XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(wx_alert_shell); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(wx_alert_shell), XtWindow(wx_alert_shell)); } } /* Display_Wx_Alert */ ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /**** WX Station *******/ Widget wx_station_dialog=(Widget)NULL; Widget WX_type_data; Widget WX_temp_data; Widget WX_wind_cse_data; Widget WX_wind_spd_data; Widget WX_wind_gst_data; Widget WX_rain_data; Widget WX_to_rain_data; Widget WX_rain_h_data; Widget WX_rain_24_data; Widget WX_humidity_data; Widget WX_speed_label; Widget WX_gust_label; Widget WX_temp_label; Widget WX_rain_label; Widget WX_to_rain_label; Widget WX_rain_h_label; Widget WX_rain_24_label; Widget WX_dew_point_data; Widget WX_high_wind_data; Widget WX_wind_chill_data; Widget WX_heat_index_data; Widget WX_baro_data; Widget WX_baro_label; Widget WX_three_hour_baro_data; Widget WX_three_hour_baro_label; Widget WX_hi_temp_data; Widget WX_low_temp_data; Widget WX_dew_point_label; Widget WX_wind_chill_label; Widget WX_heat_index_label; Widget WX_hi_temp_label; Widget WX_low_temp_label; Widget WX_high_wind_label; void WX_station_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station_destroy_shell" ); XtDestroyWidget(shell); wx_station_dialog = (Widget)NULL; end_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station_destroy_shell" ); } void WX_station_change_data(Widget widget, XtPointer clientData, XtPointer callData) { WX_station_destroy_shell(widget,clientData,callData); } // This is the "Own Weather Station" Dialog // void WX_station( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, form1, button_close, frame, WX_type, temp, wind_cse, wind_spd, wind_gst, my_rain, to_rain, rain_h, my_rain_24, baro, dew_point, high_wind, wind_chill, heat_index, three_hour_baro, hi_temp; Atom delw; if(!wx_station_dialog) { begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station" ); wx_station_dialog = XtVaCreatePopupShell(langcode("WXPUPSI000"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("WX_station pane",xmPanedWindowWidgetClass, wx_station_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("WX_station my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase,7, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); WX_type = XtVaCreateManagedWidget(langcode("WXPUPSI001"),xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_type_data = XtVaCreateManagedWidget("WX_station type data", xmTextFieldWidgetClass, my_form, XmNtraversalOn, FALSE, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 70, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, WX_type, XmNleftOffset, 5, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 30, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("WX_station frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, WX_type_data, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // sts (void)XtVaCreateManagedWidget(langcode("WXPUPSI002"),xmLabelWidgetClass,frame, XmNtraversalOn, FALSE, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form1 = XtVaCreateWidget("WX_station form1",xmFormWidgetClass, frame, XmNtraversalOn, FALSE, XmNfractionBase, 7, XmNbackground, colors[0xff], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, NULL); wind_cse = XtVaCreateManagedWidget(langcode("WXPUPSI003"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_cse_data = XtVaCreateManagedWidget("WX_station wc data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // wind_deg (void)XtVaCreateManagedWidget(langcode("UNIOP00024"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_cse_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_spd = XtVaCreateManagedWidget(langcode("WXPUPSI004"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_spd_data = XtVaCreateManagedWidget("WX_station ws data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_speed_label= XtVaCreateManagedWidget("WX_station speed label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_spd_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_gst = XtVaCreateManagedWidget(langcode("WXPUPSI005"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_gst_data = XtVaCreateManagedWidget("WX_station wg data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_gust_label= XtVaCreateManagedWidget("WX_station gust label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_gst_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); temp = XtVaCreateManagedWidget(langcode("WXPUPSI006"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_temp_data = XtVaCreateManagedWidget("WX_station temp data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 8, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_temp_label= XtVaCreateManagedWidget("WX_station temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_temp_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); my_rain = XtVaCreateManagedWidget(langcode("WXPUPSI007"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, temp, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_data = XtVaCreateManagedWidget("WX_station rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, temp, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_label= XtVaCreateManagedWidget("WX_station rain label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, temp, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); to_rain = XtVaCreateManagedWidget(langcode("WXPUPSI008"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_to_rain_data = XtVaCreateManagedWidget("WX_station today rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_to_rain_label= XtVaCreateManagedWidget("WX_station to label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_to_rain_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); rain_h = XtVaCreateManagedWidget(langcode("WXPUPSI014"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_h_data = XtVaCreateManagedWidget("WX_station hour rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_h_label= XtVaCreateManagedWidget("WX_station hour label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_h_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); my_rain_24 = XtVaCreateManagedWidget(langcode("WXPUPSI015"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_24_data = XtVaCreateManagedWidget("WX_station 24h rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_24_label= XtVaCreateManagedWidget("WX_station 24h label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_24_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // humidity (void)XtVaCreateManagedWidget(langcode("WXPUPSI010"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_humidity_data = XtVaCreateManagedWidget("WX_station Humidity data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 8, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // humidity_n (void)XtVaCreateManagedWidget(langcode("UNIOP00026"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_humidity_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); dew_point = XtVaCreateManagedWidget(langcode("WXPUPSI018"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_dew_point_data = XtVaCreateManagedWidget("WX_station dew point", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,1, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_dew_point_label = XtVaCreateManagedWidget("WX_station dew label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_dew_point_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); high_wind = XtVaCreateManagedWidget(langcode("WXPUPSI019"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dew_point, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_high_wind_data = XtVaCreateManagedWidget("WX_station High Wind", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive, TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, dew_point, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_high_wind_label = XtVaCreateManagedWidget("WX_station high wind label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,dew_point, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_high_wind_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_chill = XtVaCreateManagedWidget(langcode("WXPUPSI020"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, high_wind, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_chill_data = XtVaCreateManagedWidget("WX_station Wind Chill", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, high_wind, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_wind_chill_label = XtVaCreateManagedWidget("WX_station wind label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,high_wind, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_chill_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); heat_index = XtVaCreateManagedWidget(langcode("WXPUPSI021"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_chill, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_heat_index_data = XtVaCreateManagedWidget("WX_station Heat Index", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_chill, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_heat_index_label = XtVaCreateManagedWidget("WX_station heat label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,wind_chill, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_heat_index_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); baro = XtVaCreateManagedWidget(langcode("WXPUPSI009"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, heat_index, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_baro_data = XtVaCreateManagedWidget("WX_station Baro", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, heat_index, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_baro_label = XtVaCreateManagedWidget("WX_Station baro unit label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,heat_index, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_baro_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); three_hour_baro = XtVaCreateManagedWidget(langcode("WXPUPSI022"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_three_hour_baro_data = XtVaCreateManagedWidget("WX_station 3-Hr Baro", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_three_hour_baro_label = XtVaCreateManagedWidget("WX_station 3hr baro unit label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_three_hour_baro_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); hi_temp = XtVaCreateManagedWidget(langcode("WXPUPSI023"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hi_temp_data = XtVaCreateManagedWidget("WX_station Today's High Temp", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_hi_temp_label = XtVaCreateManagedWidget("WX_station high temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_hi_temp_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // low_temp (void)XtVaCreateManagedWidget(langcode("WXPUPSI024"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_low_temp_data = XtVaCreateManagedWidget("WX_station Today's Low Temp", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_low_temp_label = XtVaCreateManagedWidget("WX_station low temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_low_temp_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, WX_station_destroy_shell, wx_station_dialog); pos_dialog(wx_station_dialog); delw = XmInternAtom(XtDisplay(wx_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_station_dialog, delw, WX_station_destroy_shell, (XtPointer)wx_station_dialog); XtManageChild(my_form); XtManageChild(form1); XtManageChild(pane); resize_dialog(my_form, wx_station_dialog); end_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station" ); XtPopup(wx_station_dialog,XtGrabNone); fill_wx_data(); } else { (void)XRaiseWindow(XtDisplay(wx_station_dialog), XtWindow(wx_station_dialog)); } } void fill_wx_data(void) { DataRow *p_station; char temp[20]; WeatherRow *weather; if (wx_station_dialog != NULL) { begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:fill_wx_data" ); if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // DK7IN: only add record if we found something... { weather = p_station->weather_data; if (strlen(wx_station_type) > 1) { XmTextFieldSetString(WX_type_data,wx_station_type); } else { XmTextFieldSetString(WX_type_data,""); } XtManageChild(WX_type_data); if (weather != 0) // we have weather data { if (strlen(weather->wx_temp) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(weather->wx_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_temp_data,temp); } else { XmTextFieldSetString(WX_temp_data,weather->wx_temp); } } else { XmTextFieldSetString(WX_temp_data,""); } XtManageChild(WX_temp_data); if (strlen(weather->wx_course) > 0) { XmTextFieldSetString(WX_wind_cse_data,weather->wx_course); } else { XmTextFieldSetString(WX_wind_cse_data,""); } XtManageChild(WX_wind_cse_data); if (strlen(weather->wx_speed) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(weather->wx_speed)*1.6094)); XmTextFieldSetString(WX_wind_spd_data,temp); } else { XmTextFieldSetString(WX_wind_spd_data,weather->wx_speed); } } else { XmTextFieldSetString(WX_wind_spd_data,""); } XtManageChild(WX_wind_spd_data); if (strlen(weather->wx_gust) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(weather->wx_gust)*1.6094)); XmTextFieldSetString(WX_wind_gst_data,temp); } else { XmTextFieldSetString(WX_wind_gst_data,weather->wx_gust); } } else { XmTextFieldSetString(WX_wind_gst_data,""); } XtManageChild(WX_wind_gst_data); if (strlen(weather->wx_rain_total) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain_total)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain_total)/100.0); XmTextFieldSetString(WX_rain_data,temp); } else { XmTextFieldSetString(WX_rain_data,""); } XtManageChild(WX_rain_data); if (strlen(weather->wx_rain) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain)/100.0); XmTextFieldSetString(WX_rain_h_data,temp); } else { XmTextFieldSetString(WX_rain_h_data,""); } XtManageChild(WX_rain_h_data); if (strlen(weather->wx_prec_24) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_24)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_24)/100.0); XmTextFieldSetString(WX_rain_24_data,temp); } else { XmTextFieldSetString(WX_rain_24_data,""); } XtManageChild(WX_rain_24_data); if (strlen(weather->wx_prec_00) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_00)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_00)/100.0); XmTextFieldSetString(WX_to_rain_data,temp); } else { XmTextFieldSetString(WX_to_rain_data,""); } XtManageChild(WX_rain_data); if (strlen(weather->wx_hum) > 0) { XmTextFieldSetString(WX_humidity_data,weather->wx_hum); } else { XmTextFieldSetString(WX_humidity_data,""); } XtManageChild(WX_humidity_data); if (strlen(wx_dew_point) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_dew_point)-32)*5.0)/9.0)); XmTextFieldSetString(WX_dew_point_data,temp); } else { XmTextFieldSetString(WX_dew_point_data,wx_dew_point); } } else { XmTextFieldSetString(WX_dew_point_data,""); } XtManageChild(WX_dew_point_data); if (strlen(wx_high_wind) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(wx_high_wind)*1.6094)); XmTextFieldSetString(WX_high_wind_data,temp); } else { XmTextFieldSetString(WX_high_wind_data,wx_high_wind); } } else { XmTextFieldSetString(WX_high_wind_data,""); } XtManageChild(WX_high_wind_data); if (strlen(wx_wind_chill) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_wind_chill)-32)*5.0)/9.0)); XmTextFieldSetString(WX_wind_chill_data,temp); } else { XmTextFieldSetString(WX_wind_chill_data,wx_wind_chill); } } else { XmTextFieldSetString(WX_wind_chill_data,""); } XtManageChild(WX_wind_chill_data); if (strlen(weather->wx_baro) > 0) { if (!english_units) { //xastir_snprintf(temp, sizeof(temp), "%0.0f", // atof(wx_baro_inHg)*25.4); // inch Hg -> mm Hg //XmTextFieldSetString(WX_baro_data,temp); XmTextFieldSetString(WX_baro_data,weather->wx_baro); // hPa } else // inches mercury { xastir_snprintf(temp, sizeof(temp), "%0.2f", (atof(weather->wx_baro)*0.02953)); XmTextFieldSetString(WX_baro_data,temp); } } else { XmTextFieldSetString(WX_baro_data,""); } XtManageChild(WX_baro_data); if (wx_three_hour_baro_on) { if (!english_units) // hPa { //xastir_snprintf(temp, sizeof(temp), "%0.0f", // atof(wx_three_hour_baro)*25.4); // inch Hg -> mm Hg XmTextFieldSetString(WX_three_hour_baro_data,wx_three_hour_baro); } else // inches mercury { xastir_snprintf(temp, sizeof(temp), "%0.2f", (atof(wx_three_hour_baro)*0.02953)); XmTextFieldSetString(WX_three_hour_baro_data,temp); } } else { XmTextFieldSetString(WX_three_hour_baro_data,""); } XtManageChild(WX_three_hour_baro_data); if (wx_hi_temp_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_hi_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_hi_temp_data,temp); } else { XmTextFieldSetString(WX_hi_temp_data,wx_hi_temp); } } else { XmTextFieldSetString(WX_hi_temp_data,""); } XtManageChild(WX_hi_temp_data); if (wx_low_temp_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_low_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_low_temp_data,temp); } else { XmTextFieldSetString(WX_low_temp_data,wx_low_temp); } } else { XmTextFieldSetString(WX_low_temp_data,""); } XtManageChild(WX_low_temp_data); if (wx_heat_index_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_heat_index)-32)*5.0)/9.0)); XmTextFieldSetString(WX_heat_index_data,temp); } else { XmTextFieldSetString(WX_heat_index_data,wx_heat_index); } } else { XmTextFieldSetString(WX_heat_index_data,""); } XtManageChild(WX_heat_index_data); } } } /* labels */ if (!english_units) { XmTextFieldSetString(WX_speed_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_speed_label,langcode("UNIOP00013")); } XtManageChild(WX_speed_label); if (!english_units) { XmTextFieldSetString(WX_gust_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_gust_label,langcode("UNIOP00013")); } XtManageChild(WX_gust_label); if (!english_units) { XmTextFieldSetString(WX_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_temp_label); if (!english_units) { XmTextFieldSetString(WX_rain_label,langcode("UNIOP00016")); } else { XmTextFieldSetString(WX_rain_label,langcode("UNIOP00017")); } XtManageChild(WX_rain_label); if (!english_units) { XmTextFieldSetString(WX_to_rain_label,langcode("UNIOP00022")); } else { XmTextFieldSetString(WX_to_rain_label,langcode("UNIOP00023")); } XtManageChild(WX_to_rain_label); if (!english_units) { XmTextFieldSetString(WX_rain_h_label,langcode("UNIOP00020")); } else { XmTextFieldSetString(WX_rain_h_label,langcode("UNIOP00021")); } XtManageChild(WX_rain_h_label); if (!english_units) { XmTextFieldSetString(WX_rain_24_label,langcode("UNIOP00018")); } else { XmTextFieldSetString(WX_rain_24_label,langcode("UNIOP00019")); } XtManageChild(WX_rain_24_label); if (!english_units) { XmTextFieldSetString(WX_dew_point_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_dew_point_label,langcode("UNIOP00015")); } XtManageChild(WX_dew_point_label); if (!english_units) { XmTextFieldSetString(WX_wind_chill_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_wind_chill_label,langcode("UNIOP00015")); } XtManageChild(WX_wind_chill_label); if (!english_units) { XmTextFieldSetString(WX_heat_index_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_heat_index_label,langcode("UNIOP00015")); } XtManageChild(WX_heat_index_label); if (!english_units) { XmTextFieldSetString(WX_hi_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_hi_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_hi_temp_label); if (!english_units) { XmTextFieldSetString(WX_low_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_low_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_low_temp_label); if (!english_units) { XmTextFieldSetString(WX_high_wind_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_high_wind_label,langcode("UNIOP00013")); } XtManageChild(WX_high_wind_label); if (!english_units) { XmTextFieldSetString(WX_baro_label,langcode("UNIOP00025")); } else { XmTextFieldSetString(WX_baro_label,langcode("UNIOP00027")); } XtManageChild(WX_baro_label); if (!english_units) { XmTextFieldSetString(WX_three_hour_baro_label,langcode("UNIOP00025")); } else { XmTextFieldSetString(WX_three_hour_baro_label,langcode("UNIOP00027")); } XtManageChild(WX_three_hour_baro_label); end_critical_section(&wx_station_dialog_lock, "wx_gui.c:fill_wx_data" ); } } Xastir-Release-2.2.2/src/x_spider.c000066400000000000000000001534421501463444000171270ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // // The idea here: Have Xastir spawn off a separate server (via a // system() call?) which can provide listening sockets for other // APRS clients to connect to. This allows other clients to share // Xastir's TNC ports. Forking Xastir directly and running the // server code doesn't work out well: The new process ends up with // the large Xastir memory image. We need a separate app with a // small memory image for the server. It might spawn off quite a // few processes, and we need it to be small and fast. // // The initial goal here is to take one box that is RF-rich (running // one or more TNC's), and have the ability to let other APRS // clients (Xastir or otherwise) to share the RF and/or internet // connections of the "master" Xastir session. This could be useful // in an EOC (Emergency Operations Center), a large SAR mission with // multiple computers, or simply to allow one to connect to their // home Xastir session from work and gain the use of the RF ports. // My use: On a SAR mission, using wireless networking and laptops // to let everyone see the same picture, multiplexing to one Xastir // session running a TNC. As usual, I'm sure other users will // figure out new and inventive uses for it. // // Yes, this does pose some security risks to the license of the // operator. I wouldn't recommend having an open port on the // internet to allow people to use your RF ports. Of course with // the authentication stuff that'll be in here, it's as secure as // the igating stuff that we currently have for APRS. // // I thought about using IPC Messaging or FIFO's (named pipes) in // order to make the connection from this server back to the // "master" Xastir session. I looked at the lack of support for // them in Cygwin and decided to use sockets instead. We'll set up // a special registration for Xastir so that this server code knows // which port is the "master" port (controlling port). // // Xastir will end up with a togglebutton to enable the server: // Starts up x_spider. // Connects to x_spider with a socket. // Sends a special string so x_spider knows which one is the // controlling (master) socket. // All packets received/transmitted by Xastir on any port also get // sent to x_spider. // // x_spider: // Accepts client socket connections. // Spawns a new process for each one. // Each new process talks to the main x_spider via two pipes. // Authenticate each connecting client in the normal manner. // Accept data from any socket, echo data out _all_ sockets. // If the "master" Xastir sends a shutdown packet, all connections // are dropped and x_spider and all it's children will exit. // x_spider uses select() calls to multiplex all pipes and the // listening socket. It shouldn't use up much CPU as it'll be // in the blocking select call until it has data to process. // x_spider's children should also wait in blocking calls until // there is data to process. // // This makes the design of the server rather simple: It needs to // authenticate clients and it needs to parse the shutdown message // from the "master" socket. Other than that it just needs to // re-transmit anything heard on one socket to all of the other // connected sockets. // // Xastir itself will have to change a bit in order to add the // togglebutton, to send anything transmit/received to the special // socket, and to send the registration and shutdown strings to the // server at the appropriate times. Not earth-shaking changes, but // changes nonetheless. // // Most of this code is adapted directly from W. Richard Steven's // book: "Unix Network Programming". Highly recommended book, as // are the other books by him that I own. I was sorry to hear of // his passing. // // Name for this? Spider, centipede, millipede, octopus, // multiplexer, repeater. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "x_spider.h" #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include #include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #ifndef SIGRET #define SIGRET void #endif // SIGRET #include "xastir.h" // Must be last include file #include "leak_detection.h" // Define this if you wish to use this as a standalone program // instead of as a function in another program. // //#define STANDALONE_PROGRAM // These are from util.h/util.c. We can't include util.h here // because it causes other problems. extern short checkHash(char *theCall, short theHash); extern void get_timestamp(char *timestring); extern void split_string( char *data, char *cptr[], int max, char search_char ); // From database.h extern char my_callsign[]; extern char *pname; typedef struct _pipe_object { int to_child[2]; int to_parent[2]; char callsign[20]; int authenticated; int active; // Mark for deletion after every task is finished struct _pipe_object *next; } pipe_object; pid_t parent_pid; pipe_object *pipe_head = NULL; //int master_fd = -1; // Start with an invalid value pipe_object *xastir_tcp_pipe = NULL; pipe_object *xastir_udp_pipe = NULL; // TCP server pipes to/from Xastir proper int pipe_xastir_to_tcp_server = -1; int pipe_tcp_server_to_xastir = -1; // UDP server pipes to/from Xastir proper int pipe_xastir_to_udp_server = -1; // (not currently used) int pipe_udp_server_to_xastir = -1; /* // Read "n" bytes from a descriptor. Use in place of read() when fd // is a stream socket. This routine is from "Unix Network // Programming". // // This routine is not used currently. // int readn(int fd, char *ptr, int nbytes) { int nleft, nread; nleft = nbytes; while (nleft > 0) { nread = read(fd, ptr, nleft); if (nread < 0) { return(nread); // Error, return < 0 } else if (nread == 0) { break; // EOF } nleft -= nread; ptr += nread; } return(nbytes - nleft); // Return >= 0 } */ // Write "n" bytes to a descriptor. Use in place of write() when fd // is a stream socket. This routine is from "Unix Network // Programming". // int writen(int fd, char *ptr, int nbytes) { int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) { return(nwritten); // Error } nleft -= nwritten; ptr += nwritten; } // fprintf(stderr, // "writen: %d bytes written, %d bytes left to write\n", // nleft, // nbytes - nleft); return(nbytes - nleft); } // Read a line from a descriptor. Read the line one byte at a time, // looking for the newline. We store the newline in the buffer, // then follow it with a null (the same as fgets(3)). We return the // number of characters up to, but not including, the null (the same // as strlen(3)); This routine is from "Unix Network Programming". // int readline(int fd, char *ptr, int maxlen) { int n, rc; char c; for (n = 1; n < maxlen; n++) { if ( (rc = read(fd, &c, 1)) == 1) { *ptr++ = c; if (c == '\n') { break; } } else if (rc == 0) { if (n == 1) { return(0); // EOF, no data read } else { break; // EOF, some data was read } } else { return(-1); // Error } } *ptr = 0; return(n); } #define MAXLINE 512 // Read a stream socket one line at a time, and write each line back // to the sender. Return when the connection is terminated. This // routine is from "Unix Network Programming". // /* void str_echo(int sockfd) { int n; char line[MAXLINE]; for ( ; ; ) { n = readline(sockfd, line, MAXLINE); if (n == 0) { return; // Connection terminated } if (n < 0) { fprintf(stderr,"str_echo: No data to read\n"); } if (writen(sockfd, line, n) != n) { fprintf(stderr,"str_echo: Writen error\n"); } } } */ // Read a stream socket one line at a time, and write each line back // to the sender. Return when the connection is terminated. This // routine is from "Unix Network Programming". // void str_echo2(int sockfd, int pipe_from_parent, int pipe_to_parent) { int n; char line[MAXLINE]; // Set socket to be non-blocking. // if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"str_echo2: Couldn't set socket non-blocking\n"); } // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_from_parent, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"str_echo2: Couldn't set read-end of pipe_from_parent non-blocking\n"); } //Send our callsign to spider clients as "#callsign" much like APRS-IS sends "# javaAPRS" // # xastir 1.5.1 callsign: sprintf(line,"# Welcome to Xastir's server port, callsign: %s\r\n",my_callsign); writen(sockfd,line,strlen(line)); // Infinite loop for ( ; ; ) { // // Read data from socket, write to pipe (parent) // if (!sockfd) // Socket is closed { return; // Connection terminated } n = readline(sockfd, line, MAXLINE); if (n == 0) { return; // Connection terminated } if (n < 0) { //fprintf(stderr,"str_echo2: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"str_echo2: Readline error socket: %d\n",errno); //close(sockfd); return; } } else // We received some data. Send it down the pipe. { // fprintf(stderr,"str_echo2: %s\n",line); if (writen(pipe_to_parent, line, n) != n) { fprintf(stderr,"str_echo2: Writen error socket: %d\n",errno); //close(sockfd); return; } } // // Read data from pipe (parent), write to socket // if (!pipe_from_parent) { exit(0); } n = readline(pipe_from_parent, line, MAXLINE); if (n == 0) { exit(0); // Connection terminated } if (n < 0) { //fprintf(stderr,"str_echo2: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"str_echo2: Readline error pipe: %d\n",errno); //close(pipe_from_parent); return; } } else // We received some data. Send it down the socket. { // fprintf(stderr,"str_echo2: %s\n",line); if (writen(sockfd, line, n) != n) { fprintf(stderr,"str_echo2: Writen error pipe: %d\n",errno); //close(pipe_from_parent); return; } } // Slow the loop down to prevent excessive CPU. // NOTE: We must be faster at processing packets than the // main.c:UpdateTime() can send them to us through the pipe! If // we're not, we lose or corrupt packets. usleep(1000); // 1ms } } // Function which checks the incoming pipes to see if there's any // data. If there is, checks to see if it is a control packet or a // registration packet from the master. If not, echoes the data out // all outgoing pipes. // // If we get a shutdown from the verified master, send a "1" as the // return value, which will shut down the server. Otherwise send a // "0" return value. // // Incoming registration data: Record only the master socket. All // others should be handled by the child processes, and they should // not pass the registration info down to us. Same for control // packets. Actually, the child process handling the master socket // could skip notifying us as well, and just pass down the control // packets if the master sent any (like the shutdown packet). If we // lost the connection between Xastir and x_spider, we might not // have a clean way of shutting down the server in that case though. // Might be better to record it down here, and if the pipes ever // closed, we shut down x_spider and all the child processes. // int pipe_check(char *client_address) { pipe_object *p = pipe_head; int n; char line[MAXLINE]; // Need a select here with a timeout? Also need a method of // revising the read bits we send to select. Should we revise // them every time through the loop, or set a variable in the // main() routine whenever a new connect comes in. What about // connects that go away? We need a way to free up the pipes // and sockets in that case, and revise the select bits again. // select(); //fprintf(stderr,"pipe_check()\n"); // All of the read ends of the pipes have been set non-blocking // by this point. // Check all the pipes in the linked list looking for something // to read. while (p != NULL) { // fprintf(stderr,"Running through pipes\n"); // // Read data from pipe, write to all pipes except the one // who sent it. // n = p->active ? readline(p->to_parent[0], line, MAXLINE): 0; if (n == 0 && p->active) { char timestring[101]; get_timestamp(timestring); if (p->authenticated) { fprintf(stderr, "%s X_spider session terminated, callsign: %s, address: %s\n", timestring, p->callsign, client_address); } else { fprintf(stderr, "%s X_spider session terminated, unauthenticated user, address %s\n", timestring, client_address); } // Close the pipe close(p->to_child[1]); close(p->to_parent[0]); p->active = 0; // This task is ready to let go. wait(NULL); // Reap the status of the dead process } else if (n < 0) { //fprintf(stderr,"pipe_check: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"pipe_check: Readline error: %d\n",errno); } } else if (p->active) // We received some data. Send it down all of the { // pipes except the one that sent it. pipe_object *q; // Check for an authentication string. If the pipe has not been // authenticated, we don't allow it to send anything to the upstream // server. It's probably ok to send it to downstream connections // though. // Check for "user" "pass" string. // "user WE7U-13 pass XXXX vers XASTIR 1.3.3" if (strstr(line,"user") && strstr(line,"pass")) { char line2[MAXLINE]; char *callsign; char *passcode_str; short passcode; char *space; // We have a string with user/pass in it, but they // can be anywhere along the line. We'll have to // search for each piece. //fprintf(stderr,"x_spider:Found an authentication string\n"); // Copy the line xastir_snprintf(line2, sizeof(line2), "%s", line); // Add white space to the end. strncat(line2, " ", sizeof(line2) - 1 - strlen(line2)); // Find the "user" string position callsign = strstr(line2,"user"); if (callsign == NULL) { continue; } // Fast-forward past the "user" word. callsign += 4; // Skip past any additional spaces that might be // present between "user" and callsign. while (callsign[0] == ' ' && callsign[0] != '\0') { callsign += 1; } if (callsign[0] == '\0') { continue; } // We should now be pointing at the beginning of the // callsign. // Find the space after the callsign space = strstr(callsign," "); if (space == NULL) { continue; } // Terminate the callsign string space[0] = '\0'; // Snag the passcode string // Find the "pass" string passcode_str = strstr(&space[1],"pass"); if (passcode_str == NULL) { continue; } // Fast-forward past the "pass" word. passcode_str = passcode_str + 4; // Skip past any additional spaces that might be // present between "pass" and the passcode. while (passcode_str[0] == ' ' && passcode_str[0] != '\0') { passcode_str += 1; } if (passcode_str[0] == '\0') { continue; } // Find the space after the passcode space = strstr(&passcode_str[0]," "); if (space == NULL) { continue; } // Terminate the passcode string space[0] = '\0'; passcode = atoi(passcode_str); //fprintf(stderr,"x_spider: user:.%s., pass:%d\n", callsign, passcode); if (checkHash(callsign, passcode)) { // Authenticate the pipe. It is now allowed to send // to the upstream server. //fprintf(stderr, // "x_spider: Authenticated user %s\n", // callsign); p->authenticated = 1; xastir_snprintf(p->callsign, sizeof(p->callsign), "%s", callsign); p->callsign[19] = '\0'; } else { fprintf(stderr, "X_spider: Bad authentication, user %s, pass %d\n", callsign, passcode); fprintf(stderr, "Line: %s\n", line); } } q = pipe_head; while (q != NULL) { // fprintf(stderr,"pipe_check: %s\n",line); // Only send to active pipes if (q != p && q->active) { if (writen(q->to_child[1], line, n) != n) { fprintf(stderr,"pipe_check: Writen error1: %d\n",errno); } } q = q->next; } // Here we send it to Xastir itself. We use a couple of // global variables just like channel_data() does, but // we don't have to protect them in the same manner as // we only have one process on each end. // // Send it down the pipe to Xastir's main thread. Knock off any // carriage return that might be present. We only want a linefeed // on the end. if (n > 0 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } if (n > 0 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } // Add the linefeed on the end strncat(line,"\n",sizeof(line)-strlen(line)-1); n++; // Only send to upstream server if this client has authenticated. if (p->authenticated) { //fprintf(stderr,"Data available, sending to server\n"); //fprintf(stderr,"\t%s\n",line); if (writen(pipe_tcp_server_to_xastir, line, n) != n) { fprintf(stderr, "pipe_check: Writen error2: %d\n", errno); } } } if (p) { p = p->next; } } // Check the pipe from Xastir's main thread to see if it is // sending us any data n = readline(pipe_xastir_to_tcp_server, line, MAXLINE); if (n == 0) { exit(0); // Connection terminated } if (n < 0) { //fprintf(stderr,"pipe_check: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"pipe_check: Readline error: %d\n",errno); } } else // We received some data. Send it down all of the { // pipes. // Also send it down the socket. // Check for disconnected clients and delete their records // from the chain. pipe_object *q = pipe_head; pipe_object *r = pipe_head; for (q = pipe_head; q != NULL; ) { if (!q->active) // Marked for deletion. { // Check for head of list, handle it in a special // manner. We don't have to fix up the "next" // pointer on the previous object (it doesn't exist) // but must fix up "pipe_head" pointer. if (q == pipe_head) { pipe_head = q->next; // New head of list p = q; // Assign temporary pointer q = q->next; // Keep pointer to next object r = q; // Keep 'r' and 'q' the same for now, // later 'r' will lag 'q' by one object free(p); // Free struct at temporary pointer } else // Not the head object { r->next = q->next; // Bridge soon-to-be-made gap p = q; // Assign temporary pointer q = q->next; // Keep pointer to next connection. free(p); // Free struct at temp pointer } } else { r = q; // Pointer to last object (so we can get to // the "next" pointer) q = q->next; // Pointer to next object } } q = pipe_head; // Reset pointer to beginning of list //fprintf(stderr,"n:%d\n",n); // Terminate it line[n] = '\0'; //fprintf(stderr,"sp %s\n", line); // The internet protocol for sending lines is "\r\n". Knock // off any line-end characters that might be present, then // add a "\r\n" combo on the end. // if (n >= 1 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } if (n >= 1 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } // Add carriage-return/linefeed onto the end strncat(line, "\r\n", sizeof(line)-strlen(line)-1); n += 2; while (q != NULL && q->active) { // fprintf(stderr,"pipe_check: %s\n",line); if (writen(q->to_child[1], line, n) != n) { fprintf(stderr,"pipe_check: Writen error1: %d\n",errno); } q = q->next; } } return(0); } // The below three functions init_set_proc_title() and // set_proc_title() are from: // http://lightconsulting.com/~thalakan/process-title-notes.html // They seems to work fine on Linux, but they only change the "ps" // listings, not the top listings. I don't know why yet. // Here's another good web page for Linux: // http://www.uwsg.iu.edu/hypermail/linux/kernel/0006.1/0610.html // clear_proc_title is to clean up internal pointers for environment. /* Globals */ static char **Argv = ((void *)0); #ifdef __linux__ #ifndef __LSB__ extern char *__progname, *__progname_full; #endif // __LSB__ #endif // __linux__ static char *LastArgv = ((void *)0); static char **local_environ; #ifdef __linux__ #ifndef __LSB__ static char *old_progname, *old_progname_full; #endif // __LSB__ #endif // __linux__ void clear_proc_title(void) { int i; for(i = 0; local_environ && local_environ[i] != NULL; i++) { free(local_environ[i]); } if (local_environ) { free(local_environ); local_environ = NULL; } #ifdef __linux__ #ifndef __LSB__ free(__progname); free(__progname_full); __progname = old_progname; __progname_full = old_progname_full; #endif // __LSB__ #endif // __linux__ } void init_set_proc_title(int UNUSED(argc), char *argv[], char *envp[]) { int i, envpsize; char **p; for(i = envpsize = 0; envp[i] != NULL; i++) { envpsize += strlen(envp[i]) + 1; } if((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL ) { local_environ = p; for(i = 0; envp[i] != NULL; i++) { if((local_environ[i] = malloc(strlen(envp[i]) + 1)) != NULL) xastir_snprintf(local_environ[i], strlen(envp[i])+1, "%s", envp[i]); } } local_environ[i] = NULL; Argv = argv; for(i = 0; argv[i] != NULL; i++) { if((LastArgv + 1) == argv[i]) // Not sure if this conditional is needed { LastArgv = envp[i] + strlen(envp[i]); } } #ifdef __linux__ #ifndef __LSB__ // Pretty sure you don't need this either old_progname = __progname; old_progname_full = __progname_full; __progname = strdup("xastir"); __progname_full = strdup(argv[0]); #endif // __LSB__ #endif // __linux__ atexit(clear_proc_title); } void set_proc_title(char *fmt,...) { va_list msg; static char statbuf[8192]; char *p; int i,maxlen = (LastArgv - Argv[0]) - 2; //fprintf(stderr,"DEBUG: maxlen: %i\n", maxlen); va_start(msg,fmt); memset(statbuf, 0, sizeof(statbuf)); xastir_vsnprintf(statbuf, sizeof(statbuf), fmt, msg); va_end(msg); i = strlen(statbuf); xastir_snprintf(Argv[0], maxlen, "%s", statbuf); p = &Argv[0][i]; while(p < LastArgv) { *p++ = '\0'; } Argv[1] = ((void *)0) ; } #define ADDR_STR_LEN 39 char *addr_str(const struct sockaddr *sa, char *s) { switch(sa->sa_family) { case AF_INET: inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, ADDR_STR_LEN); break; case AF_INET6: inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, ADDR_STR_LEN); break; default: xastir_snprintf(s, ADDR_STR_LEN, "", sa->sa_family); return NULL; } return s; } #define MAXSOCK 8 int open_spider_server_sockets(int socktype, int port, int **s_in) { struct addrinfo hints, *res, *res0; int error; int nsock; int buf; int *s; char port_str[16]; xastir_snprintf(port_str, 16, "%d", port); *s_in = calloc(MAXSOCK, sizeof(int)); s = *s_in; // Query for socketrs we need to create (probably 1 each for IPv4 + IPv6) memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = socktype; hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, port_str, &hints, &res0); if (error) { fprintf(stderr, "Error: Unable to lookup addresses for port %s\n", port_str); return 0; } // Create and setup each socket nsock = 0; for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { s[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s[nsock] < 0) { fprintf(stderr, "Error: Opening socket (family %d protocol %d\n", res->ai_family, res->ai_protocol); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); continue; } #ifdef IPV6_V6ONLY if(res->ai_family == AF_INET6) { buf = 1; if (setsockopt(s[nsock], IPPROTO_IPV6, IPV6_V6ONLY, (char *)&buf, sizeof(buf)) < 0) { fprintf(stderr, "x_spider: Unable to set IPV6_V6ONLY.\n"); } } #endif if(socktype == SOCK_STREAM) { // Set the new socket to be non-blocking. // if (fcntl(s[nsock], F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set socket non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // Set up to reuse the port number (good for debug so we can // restart the server quickly against the same port). buf = 1; if (setsockopt(s[nsock], SOL_SOCKET, SO_REUSEADDR, (char *)&buf, sizeof(buf)) < 0) { fprintf(stderr,"x_spider: Couldn't set socket REUSEADDR\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } } if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { fprintf(stderr, "x_spider: Can't bind local address for AF %d: %d - %s\n", res->ai_family, errno, strerror(errno)); fprintf(stderr, "Either this OS maps IPv4 addresses to IPv6 and this may be expected or\n"); fprintf(stderr,"could some processes still be running from a previous run of Xastir?\n"); close(s[nsock]); continue; } if(socktype == SOCK_STREAM) { // Set up to listen. We allow up to five backlog connections // (unserviced connects that get put on a queue until we can // service them). (void) listen(s[nsock], 5); } nsock++; } if (nsock == 0) { fprintf(stderr, "x_spider: Couldn't open any sockets\n"); } freeaddrinfo(res0); return nsock; } // Create a poll structure from an array of sockets struct pollfd* setup_poll_array(int nsock, int* sockfds) { int i; struct pollfd* polls; polls = calloc(nsock, sizeof(struct pollfd)); for(i=0; iauthenticated = 0; p->callsign[0] = '\0'; get_timestamp(timestring); fprintf(stderr,"%s X_spider client connected from address %s\n", timestring, addr_str((struct sockaddr*)&cli_addr, addrstring)); if (pipe(p->to_child) < 0 || pipe(p->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); if (p->to_child[1]) { close(p->to_child[1]); } if (p->to_child[0]) { close(p->to_child[0]); } free(p); // Free the malloc'd memory. p = NULL; close(newsockfd); goto finis; } // Indicate active connection! p->active = 1; // Link it into the head of the chain. // p->next = pipe_head; pipe_head = p; flag = 1; // Turn on the socket keepalive option (void)setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)); // Disable the Nagle algorithm (speeds things up) (void)setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); if ( (childpid = fork()) < 0) { // // Problem forking. Clean up and continue loop. // fprintf(stderr,"x_spider: Fork error\n"); // Close pipes close(p->to_child[0]); close(p->to_child[1]); close(p->to_parent[0]); close(p->to_parent[1]); pipe_head = p->next; free(p); // Free the malloc'd memory. p = NULL; close(newsockfd); goto finis; } else if (childpid == 0) { // // child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); /* fprintf(stderr, "Client address: %s\n", inet_ntoa(cli_addr.sin_addr)); */ // Change the name of the new child process. So far // this only works for "ps" listings, not for "top". // This code only works on Linux. For BSD use // setproctitle(3), NetBSD can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s%s %s", "x-spider client @", addr_str((struct sockaddr*)&cli_addr, addrstring), "(xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ // It'd be very cool here to include the IP address of the remote // client on the "ps" line, and include the callsign of the // connecting client once the client authenticates. Both of these // are do-able. // New naming system so that we don't have to remember // the longer name: // pipe_to_parent = p->to_parent[1]; pipe_from_parent = p->to_child[0]; close(sockfd); // Close original socket. Child // doesn't need the listening // socket. close(p->to_child[1]); // Close write end of pipe close(p->to_parent[0]); // Close read end of pipe // str_echo(newsockfd); // Process the request str_echo2(newsockfd, pipe_from_parent, pipe_to_parent); // Clean up and exit // close(pipe_to_parent); close(pipe_from_parent); exit(0); } // // Parent process // close(newsockfd); close(p->to_parent[1]); // Close write end of pipe close(p->to_child[0]); // Close read end of pipe // Set read-end of pipe to be non-blocking. // if (fcntl(p->to_parent[0], F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_to_parent non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } finis: // Need a delay so that we don't use too much CPU, at least // for debug. Put the delay into the select() call in the // pipe_check() function once we get to that stage of // coding. // // NOTE: We must be faster at processing packets than the // main.c:UpdateTime() can send them to us through the pipe! If // we're not, we lose or corrupt packets. usleep(1000); // 1ms } } // Send a nack back to the xastir_udp_client program void send_udp_nack(int sock, struct sockaddr *from, int fromlen) { int n; n = sendto(sock, "NACK", // Negative Acknowledgment 5, 0, (struct sockaddr *)from, fromlen); if (n < 0) { fprintf(stderr, "Error: sendto"); } } // Create a UDP listening port. This allows scripts and other // programs to inject packets into Xastir via UDP protocol. // void UDP_Server(int UNUSED(argc), char * UNUSED(argv[]), char * UNUSED(envp[]) ) { int sock, n1, n2; socklen_t fromlen; struct sockaddr_storage from; struct pollfd *polls; char buf[1024]; char buf2[512]; char *callsign; short passcode; char *cptr[10]; char *message = NULL; char message2[1024]; int send_to_inet; int send_to_rf; int *sockfds; int nsock; int i, rc; char addrstring[ADDR_STR_LEN+1]; nsock = open_spider_server_sockets(SOCK_DGRAM, SERV_UDP_PORT, &sockfds); if(!nsock) { fprintf(stderr, "Unable to setup any x_spider UDP server sockets.\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); return; } // Setup socket polling array and free the socket array // (since the FDs were copied into the poll array) polls = setup_poll_array(nsock, sockfds); free(sockfds); while (1) { rc = poll(polls, nsock, 5000); // Wait for data if(rc == -1) { fprintf(stderr, "x_spider: UDP poll() returned error %d: %s.\n", errno, strerror(errno)); continue; } else if (rc == 0) { // Timeout, check if parent is still alive rc = kill(parent_pid, 0); if(rc == -1 && errno == ESRCH) { // Parent died, exit return; } continue; } // Data should be waiting. Scan the poll set for an FD that has one waiting and use that. sock = -1; for(i=0; ito_child) < 0 || pipe(xastir_tcp_pipe->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); free(xastir_tcp_pipe); // Free the malloc'd memory. xastir_tcp_pipe = NULL; return(0); } xastir_tcp_pipe->authenticated = 1; xastir_tcp_pipe->callsign[0] = '\0'; if ( (childpid = fork()) < 0) { fprintf(stderr,"Fork_TCP_server: Fork error\n"); // Close pipes close(xastir_tcp_pipe->to_child[0]); close(xastir_tcp_pipe->to_child[1]); close(xastir_tcp_pipe->to_parent[0]); close(xastir_tcp_pipe->to_parent[1]); free(xastir_tcp_pipe); // Free the malloc'd memory. xastir_tcp_pipe = NULL; return(0); } else if (childpid == 0) { // // Child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So far this // only works for "ps" listings, not for "top". This code // only works on Linux. For BSD use setproctitle(3), NetBSD // can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s", "x-spider TCP daemon (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ close(xastir_tcp_pipe->to_child[1]); // Close write end of pipe close(xastir_tcp_pipe->to_parent[0]); // Close read end of pipe // Assign the global variables pipe_tcp_server_to_xastir = xastir_tcp_pipe->to_parent[1]; pipe_xastir_to_tcp_server = xastir_tcp_pipe->to_child[0]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_xastir_to_tcp_server, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_tcp_server non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } TCP_Server(argc, argv, envp); fprintf(stderr,"TCP_Server process died.\n"); exit(1); } // // Parent process // close(xastir_tcp_pipe->to_parent[1]); // Close write end of pipe close(xastir_tcp_pipe->to_child[0]); // Close read end of pipe // Assign the global variables so that Xastir itself will know // how to talk to the pipes pipe_tcp_server_to_xastir = xastir_tcp_pipe->to_parent[0]; pipe_xastir_to_tcp_server = xastir_tcp_pipe->to_child[1]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_tcp_server_to_xastir, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_tcp_server_to_xastir non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // // Set write-end of pipe to be non-blocking. // // // if (fcntl(pipe_xastir_to_tcp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_tcp_server non-blocking\n"); // } // We don't need to do anything here except return back to the // calling routine with the PID of the new server process, so // that it can request the server and all it's children to quit // when Xastir quits or segfaults. return(childpid); // Really the parent PID in this case } #endif // STANDALONE_PROGRAM int Fork_UDP_server(int argc, char *argv[], char *envp[]) { int childpid; // Allocate a pipe before we fork. // xastir_udp_pipe = (pipe_object *)malloc(sizeof(pipe_object)); if (xastir_udp_pipe == NULL) { fprintf(stderr,"x_spider: Couldn't malloc pipe_object\n"); return(0); } if (pipe(xastir_udp_pipe->to_child) < 0 || pipe(xastir_udp_pipe->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); free(xastir_udp_pipe); // Free the malloc'd memory. xastir_udp_pipe = NULL; return(0); } xastir_udp_pipe->authenticated = 1; xastir_udp_pipe->callsign[0] = '\0'; if ( (childpid = fork()) < 0) { fprintf(stderr,"Fork_UDP_server: Fork error\n"); // Close pipes close(xastir_udp_pipe->to_child[0]); close(xastir_udp_pipe->to_child[1]); close(xastir_udp_pipe->to_parent[0]); close(xastir_udp_pipe->to_parent[1]); free(xastir_udp_pipe); // Free the malloc'd memory. xastir_udp_pipe = NULL; return(0); } else if (childpid == 0) { // // Child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Store parent pid parent_pid = getppid(); // Change the name of the new child process. So far this // only works for "ps" listings, not for "top". This code // only works on Linux. For BSD use setproctitle(3), NetBSD // can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s", "x-spider UDP daemon (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ close(xastir_udp_pipe->to_child[1]); // Close write end of pipe close(xastir_udp_pipe->to_parent[0]); // Close read end of pipe // Assign the global variables pipe_udp_server_to_xastir = xastir_udp_pipe->to_parent[1]; pipe_xastir_to_udp_server = xastir_udp_pipe->to_child[0]; // Set read-end of pipe to be non-blocking. // // if (fcntl(pipe_xastir_to_udp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr, // "x_spider: Couldn't set read-end of pipe_xastir_to_udp_server non-blocking\n"); // } UDP_Server(argc, argv, envp); fprintf(stderr,"UDP_Server process died.\n"); exit(1); } // // Parent process // close(xastir_udp_pipe->to_parent[1]); // Close write end of pipe close(xastir_udp_pipe->to_child[0]); // Close read end of pipe // Assign the global variables so that Xastir itself will know // how to talk to the pipes pipe_udp_server_to_xastir = xastir_udp_pipe->to_parent[0]; pipe_xastir_to_udp_server = xastir_udp_pipe->to_child[1]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_udp_server_to_xastir, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_udp_server_to_xastir non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // // Set write-end of pipe to be non-blocking. // // // if (fcntl(pipe_xastir_to_udp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_udp_server non-blocking\n"); // } // We don't need to do anything here except return back to the // calling routine with the PID of the new server process, so // that it can request the server and all it's children to quit // when Xastir quits or segfaults. return(childpid); // Really the parent PID in this case } Xastir-Release-2.2.2/src/x_spider.h000066400000000000000000000027501501463444000171270ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_SERVER_H #define __XASTIR_SERVER_H //#include "xastir.h" #define NET_CONNECT_TIMEOUT 20 #define SERV_TCP_PORT 2023 #define SERV_UDP_PORT 2023 extern char *pname; extern int pipe_xastir_to_tcp_server; extern int pipe_tcp_server_to_xastir; extern int pipe_xastir_to_udp_server; extern int pipe_udp_server_to_xastir; extern int writen(int fd, char *ptr, int nbytes); extern int readline(int fd, char *ptr, int maxlen); extern int Fork_TCP_server(int argc, char *argv[], char *envp[]); extern int Fork_UDP_server(int argc, char *argv[], char *envp[]); #endif /* XASTIR_SERVER_H */ Xastir-Release-2.2.2/src/xa_config.c000066400000000000000000002602321501463444000172430ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "xa_config.h" #include "interface.h" #include "xastir.h" #include "main.h" #include "util.h" #include "bulletin_gui.h" #include "list_gui.h" #include "messages.h" #include "draw_symbols.h" #include "maps.h" #include "track_gui.h" #include "geo.h" #include "snprintf.h" #include "objects.h" #include "db_gis.h" // Must be last include file #include "leak_detection.h" #define CONFIG_FILE "config/xastir.cnf" #define CONFIG_FILE_BAK1 "config/xastir.cnf.1" #define CONFIG_FILE_BAK2 "config/xastir.cnf.2" #define CONFIG_FILE_BAK3 "config/xastir.cnf.3" #define CONFIG_FILE_BAK4 "config/xastir.cnf.4" #define CONFIG_FILE_TMP "config/xastir.cnf.tmp" #define MAX_VALUE 300 char xa_config_dir[1000]; /* cmdline option user config dir */ void store_string(FILE * fout, char *option, char *value) { // if (debug_level & 1) // fprintf(stderr,"Store String Start\n"); // TODO: Replace with function which doesn't depend on locale. // We'd also need to replace any xastir_snprintf() functions // throughout. fprintf (fout, "%s:%s\n", option, value); // if (debug_level & 1) // fprintf(stderr,"Store String Stop\n"); } void store_char(FILE * fout, char *option, char value) { char value_o[2]; value_o[0] = value; value_o[1] = '\0'; store_string (fout, option, value_o); } void store_int(FILE * fout, char *option, int value) { char value_o[MAX_VALUE]; xastir_snprintf (value_o, sizeof(value_o), "%d", value); store_string (fout, option, value_o); } void store_long (FILE * fout, char *option, long value) { char value_o[MAX_VALUE]; xastir_snprintf(value_o, sizeof(value_o), "%ld", value); store_string (fout, option, value_o); } void store_float (FILE * fout, char *option, float value) { char value_o[MAX_VALUE]; xastir_snprintf(value_o, sizeof(value_o), "%f", value); store_string (fout, option, value_o); } FILE * fin; void input_close(void) { if(fin != NULL) { (void)fclose(fin); } fin = NULL; } /* This function will read the configuration file (xastir.cnf) until it finds the requested option. When the requested option is found it will return the value of that option. The return value of the function will be 1 if the option is found and 0 if the option is not found. May return empty string in "value". */ int get_string(char *option, char *value, int value_size) { char config_file[MAX_VALUE]; char config_line[256]; short option_found; char *value_array[2]; option_found = 0; if (fin == NULL) { get_user_base_dir(CONFIG_FILE, config_file, sizeof(config_file)); // filecreate() refuses to create a new file if it already // exists. (void)filecreate(config_file); fin = fopen (config_file, "r"); } if (fin != NULL) { int loop_counter = 0; while (!option_found && loop_counter < 2) { // Search to the end of file and then repeat from the // beginning (once) if not found the first time. As // long as we keep the order of saves/restores to/from // the file the same, this will mean exactly one fgets() // per variable sought. if (loop_counter == 1) { // We didn't find it the first time through, try // once more from the start of file. (void)fseek(fin, 0, SEEK_SET); } // Read the file line-by-line. fgets() also reads in // the line-end characters so we'll have to remove // those. while (!option_found && (fgets (&config_line[0], 256, fin) != NULL)) { // Find the line containing "option" // Here we assume no leading/trailing white space // for value_array[0]. split_string(config_line, value_array, 2, ':'); if (strcmp (value_array[0], option) == 0) { int len; // Found the correct line option_found = 1; remove_leading_spaces(value_array[1]); // Eliminate line-end chars. Do this twice 'cuz // some operating systems add two characters // (\r\n) len = strlen(value_array[1]); if (len > 0) { if ( (value_array[1][len-1] == '\n') || (value_array[1][len-1] == '\r') ) { value_array[1][len-1] = '\0'; } } len = strlen(value_array[1]); if (len > 0) { if ( (value_array[1][len-1] == '\n') || (value_array[1][len-1] == '\r') ) { value_array[1][len-1] = '\0'; } } remove_trailing_spaces(value_array[1]); if (value_array[1] == NULL) { value = ""; } else xastir_snprintf(value, value_size, "%s", value_array[1]); //fprintf(stderr,"%s = %s\n", value_array[0], value); } } // End of while (fgets) loop_counter++; } // End of while (!option_found) } // End of if else { fprintf(stderr,"Couldn't open file: %s\n", config_file); } return (option_found); } int get_char(char *option, char *value) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret) { *value = value_o[0]; } return (ret); } // Snags an int and checks whether it is within the correct range. // If not, it assigns a default value. Returns the value. int get_int(char *option, int low, int high, int def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (atoi(value_o) >= low) && (atoi(value_o) <= high) ) { return(atoi (value_o)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %d\n", // option, // def); return(def); } fprintf(stderr,"xastir.cnf: %s out-of-range: %d, changing to default: %d\n", option, atoi(value_o), def); return(def); } // Snags a long and checks whether it is within the correct range. // If not, it assigns a default value. Returns the value. long get_long(char *option, long low, long high, long def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (atol(value_o) >= low) && (atol(value_o) <= high) ) { return(atol(value_o)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %ld\n", // option, // def); return(def); } fprintf(stderr, "xastir.cnf: %s out-of-range: %ld, changing to default: %ld\n", option, atol(value_o), def); return(def); } // Snags a float value and checks whether it is within the correct // range. If not, it assigns a default value. Returns the value. float get_float(char *option, float low, float high, float def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (strtof(value_o, NULL) >= low) && (strtof(value_o, NULL) <= high ) ) { return(strtof(value_o, NULL)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %f\n", // option, // def); return(def); } fprintf(stderr, "xastir.cnf: %s out-of-range: %f, changing to default: %f\n", option, strtof(value_o, NULL), def); return(def); } // Note on get_user_base_dir // // The original implementation of this function used a static char array // to do all the path construction, and returned a pointer to that array. // // This function was changed in Sept 2012 to remove its original use // of a single static char array. That version was highly unsafe in a // threaded environment, and was used routinely in multiple threads. // Even inserting mutexes to prevent simultaneous writes by multiple threads // wasn't good enough, because once the mutex was released there was no // guarantee that one thread would not write into the static array while // another thread was reading it. The result was that it was sometimes // possible for paths to get corrupted, especially if multiple logging // options and png snapshots were simultaneously selected. // // Prior to the change, one called this as: // ptr = get_user_base_dir("pathfragment"); // and ptr was always a pointer to the static char array. Now // the caller is responsible for passing in the array into which we'll // write. This way, threads should never be clobbering each other's paths // returned from this routine. // char *get_user_base_dir(char *dir, char * base, size_t base_size) { char *env_ptr; // fprintf(stderr,"base: %s \nxa_config_dir: %s\n", base, xa_config_dir); switch (xa_config_dir[0]) { case '/': //have some path xastir_snprintf(base, base_size, "%s",xa_config_dir); break; case '\0' : // build from scratch xastir_snprintf(base, base_size, "%s", ((env_ptr = getenv ("XASTIR_USER_BASE")) != NULL) ? env_ptr : user_dir); if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } strncat (base, ".xastir/", base_size - 1 - strlen(base)); break ; default: // Unqualified path xastir_snprintf(base, base_size, "%s", ((env_ptr = getenv ("PWD")) != NULL) ? env_ptr : user_dir); if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } strncat (base, xa_config_dir, base_size - 1 - strlen(base)); } if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } // Save base so we monkey around less later. xastir_snprintf(xa_config_dir,sizeof(xa_config_dir),"%s", base); // Append dir and return return strncat(base, dir, base_size - 1 - strlen(base)); } char *get_data_base_dir(char *dir) { static char base[MAX_VALUE]; char *env_ptr; // Snag this variable from the environment if it exists there, // else grab it from the define from the compile command-line // that should look like one of these: // // -DXASTIR_DATA_BASE=\"/opt/Xastir/share/xastir\" // -DXASTIR_DATA_BASE=\"/usr/local/share/xastir\" // xastir_snprintf(base, sizeof(base), "%s", ((env_ptr = getenv ("XASTIR_DATA_BASE")) != NULL) ? env_ptr : XASTIR_DATA_BASE); if (base[strlen (base) - 1] != '/') { strncat(base, "/", sizeof(base) - 1 - strlen(base)); } strncat(base, dir, sizeof(base) - 1 - strlen(base)); return base; } // Care should be taken here to make sure that no out-of-range data // is saved, as it will mess up Xastir startup from that point on. // Also: Config file should be owned by the user, and not by root. // If chmod 4755 is done on the executable, then the config file ends // up being owned by root from then on. // // Yea, I could have made this nicer by algorithmically figuring out // the backup filenames and rotating among .1 through .9. Perhaps // next go-around! Just having multiples is a big win, in case some // of them get blown away. // // Another step that needs to be made is to restore config settings // for the cases where Xastir comes up with a nonexistent or empty // xastir.cnf file. If the backups exist, we should copy them // across. // void save_data(void) { int i; char name_temp[20]; char name[50]; FILE * fout; char config_file_tmp[MAX_VALUE]; char config_file[MAX_VALUE]; char config_file_bak1[MAX_VALUE]; char config_file_bak2[MAX_VALUE]; char config_file_bak3[MAX_VALUE]; char config_file_bak4[MAX_VALUE]; struct stat file_status; // Force the locale to a default so that we don't have // conversion problems due to LANG/LC_ALL/LC_CTYPE/LC_NUMERIC // environment variables. (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); // if (debug_level & 1) // fprintf(stderr,"Store String Start\n"); // The new file we'll create get_user_base_dir(CONFIG_FILE_TMP, config_file_tmp, sizeof(config_file_tmp)); // Save to the new config file fout = fopen (config_file_tmp, "a"); if (fout != NULL) { // Position x_return; // Position y_return; if (debug_level & 1) { fprintf(stderr,"Save Data Start\n"); } /* language */ store_string (fout, "LANGUAGE", lang_to_use); /* my data */ store_string (fout, "STATION_CALLSIGN", my_callsign); store_string (fout, "STATION_LAT", my_lat); store_string (fout, "STATION_LONG", my_long); store_char (fout, "STATION_GROUP", my_group); store_char (fout, "STATION_SYMBOL", my_symbol); store_char (fout, "STATION_MESSAGE_TYPE", aprs_station_message_type); store_string (fout, "STATION_POWER", my_phg); store_string (fout, "STATION_COMMENTS", my_comment); store_int (fout, "MY_TRAIL_DIFF_COLOR", my_trail_diff_color); if (debug_level & 1) { fprintf(stderr,"Save Data 1\n"); } /* default values */ store_long (fout, "SCREEN_WIDTH", screen_width); store_long (fout, "SCREEN_HEIGHT", screen_height); /* // Get the X/Y offsets for the main window XtVaGetValues(appshell, XmNx, &x_return, XmNy, &y_return, NULL); fprintf(stderr,"X:%d y:%d\n", (int)x_return, (int)y_return); store_int (fout, "SCREEN_X_OFFSET", (int)x_return); store_int (fout, "SCREEN_Y_OFFSET", (int)y_return); */ store_long (fout, "SCREEN_LAT", center_latitude); store_long (fout, "SCREEN_LONG", center_longitude); store_string(fout, "RELAY_DIGIPEAT_CALLS", relay_digipeater_calls); store_int (fout, "COORDINATE_SYSTEM", coordinate_system); store_int (fout, "STATION_TRANSMIT_AMB", position_amb_chars); if (scale_y > 0) { store_long (fout, "SCREEN_ZOOM", scale_y); } else { store_long (fout, "SCREEN_ZOOM", 1); } store_int (fout, "MAP_BGCOLOR", map_background_color); store_int (fout, "MAP_DRAW_FILLED_COLORS", map_color_fill); #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) store_float (fout, "IMAGEMAGICK_GAMMA_ADJUST", imagemagick_gamma_adjust); #endif // HAVE_MAGICK store_float(fout, "RASTER_MAP_INTENSITY", raster_map_intensity); #endif // NO_GRAPHICS store_string(fout, "PRINT_PROGRAM", printer_program); store_string(fout, "PREVIEWER_PROGRAM", previewer_program); store_int (fout, "MAP_LETTERSTYLE", letter_style); store_int (fout, "MAP_ICONOUTLINESTYLE", icon_outline_style); store_int (fout, "MAP_WX_ALERT_STYLE", wx_alert_style); store_string(fout, "ALTNET_CALL", altnet_call); store_int(fout, "ALTNET", altnet); store_int(fout, "SKIP_DUPE_CHECK", skip_dupe_checking); store_string (fout, "AUTO_MAP_DIR", AUTO_MAP_DIR); store_string (fout, "ALERT_MAP_DIR", ALERT_MAP_DIR); store_string (fout, "SELECTED_MAP_DIR", SELECTED_MAP_DIR); store_string (fout, "SELECTED_MAP_DATA", SELECTED_MAP_DATA); store_string (fout, "MAP_INDEX_DATA", MAP_INDEX_DATA); store_string (fout, "SYMBOLS_DIR", SYMBOLS_DIR); store_string (fout, "SOUND_DIR", SOUND_DIR); store_string (fout, "GROUP_DATA_FILE", group_data_file); store_string (fout, "GNIS_FILE", locate_gnis_filename); store_string (fout, "GEOCODE_FILE", geocoder_map_filename); store_int (fout, "SHOW_FIND_TARGET", show_destination_mark); /* maps */ store_int (fout, "MAPS_LONG_LAT_GRID", long_lat_grid); store_int (fout, "MAPS_LABELED_GRID_BORDER", draw_labeled_grid_border); store_int (fout, "MAPS_LEVELS", map_color_levels); store_int (fout, "MAPS_LABELS", map_labels); store_int (fout, "MAP_LOCK_PAN_ZOOM", map_lock_pan_zoom); store_int (fout, "MAPS_AUTO_MAPS", map_auto_maps); store_int (fout, "MAPS_AUTO_MAPS_SKIP_RASTER", auto_maps_skip_raster); store_int (fout, "MAPS_INDEX_ON_STARTUP", index_maps_on_startup); store_string (fout, "MAPS_LABEL_FONT_TINY", rotated_label_fontname[FONT_TINY]); store_string (fout, "MAPS_LABEL_FONT_SMALL", rotated_label_fontname[FONT_SMALL]); store_string (fout, "MAPS_LABEL_FONT_MEDIUM", rotated_label_fontname[FONT_MEDIUM]); // NOTE: FONT_DEFAULT points to FONT_MEDIUM. store_string (fout, "MAPS_LABEL_FONT_LARGE", rotated_label_fontname[FONT_LARGE]); store_string (fout, "MAPS_LABEL_FONT_HUGE", rotated_label_fontname[FONT_HUGE]); store_string (fout, "MAPS_LABEL_FONT_BORDER", rotated_label_fontname[FONT_BORDER]); store_string (fout, "SYSTEM_FIXED_FONT", rotated_label_fontname[FONT_SYSTEM]); store_string (fout, "STATION_FONT", rotated_label_fontname[FONT_STATION]); store_string (fout, "ATV_ID_FONT", rotated_label_fontname[FONT_ATV_ID]); #ifdef HAVE_LIBGEOTIFF store_int (fout, "DRG_XOR_COLORS", DRG_XOR_colors); store_int (fout, "DRG_SHOW_COLORS_0", DRG_show_colors[0]); store_int (fout, "DRG_SHOW_COLORS_1", DRG_show_colors[1]); store_int (fout, "DRG_SHOW_COLORS_2", DRG_show_colors[2]); store_int (fout, "DRG_SHOW_COLORS_3", DRG_show_colors[3]); store_int (fout, "DRG_SHOW_COLORS_4", DRG_show_colors[4]); store_int (fout, "DRG_SHOW_COLORS_5", DRG_show_colors[5]); store_int (fout, "DRG_SHOW_COLORS_6", DRG_show_colors[6]); store_int (fout, "DRG_SHOW_COLORS_7", DRG_show_colors[7]); store_int (fout, "DRG_SHOW_COLORS_8", DRG_show_colors[8]); store_int (fout, "DRG_SHOW_COLORS_9", DRG_show_colors[9]); store_int (fout, "DRG_SHOW_COLORS_10", DRG_show_colors[10]); store_int (fout, "DRG_SHOW_COLORS_11", DRG_show_colors[11]); store_int (fout, "DRG_SHOW_COLORS_12", DRG_show_colors[12]); #endif // HAVE_LIBGEOTIFF // filter values // NOT SAVED: Select_.none store_int (fout, "DISPLAY_MY_STATION", Select_.mine); store_int (fout, "DISPLAY_TNC_STATIONS", Select_.tnc); store_int (fout, "DISPLAY_TNC_DIRECT_STATIONS", Select_.direct); store_int (fout, "DISPLAY_TNC_VIADIGI_STATIONS", Select_.via_digi); store_int (fout, "DISPLAY_NET_STATIONS", Select_.net); store_int (fout, "DISPLAY_TACTICAL_STATIONS", Select_.tactical); store_int (fout, "DISPLAY_OLD_STATION_DATA", Select_.old_data); store_int (fout, "DISPLAY_STATIONS", Select_.stations); store_int (fout, "DISPLAY_FIXED_STATIONS", Select_.fixed_stations); store_int (fout, "DISPLAY_MOVING_STATIONS", Select_.moving_stations); store_int (fout, "DISPLAY_WEATHER_STATIONS", Select_.weather_stations); store_int (fout, "DISPLAY_CWOP_WX_STATIONS", Select_.CWOP_wx_stations); store_int (fout, "DISPLAY_OBJECTS", Select_.objects); store_int (fout, "DISPLAY_STATION_WX_OBJ", Select_.weather_objects); store_int (fout, "DISPLAY_WATER_GAGE_OBJ", Select_.gauge_objects); store_int (fout, "DISPLAY_OTHER_OBJECTS", Select_.other_objects); store_int (fout, "DISPLAY_AIRCRAFT_OBJECTS", Select_.aircraft_objects); store_int (fout, "DISPLAY_VESSEL_OBJECTS", Select_.vessel_objects); // display values store_int (fout, "DISPLAY_CALLSIGN", Display_.callsign); store_int (fout, "DISPLAY_LABEL_ALL_TRACKPOINTS", Display_.label_all_trackpoints); store_int (fout, "DISPLAY_SYMBOL", Display_.symbol); store_int (fout, "DISPLAY_SYMBOL_ROTATE", Display_.symbol_rotate); store_int (fout, "DISPLAY_STATION_PHG", Display_.phg); store_int (fout, "DISPLAY_DEFAULT_PHG", Display_.default_phg); store_int (fout, "DISPLAY_MOBILES_PHG", Display_.phg_of_moving); store_int (fout, "DISPLAY_ALTITUDE", Display_.altitude); store_int (fout, "DISPLAY_COURSE", Display_.course); store_int (fout, "DISPLAY_SPEED", Display_.speed); store_int (fout, "DISPLAY_SPEED_SHORT", Display_.speed_short); store_int (fout, "DISPLAY_DIST_COURSE", Display_.dist_bearing); store_int (fout, "DISPLAY_WEATHER", Display_.weather); store_int (fout, "DISPLAY_STATION_WX", Display_.weather_text); store_int (fout, "DISPLAY_TEMP_ONLY", Display_.temperature_only); store_int (fout, "DISPLAY_WIND_BARB", Display_.wind_barb); store_int (fout, "DISPLAY_STATION_TRAILS", Display_.trail); store_int (fout, "DISPLAY_LAST_HEARD", Display_.last_heard); store_int (fout, "DISPLAY_POSITION_AMB", Display_.ambiguity); store_int (fout, "DISPLAY_DF_INFO", Display_.df_data); store_int (fout, "DISPLAY_DF_BEAMWIDTH_INFO", Display_.df_beamwidth_data); store_int (fout, "DISPLAY_DF_BEARING_INFO", Display_.df_bearing_data); store_int (fout, "DISPLAY_DEAD_RECKONING_INFO", Display_.dr_data); store_int (fout, "DISPLAY_DEAD_RECKONING_ARC", Display_.dr_arc); store_int (fout, "DISPLAY_DEAD_RECKONING_COURSE", Display_.dr_course); store_int (fout, "DISPLAY_DEAD_RECKONING_SYMBOL", Display_.dr_symbol); store_int (fout, "DISPLAY_UNITS_ENGLISH", english_units); store_int (fout, "DISPLAY_DIST_BEAR_STATUS", do_dbstatus); // CAD Objects store_int (fout, "DISPLAY_CAD_OBJECT_LABEL", CAD_show_label); store_int (fout, "DISPLAY_CAD_OBJECT_PROBABILITY", CAD_show_raw_probability); store_int (fout, "DISPLAY_CAD_OBJECT_COMMENT", CAD_show_comment); store_int (fout, "DISPLAY_CAD_OBJECT_AREA", CAD_show_area); // Interface values store_int (fout, "DISABLE_TRANSMIT", transmit_disable); store_int (fout, "DISABLE_POSIT_TX", posit_tx_disable); store_int (fout, "DISABLE_OBJECT_TX", object_tx_disable); store_int (fout, "ENABLE_SERVER_PORT", enable_server_port); for (i = 0; i < MAX_IFACE_DEVICES; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "DEVICE%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].device_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "NAME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_name); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RADIO_PORT", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].radio_port); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "CONVERSE_CMD", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_converse_string); #ifdef HAVE_DB xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].database_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA_TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].database_schema_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_USERNAME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_username); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_schema); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_UNIX_SOCKET", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_unix_socket); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "QUERY_ON_STARTUP", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].query_on_startup); #endif /* HAVE_DB */ xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "INTERFACE_COMMENT", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].comment); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "HOST", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_name); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "PASSWD", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_pswd); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "FILTER_PARAMS", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_filter_string); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO1", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO2", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto2); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO3", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto3); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO_IGATE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto_igate); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_UP_FILE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].tnc_up_file); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_DOWN_FILE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].tnc_down_file); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXDELAY", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].txdelay); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_PERSISTENCE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].persistence); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_SLOTTIME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].slottime); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXTAIL", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].txtail); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_FULLDUPLEX", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].fullduplex); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_INIT_KISSMODE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].init_kiss); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SPEED", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].sp); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "STYLE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].style); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "IGATE_OPTION", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].igate_options); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TXMT", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].transmit_data); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RELAY_DIGIPEAT", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].relay_digipeat); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RECONN", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].reconnect); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "ONSTARTUP", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].connect_on_startup); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat(name, "GPSRETR", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].gps_retrieve); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SETTIME", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].set_time); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNCEXTRADELAY", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].tnc_extra_delay); } /* TNC */ store_int (fout, "TNC_LOG_DATA", log_tnc_data); store_string (fout, "LOGFILE_TNC", LOGFILE_TNC); /* NET */ store_int (fout, "NET_LOG_DATA", log_net_data); store_int (fout, "NET_RUN_AS_IGATE", operate_as_an_igate); store_int (fout, "NETWORK_WAITTIME", NETWORK_WAITTIME); // LOGGING store_int (fout, "LOG_IGATE", log_igate); store_int (fout, "LOG_WX", log_wx); store_int (fout, "LOG_MESSAGE", log_message_data); store_int (fout, "LOG_WX_ALERT", log_wx_alert_data); store_string (fout, "LOGFILE_IGATE", LOGFILE_IGATE); store_string (fout, "LOGFILE_NET", LOGFILE_NET); store_string (fout, "LOGFILE_WX", LOGFILE_WX); store_string (fout, "LOGFILE_MESSAGE", LOGFILE_MESSAGE); store_string (fout, "LOGFILE_WX_ALERT", LOGFILE_WX_ALERT); // SNAPSHOTS store_int (fout, "SNAPSHOTS_ENABLED", snapshots_enabled); // KML SNAPSHOTS store_int (fout, "KMLSNAPSHOTS_ENABLED", kmlsnapshots_enabled); /* WX ALERTS */ store_long (fout, "WX_ALERTS_REFRESH_TIME", (long)WX_ALERTS_REFRESH_TIME); /* GPS */ store_long (fout, "GPS_TIME", (long)gps_time); /* still needed */ /* POSIT RATE */ store_long (fout, "POSIT_RATE", (long)POSIT_rate); /* OBJECT RATE */ store_long (fout, "OBJECT_RATE", (long)OBJECT_rate); /* UPDATE DR RATE */ store_long (fout, "UPDATE_DR_RATE", (long)update_DR_rate); /* station broadcast type */ store_int (fout, "BST_TYPE", output_station_type); #ifdef TRANSMIT_RAW_WX store_int (fout, "BST_WX_RAW", transmit_raw_wx); #endif // TRANSMIT_RAW_WX store_int (fout, "BST_COMPRESSED_POSIT", transmit_compressed_posit); store_int (fout, "COMPRESSED_OBJECTS_ITEMS", transmit_compressed_objects_items); store_int (fout, "SMART_BEACONING", smart_beaconing); store_int (fout, "SB_TURN_MIN", sb_turn_min); store_int (fout, "SB_TURN_SLOPE", sb_turn_slope); store_int (fout, "SB_TURN_TIME", sb_turn_time); store_int (fout, "SB_POSIT_FAST", sb_posit_fast); store_int (fout, "SB_POSIT_SLOW", sb_posit_slow); store_int (fout, "SB_LOW_SPEED_LIMIT", sb_low_speed_limit); store_int (fout, "SB_HIGH_SPEED_LIMIT", sb_high_speed_limit); store_int (fout, "POP_UP_NEW_BULLETINS", pop_up_new_bulletins); store_int (fout, "VIEW_ZERO_DISTANCE_BULLETINS", view_zero_distance_bulletins); store_int (fout, "WARN_ABOUT_MOUSE_MODIFIERS", warn_about_mouse_modifiers); /* -dk7in- variable beacon interval */ /* mobile: max 2 min */ /* fixed: max 15 min */ if ((output_station_type >= 1) && (output_station_type <= 3)) { max_transmit_time = (time_t)120l; /* 2 min @ mobile */ } else { max_transmit_time = (time_t)900l; /* 15 min @ fixed */ } /* Audio Alarms */ store_string (fout, "SOUND_COMMAND", sound_command); store_int (fout, "SOUND_PLAY_ONS", sound_play_new_station); store_string (fout, "SOUND_ONS_FILE", sound_new_station); store_int (fout, "SOUND_PLAY_ONM", sound_play_new_message); store_string (fout, "SOUND_ONM_FILE", sound_new_message); store_int (fout, "SOUND_PLAY_PROX", sound_play_prox_message); store_string (fout, "SOUND_PROX_FILE", sound_prox_message); store_string (fout, "PROX_MIN", prox_min); store_string (fout, "PROX_MAX", prox_max); store_int (fout, "SOUND_PLAY_BAND", sound_play_band_open_message); store_string (fout, "SOUND_BAND_FILE", sound_band_open_message); store_string (fout, "BANDO_MIN", bando_min); store_string (fout, "BANDO_MAX", bando_max); store_int (fout, "SOUND_PLAY_WX_ALERT", sound_play_wx_alert_message); store_string (fout, "SOUND_WX_ALERT_FILE", sound_wx_alert_message); #ifdef HAVE_FESTIVAL /* Festival speech settings */ store_int (fout, "SPEAK_NEW_STATION",festival_speak_new_station); store_int (fout, "SPEAK_PROXIMITY_ALERT",festival_speak_proximity_alert); store_int (fout, "SPEAK_TRACKED_ALERT",festival_speak_tracked_proximity_alert); store_int (fout, "SPEAK_BAND_OPENING",festival_speak_band_opening); store_int (fout, "SPEAK_MESSAGE_ALERT",festival_speak_new_message_alert); store_int (fout, "SPEAK_MESSAGE_BODY",festival_speak_new_message_body); store_int (fout, "SPEAK_WEATHER_ALERT",festival_speak_new_weather_alert); store_int (fout, "SPEAK_ID",festival_speak_ID); #endif // HAVE_FESTIVAL store_int (fout, "ATV_SCREEN_ID", ATV_screen_ID); /* defaults */ store_long (fout, "DEFAULT_STATION_OLD", (long)sec_old); store_long (fout, "DEFAULT_STATION_CLEAR", (long)sec_clear); store_long (fout, "DEFAULT_AIRCRAFT_CLEAR", (long)aircraft_sec_clear); store_long(fout, "DEFAULT_STATION_REMOVE", (long)sec_remove); store_string (fout, "HELP_DATA", HELP_FILE); store_string (fout, "MESSAGE_COUNTER", message_counter); store_string (fout, "AUTO_MSG_REPLY", auto_reply_message); store_int (fout, "DISPLAY_PACKET_TYPE", Display_packet_data_type); store_int (fout, "BULLETIN_RANGE", bulletin_range); store_int(fout,"VIEW_MESSAGE_RANGE",vm_range); store_int(fout,"VIEW_MESSAGE_LIMIT",view_message_limit); store_int(fout,"PREDEF_MENU_LOAD",predefined_menu_from_file); store_string(fout,"PREDEF_MENU_FILE",predefined_object_definition_filename); store_int(fout, "READ_MESSAGES_PACKET_DATA_TYPE", Read_messages_packet_data_type); store_int(fout, "READ_MESSAGES_MINE_ONLY", Read_messages_mine_only); /* printer variables */ store_int (fout, "PRINT_ROTATED", print_rotated); store_int (fout, "PRINT_AUTO_ROTATION", print_auto_rotation); store_int (fout, "PRINT_AUTO_SCALE", print_auto_scale); store_int (fout, "PRINT_IN_MONOCHROME", print_in_monochrome); store_int (fout, "PRINT_INVERT_COLORS", print_invert); /* Rain Gauge Type, set in the Serial Weather interface properties dialog, but really a global default */ store_int (fout, "RAIN_GAUGE_TYPE", WX_rain_gauge_type); /* list attributes */ for (i = 0; i < LST_NUM; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "LIST%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "H", sizeof(name) - 1 - strlen(name)); store_int (fout, name, list_size_h[i]); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "W", sizeof(name) - 1 - strlen(name)); store_int (fout, name, list_size_w[i]); } store_int (fout, "TRACK_ME", track_me); store_string (fout, "TRACKING_STATION_CALLSIGN", tracking_station_call); store_int (fout, "MAP_CHOOSER_EXPAND_DIRS", map_chooser_expand_dirs); store_int (fout, "ST_DIRECT_TIMEOUT", st_direct_timeout); store_int (fout, "DEAD_RECKONING_TIMEOUT", dead_reckoning_timeout); store_int (fout, "SERIAL_CHAR_PACING", serial_char_pacing); store_int (fout, "TRAIL_SEGMENT_TIME", trail_segment_time); store_int (fout, "TRAIL_SEGMENT_DISTANCE", trail_segment_distance); store_int (fout, "RINO_DOWNLOAD_INTERVAL", RINO_download_interval); store_int (fout, "SNAPSHOT_INTERVAL", snapshot_interval); if (debug_level & 1) { fprintf(stderr,"Save Data Stop\n"); } // Close the config_file_tmp file, we're done writing it. (void)fclose (fout); get_user_base_dir(CONFIG_FILE, config_file, sizeof(config_file)); get_user_base_dir(CONFIG_FILE_BAK1, config_file_bak1, sizeof(config_file_bak1)); get_user_base_dir(CONFIG_FILE_BAK2, config_file_bak2, sizeof(config_file_bak2)); get_user_base_dir(CONFIG_FILE_BAK3, config_file_bak3, sizeof(config_file_bak3)); get_user_base_dir(CONFIG_FILE_BAK4,config_file_bak4, sizeof(config_file_bak4)); // // Rename the old config files so that we have a few // backups in case of corruption: // // xastir.cnf.3 -> xastir.cnf.4 // xastir.cnf.2 -> xastir.cnf.3 // xastir.cnf.1 -> xastir.cnf.2 // xastir.cnf -> xastir.cnf.1 // xastir.cnf.tmp -> xastir.cnf // // Rename bak3 to bak4 // NOTE: bak3 won't exist until a few saves have happened. // // Check whether bak3 exists if (stat(config_file_bak3, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak3); return; } if ( rename (config_file_bak3, config_file_bak4) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak3, config_file_bak4); // Attempt to restore to previous state // Nothing to do here! return; } } // Rename bak2 to bak3 // NOTE: bak2 won't exist until a few saves have happened. // // Check whether bak2 exists if (stat(config_file_bak2, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak2); return; } if ( rename (config_file_bak2, config_file_bak3) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak2, config_file_bak3); // Attempt to restore to previous state rename (config_file_bak4, config_file_bak3); // Nothing to do here! return; } } // Rename bak1 to bak2 // NOTE: bak1 won't exist until a couple of saves have happened. // // Check whether bak1 exists if (stat(config_file_bak1, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak1); return; } if ( rename (config_file_bak1, config_file_bak2) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak1, config_file_bak2); // Attempt to restore to previous state rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } // NOTE: To minimize the possibility that we'll end up with a // missing or corrupt config file, we actually should COPY // config_file to config_file_bak1 here so that there's always a // config file in place no matter what. In the next block we can do // the rename of config_file_tmp to config_file and not miss a beat. // See "man 2 rename". // Rename config to bak1 // NOTE: config won't exist until the first save happens. // // Check whether config exists if (stat(config_file, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file); return; } // // Note "copy_file()" instead of "rename()". This // assures that we always have a config file in place no // matter what errors might occur. // if ( copy_file(config_file, config_file_bak1) ) { fprintf(stderr, "Couldn't copy %s to %s, cancelling save_data()\n", config_file, config_file_bak1); // Attempt to restore to previous state rename (config_file_bak2, config_file_bak1); rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } // Rename config.tmp to xastir.cnf // NOTE: config won't exist until the first save happens. // // Check whether config.tmp exists if (stat(config_file_tmp, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_tmp); return; } if ( rename (config_file_tmp, config_file) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_tmp, config_file); // Attempt to restore to previous state rename (config_file_bak1, config_file); rename (config_file_bak2, config_file_bak1); rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } } else { // Couldn't create new config (out of filespace?). fprintf(stderr,"Couldn't open config file for appending: %s\n", config_file); // Back out the changes done to the config and backup files. // // Continue using original config file. if ( rename (config_file_bak1, config_file) ) { // Problem here, couldn't rename bak1 file to xastir.cnf fprintf(stderr, "Couldn't recover %s from %s file\n", config_file, config_file_bak1); return; } } } void load_data_or_default(void) { int i; char name_temp[20]; char name[50]; long temp; char user_base_dir[MAX_VALUE]; // Force the locale to a default so that we don't have // conversion problems due to LANG/LC_ALL/LC_CTYPE/LC_NUMERIC // environment variables. (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); /* language */ if (!get_string ("LANGUAGE", lang_to_use, sizeof(lang_to_use)) || lang_to_use[0] == '\0') { xastir_snprintf(lang_to_use, sizeof(lang_to_use), "English"); } /* my data */ if (!get_string ("STATION_CALLSIGN", my_callsign, sizeof(my_callsign)) || my_callsign[0] == '\0') { xastir_snprintf(my_callsign, sizeof(my_callsign), "NOCALL"); } if (!get_string ("STATION_LAT", my_lat, sizeof(my_lat)) || my_lat[0] == '\0') { xastir_snprintf(my_lat, sizeof(my_lat), "0000.000N"); } if ( (my_lat[4] != '.') || (my_lat[8] != 'N' && my_lat[8] != 'S') ) { xastir_snprintf(my_lat, sizeof(my_lat), "0000.000N"); fprintf(stderr,"Invalid Latitude, changing it to 0000.000N\n"); } // convert old data to high prec temp = convert_lat_s2l (my_lat); convert_lat_l2s (temp, my_lat, sizeof(my_lat), CONVERT_HP_NOSP); if (!get_string ("STATION_LONG", my_long, sizeof(my_long)) || my_long[0] == '\0') { xastir_snprintf(my_long, sizeof(my_long), "00000.000W"); } if ( (my_long[5] != '.') || (my_long[9] != 'W' && my_long[9] != 'E') ) { xastir_snprintf(my_long, sizeof(my_long), "00000.000W"); fprintf(stderr,"Invalid Longitude, changing it to 00000.000W\n"); } // convert old data to high prec temp = convert_lon_s2l (my_long); convert_lon_l2s (temp, my_long, sizeof(my_long), CONVERT_HP_NOSP); position_amb_chars = get_int ("STATION_TRANSMIT_AMB", 0, 4, 0); if (!get_char ("STATION_GROUP", &my_group)) { my_group = '/'; } if (!get_char ("STATION_SYMBOL", &my_symbol)) { my_symbol = 'x'; } if (!get_char ("STATION_MESSAGE_TYPE", &aprs_station_message_type)) { aprs_station_message_type = '='; } // Empty string is ok here. if (!get_string ("STATION_POWER", my_phg, sizeof(my_phg))) { my_phg[0] = '\0'; } if (!get_string ("STATION_COMMENTS", my_comment, sizeof(my_comment)) || my_comment[0] == '\0') { // We used to put "XASTIR-Linux" (or similar) here... //xastir_snprintf (my_comment, sizeof(my_comment), "XASTIR-%s", XASTIR_SYSTEM); // Now we put the empty string. my_comment[0] = '\0'; } /* replacing defined MY_TRAIL_DIFF_COLOR from db.c, default 0 matches default value of MY_TRAIL_DIFF_COLOR to show all mycall-ssids in the same color. */ my_trail_diff_color = get_int ("MY_TRAIL_DIFF_COLOR", 0, 1, 0); /* default values */ screen_width = get_long ("SCREEN_WIDTH", 61l, 10000l, 590l); screen_height = get_long ("SCREEN_HEIGHT", 1l, 10000l, 420l); // screen_x_offset = (Position)get_int ("SCREEN_X_OFFSET", 0, 10000, 0); // screen_y_offset = (Position)get_int ("SCREEN_Y_OFFSET", 0, 10000, 0); center_latitude = get_long ("SCREEN_LAT", 0l, 64800000l, 32400000l); center_longitude = get_long ("SCREEN_LONG", 0l, 129600000l, 64800000l); // Empty string is ok here if (!get_string("RELAY_DIGIPEAT_CALLS", relay_digipeater_calls, sizeof(relay_digipeater_calls))) { xastir_snprintf (relay_digipeater_calls, sizeof(relay_digipeater_calls), "WIDE1-1"); } // Make them all upper-case. (void)to_upper(relay_digipeater_calls); // And take out all spaces (void)remove_all_spaces(relay_digipeater_calls); coordinate_system = get_int ("COORDINATE_SYSTEM", 0, 5, USE_DDMMMM); scale_y = get_long ("SCREEN_ZOOM", 1l, 500000l, 327680l); scale_x = get_x_scale(center_longitude,center_latitude,scale_y); map_background_color = get_int ("MAP_BGCOLOR", 0, 11, 0); map_color_fill = get_int ( "MAP_DRAW_FILLED_COLORS", 0, 1, 1); #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) imagemagick_gamma_adjust = get_float("IMAGEMAGICK_GAMMA_ADJUST", 0.0, 1.0, 0.0); #endif // HAVE_MAGICK raster_map_intensity = get_float("RASTER_MAP_INTENSITY", 0.0, 1.0, 1.0); #endif // NO_GRAPHICS if (!get_string ("PRINT_PROGRAM", printer_program, sizeof(printer_program)) || printer_program[0] == '\0') { xastir_snprintf(printer_program, sizeof(printer_program), "%s", #ifdef LPR_PATH // Path to LPR if defined LPR_PATH #else // LPR_PATH // Empty path "" #endif // LPR_PATH ); } if (!get_string ("PREVIEWER_PROGRAM", previewer_program, sizeof(previewer_program)) || previewer_program[0] == '\0') { xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", #ifdef GV_PATH // Path to GV if defined GV_PATH #else // GV_PATH // Empty path "" #endif // GV_PATH ); } letter_style = get_int ("MAP_LETTERSTYLE", 0, 3, 0 ); icon_outline_style = get_int ("MAP_ICONOUTLINESTYLE", 0, 3, 0); wx_alert_style = get_int ("MAP_WX_ALERT_STYLE", 0, 1, 0); // Empty string is ok here if (!get_string("ALTNET_CALL", altnet_call, sizeof(altnet_call))) xastir_snprintf(altnet_call, sizeof(altnet_call), "XASTIR"); altnet = get_int("ALTNET", 0, 1, 0); skip_dupe_checking = get_int("SKIP_DUPE_CHECK", 0, 1, 0); if (!get_string ("AUTO_MAP_DIR", AUTO_MAP_DIR, sizeof(AUTO_MAP_DIR)) || AUTO_MAP_DIR[0] == '\0') { xastir_snprintf(AUTO_MAP_DIR, sizeof(AUTO_MAP_DIR), "%s", get_data_base_dir ("maps")); } if (!get_string ("ALERT_MAP_DIR", ALERT_MAP_DIR, sizeof(ALERT_MAP_DIR)) || ALERT_MAP_DIR[0] == '\0') { xastir_snprintf(ALERT_MAP_DIR, sizeof(ALERT_MAP_DIR), "%s", get_data_base_dir ("Counties")); } if (!get_string ("SELECTED_MAP_DIR", SELECTED_MAP_DIR, sizeof(SELECTED_MAP_DIR)) || SELECTED_MAP_DIR[0] == '\0') { xastir_snprintf(SELECTED_MAP_DIR, sizeof(SELECTED_MAP_DIR), "%s", get_data_base_dir ("maps")); } if (!get_string ("SELECTED_MAP_DATA", SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA)) || SELECTED_MAP_DATA[0] == '\0') { xastir_snprintf(SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA), "%s", "config/selected_maps.sys"); } // get the base path for the user base directory, so we can use it over // and over without having to call get_user_base_dir a godzillion times. get_user_base_dir("",user_base_dir, sizeof(user_base_dir)); // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, SELECTED_MAP_DATA, strlen(user_base_dir)) == 0) xastir_snprintf(SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA), "%s", "config/selected_maps.sys"); if (!get_string ("MAP_INDEX_DATA", MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA)) || MAP_INDEX_DATA[0] == '\0') { xastir_snprintf(MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA), "%s", "config/map_index.sys"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, MAP_INDEX_DATA, strlen(user_base_dir)) == 0) xastir_snprintf(MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA), "%s", "config/map_index.sys"); if (!get_string ("SYMBOLS_DIR", SYMBOLS_DIR, sizeof(SYMBOLS_DIR)) || SYMBOLS_DIR[0] == '\0') { xastir_snprintf(SYMBOLS_DIR, sizeof(SYMBOLS_DIR), "%s", get_data_base_dir ("symbols")); } if (!get_string ("SOUND_DIR", SOUND_DIR, sizeof(SOUND_DIR)) || SOUND_DIR[0] == '\0') { xastir_snprintf(SOUND_DIR, sizeof(SOUND_DIR), "%s", get_data_base_dir ("sounds")); } if (!get_string ("GROUP_DATA_FILE", group_data_file, sizeof(group_data_file)) || group_data_file[0] == '\0') { xastir_snprintf(group_data_file, sizeof(group_data_file), "%s", "config/groups"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, group_data_file, strlen(user_base_dir)) == 0) xastir_snprintf(group_data_file, sizeof(group_data_file), "%s", "config/groups"); if (!get_string ("GNIS_FILE", locate_gnis_filename, sizeof(locate_gnis_filename)) || locate_gnis_filename[0] == '\0') { xastir_snprintf(locate_gnis_filename, sizeof(locate_gnis_filename), "%s", get_data_base_dir ("GNIS/WA.gnis")); } if (!get_string ("GEOCODE_FILE", geocoder_map_filename, sizeof(geocoder_map_filename)) || geocoder_map_filename[0] == '\0') { xastir_snprintf(geocoder_map_filename, sizeof(geocoder_map_filename), "%s", get_data_base_dir ("GNIS/geocode")); } show_destination_mark = get_int ("SHOW_FIND_TARGET", 0, 1, 1); /* maps */ long_lat_grid = get_int ("MAPS_LONG_LAT_GRID", 0, 1, 1); draw_labeled_grid_border = get_int ("MAPS_LABELED_GRID_BORDER", 0, 1, 0); map_color_levels = get_int ("MAPS_LEVELS", 0, 1, 1); map_labels = get_int ("MAPS_LABELS", 0, 1, 1); map_lock_pan_zoom = get_int ("MAP_LOCK_PAN_ZOOM", 0, 1, 0); map_auto_maps = get_int ("MAPS_AUTO_MAPS", 0, 1, 0); auto_maps_skip_raster = get_int ("MAPS_AUTO_MAPS_SKIP_RASTER", 0, 1, 0); index_maps_on_startup = get_int ("MAPS_INDEX_ON_STARTUP", 0, 1, 1); if (!get_string ("MAPS_LABEL_FONT_TINY", rotated_label_fontname[FONT_TINY], sizeof(rotated_label_fontname[FONT_TINY])) || rotated_label_fontname[FONT_TINY][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_TINY], sizeof(rotated_label_fontname[FONT_TINY]), "-adobe-helvetica-medium-r-normal--8-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_SMALL", rotated_label_fontname[FONT_SMALL], sizeof(rotated_label_fontname[FONT_SMALL])) || rotated_label_fontname[FONT_SMALL][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_SMALL], sizeof(rotated_label_fontname[FONT_SMALL]), "-adobe-helvetica-medium-r-normal--10-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_MEDIUM", rotated_label_fontname[FONT_MEDIUM], sizeof(rotated_label_fontname[FONT_MEDIUM])) || rotated_label_fontname[FONT_MEDIUM][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_MEDIUM], sizeof(rotated_label_fontname[FONT_MEDIUM]), "-adobe-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1"); } // NOTE: FONT_DEFAULT points to FONT_MEDIUM if (!get_string ("MAPS_LABEL_FONT_LARGE", rotated_label_fontname[FONT_LARGE], sizeof(rotated_label_fontname[FONT_LARGE])) || rotated_label_fontname[FONT_LARGE][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_LARGE], sizeof(rotated_label_fontname[FONT_LARGE]), "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_HUGE", rotated_label_fontname[FONT_HUGE], sizeof(rotated_label_fontname[FONT_HUGE])) || rotated_label_fontname[FONT_HUGE][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_HUGE], sizeof(rotated_label_fontname[FONT_HUGE]), "-adobe-helvetica-medium-r-normal--24-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_BORDER", rotated_label_fontname[FONT_BORDER], sizeof(rotated_label_fontname[FONT_BORDER])) || rotated_label_fontname[FONT_BORDER][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_BORDER], sizeof(rotated_label_fontname[FONT_BORDER]), "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-1"); } if (!get_string ("SYSTEM_FIXED_FONT", rotated_label_fontname[FONT_SYSTEM], sizeof(rotated_label_fontname[FONT_SYSTEM])) || rotated_label_fontname[FONT_SYSTEM][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_SYSTEM], sizeof(rotated_label_fontname[FONT_SYSTEM]), "fixed"); // NOTE: This same default font is hard-coded into // main.c, to be used for the case when the user enters // an invalid font (so the program won't crash). } if (!get_string ("STATION_FONT", rotated_label_fontname[FONT_STATION], sizeof(rotated_label_fontname[FONT_STATION])) || rotated_label_fontname[FONT_STATION][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_STATION], sizeof(rotated_label_fontname[FONT_STATION]), "fixed"); // NOTE: This same default font is hard-coded into // main.c, to be used for the case when the user enters // an invalid font (so the program won't crash). } if (!get_string ("ATV_ID_FONT", rotated_label_fontname[FONT_ATV_ID], sizeof(rotated_label_fontname[FONT_ATV_ID])) || rotated_label_fontname[FONT_ATV_ID][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_ATV_ID], sizeof(rotated_label_fontname[FONT_ATV_ID]), "-*-helvetica-*-*-*-*-*-240-*-*-*-*-*-*"); } //N0VH #if defined(HAVE_MAGICK) net_map_timeout = get_int ("NET_MAP_TIMEOUT", 10, 300, 120); #endif //HAVE_MAGICK #ifdef HAVE_LIBGEOTIFF DRG_XOR_colors = get_int ("DRG_XOR_COLORS", 0, 1, 0); DRG_show_colors[0] = get_int ("DRG_SHOW_COLORS_0", 0, 1, 1); DRG_show_colors[1] = get_int ("DRG_SHOW_COLORS_1", 0, 1, 1); DRG_show_colors[2] = get_int ("DRG_SHOW_COLORS_2", 0, 1, 1); DRG_show_colors[3] = get_int ("DRG_SHOW_COLORS_3", 0, 1, 1); DRG_show_colors[4] = get_int ("DRG_SHOW_COLORS_4", 0, 1, 1); DRG_show_colors[5] = get_int ("DRG_SHOW_COLORS_5", 0, 1, 1); DRG_show_colors[6] = get_int ("DRG_SHOW_COLORS_6", 0, 1, 1); DRG_show_colors[7] = get_int ("DRG_SHOW_COLORS_7", 0, 1, 1); DRG_show_colors[8] = get_int ("DRG_SHOW_COLORS_8", 0, 1, 1); DRG_show_colors[9] = get_int ("DRG_SHOW_COLORS_9", 0, 1, 1); DRG_show_colors[10] = get_int ("DRG_SHOW_COLORS_10", 0, 1, 1); DRG_show_colors[11] = get_int ("DRG_SHOW_COLORS_11", 0, 1, 1); DRG_show_colors[12] = get_int ("DRG_SHOW_COLORS_12", 0, 1, 1); #endif // HAVE_LIBGEOTIFF // filter values // NOT SAVED: Select_.none Select_.mine = get_int ("DISPLAY_MY_STATION", 0, 1, 1); Select_.tnc = get_int ("DISPLAY_TNC_STATIONS", 0, 1, 1); Select_.direct = get_int ("DISPLAY_TNC_DIRECT_STATIONS", 0, 1, 1); Select_.via_digi = get_int ("DISPLAY_TNC_VIADIGI_STATIONS", 0, 1, 1); Select_.net = get_int ("DISPLAY_NET_STATIONS", 0, 1, 1); Select_.tactical = get_int ("DISPLAY_TACTICAL_STATIONS", 0, 1, 0); Select_.old_data = get_int ("DISPLAY_OLD_STATION_DATA", 0, 1, 0); Select_.stations = get_int ("DISPLAY_STATIONS", 0, 1, 1); Select_.fixed_stations = get_int ("DISPLAY_FIXED_STATIONS", 0, 1, 1); Select_.moving_stations = get_int ("DISPLAY_MOVING_STATIONS", 0, 1, 1); Select_.weather_stations = get_int ("DISPLAY_WEATHER_STATIONS", 0, 1, 1); Select_.CWOP_wx_stations = get_int ("DISPLAY_CWOP_WX_STATIONS", 0, 1, 1); Select_.objects = get_int ("DISPLAY_OBJECTS", 0, 1, 1); Select_.weather_objects = get_int ("DISPLAY_STATION_WX_OBJ", 0, 1, 1); Select_.gauge_objects = get_int ("DISPLAY_WATER_GAGE_OBJ", 0, 1, 1); Select_.other_objects = get_int ("DISPLAY_OTHER_OBJECTS", 0, 1, 1); Select_.aircraft_objects = get_int ("DISPLAY_AIRCRAFT_OBJECTS", 0, 1, 1); Select_.vessel_objects = get_int ("DISPLAY_VESSEL_OBJECTS", 0, 1, 1); // display values Display_.callsign = get_int ("DISPLAY_CALLSIGN", 0, 1, 1); Display_.label_all_trackpoints = get_int ("DISPLAY_LABEL_ALL_TRACKPOINTS", 0, 1, 0); Display_.symbol = get_int ("DISPLAY_SYMBOL", 0, 1, 1); Display_.symbol_rotate = get_int ("DISPLAY_SYMBOL_ROTATE", 0, 1, 1); Display_.phg = get_int ("DISPLAY_STATION_PHG", 0, 1, 0); Display_.default_phg = get_int ("DISPLAY_DEFAULT_PHG", 0, 1, 0); Display_.phg_of_moving = get_int ("DISPLAY_MOBILES_PHG", 0, 1, 0); Display_.altitude = get_int ("DISPLAY_ALTITUDE", 0, 1, 0); Display_.course = get_int ("DISPLAY_COURSE", 0, 1, 0); Display_.speed = get_int ("DISPLAY_SPEED", 0, 1, 1); Display_.speed_short = get_int ("DISPLAY_SPEED_SHORT", 0, 1, 0); Display_.dist_bearing = get_int ("DISPLAY_DIST_COURSE", 0, 1, 0); Display_.weather = get_int ("DISPLAY_WEATHER", 0, 1, 1); Display_.weather_text = get_int ("DISPLAY_STATION_WX", 0, 1, 1); Display_.temperature_only = get_int ("DISPLAY_TEMP_ONLY", 0, 1, 0); Display_.wind_barb = get_int ("DISPLAY_WIND_BARB", 0, 1, 1); Display_.trail = get_int ("DISPLAY_STATION_TRAILS", 0, 1, 1); Display_.last_heard = get_int ("DISPLAY_LAST_HEARD", 0, 1, 0); Display_.ambiguity = get_int ("DISPLAY_POSITION_AMB", 0, 1, 1); Display_.df_data = get_int ("DISPLAY_DF_INFO", 0, 1, 1); Display_.df_beamwidth_data = get_int ("DISPLAY_DF_BEAMWIDTH_INFO", 0, 1, 1); Display_.df_bearing_data = get_int ("DISPLAY_DF_BEARING_INFO", 0, 1, 0); Display_.dr_data = get_int ("DISPLAY_DEAD_RECKONING_INFO", 0, 1, 1); Display_.dr_arc = get_int ("DISPLAY_DEAD_RECKONING_ARC", 0, 1, 1); Display_.dr_course = get_int ("DISPLAY_DEAD_RECKONING_COURSE", 0, 1, 1); Display_.dr_symbol = get_int ("DISPLAY_DEAD_RECKONING_SYMBOL", 0, 1, 1); english_units = get_int ("DISPLAY_UNITS_ENGLISH", 0, 1, 0); do_dbstatus = get_int ("DISPLAY_DIST_BEAR_STATUS", 0, 1, 0); CAD_show_label = get_int ("DISPLAY_CAD_OBJECT_LABEL", 0, 1, 1); CAD_show_raw_probability = get_int ("DISPLAY_CAD_OBJECT_PROBABILITY", 0, 1, 1 ); CAD_show_comment = get_int ("DISPLAY_CAD_OBJECT_COMMENT", 0, 1, 1 ); CAD_show_area = get_int ("DISPLAY_CAD_OBJECT_AREA", 0, 1, 1 ); transmit_disable = get_int ("DISABLE_TRANSMIT", 0, 1, 0); posit_tx_disable = get_int ("DISABLE_POSIT_TX", 0, 1, 0); object_tx_disable = get_int ("DISABLE_OBJECT_TX", 0, 1, 0); enable_server_port = get_int ("ENABLE_SERVER_PORT", 0, 1, 0); for (i = 0; i < MAX_IFACE_DEVICES; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "DEVICE%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TYPE", sizeof(name) - 1 - strlen(name)); devices[i].device_type = get_int (name, 0,MAX_IFACE_DEVICE_TYPES,DEVICE_NONE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "NAME", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_name, sizeof(devices[i].device_name))) { devices[i].device_name[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RADIO_PORT", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].radio_port, sizeof(devices[i].radio_port))) xastir_snprintf(devices[i].radio_port, sizeof(devices[i].radio_port), "0"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "CONVERSE_CMD", sizeof(name) - 1 - strlen(name)); if (!get_string (name, devices[i].device_converse_string, sizeof(devices[i].device_converse_string)) || (strlen(devices[i].device_converse_string) == 0)) xastir_snprintf(devices[i].device_converse_string, sizeof(devices[i].device_converse_string), "k"); #ifdef HAVE_DB xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_TYPE", sizeof(name) - 1 - strlen(name)); devices[i].database_type = get_int (name, 0,MAX_DB_TYPE,MAX_DB_TYPE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA_TYPE", sizeof(name) - 1 - strlen(name)); devices[i].database_schema_type = get_int (name, 0,MAX_XASTIR_SCHEMA,XASTIR_SCHEMA_SIMPLE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_USERNAME", sizeof(name) - 1 - strlen(name)); // default to xastir if (!get_string (name, devices[i].database_username, sizeof(devices[i].database_username))) xastir_snprintf(devices[i].database_username, sizeof(devices[i].database_username), "xastir"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA", sizeof(name) - 1 - strlen(name)); // default to xastir if (!get_string (name, devices[i].database_schema, sizeof(devices[i].database_schema))) xastir_snprintf(devices[i].database_schema, sizeof(devices[i].database_schema), "xastir"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_UNIX_SOCKET", sizeof(name) - 1 - strlen(name)); // empty string is ok here if (!get_string (name, devices[i].database_unix_socket, sizeof(devices[i].database_unix_socket))) xastir_snprintf(devices[i].database_unix_socket, sizeof(devices[i].database_unix_socket), "0"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "QUERY_ON_STARTUP", sizeof(name) - 1 - strlen(name)); devices[i].query_on_startup = get_int (name, 0,1,0); #endif /* HAVE_DB */ xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "INTERFACE_COMMENT", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].comment, sizeof(devices[i].comment))) { devices[i].comment[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "HOST", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_name, sizeof(devices[i].device_host_name))) { devices[i].device_host_name[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "PASSWD", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_pswd, sizeof(devices[i].device_host_pswd))) { devices[i].device_host_pswd[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "FILTER_PARAMS", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_filter_string, sizeof(devices[i].device_host_filter_string))) { devices[i].device_host_filter_string[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO1", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto1, sizeof(devices[i].unproto1))) { devices[i].unproto1[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO2", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto2, sizeof(devices[i].unproto2))) { devices[i].unproto2[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO3", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto3, sizeof(devices[i].unproto3))) { devices[i].unproto3[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO_IGATE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto_igate, sizeof(devices[i].unproto_igate)) || devices[i].unproto_igate[0] == '\0') { xastir_snprintf(devices[i].unproto_igate, sizeof(devices[i].unproto_igate), "WIDE2-1"); } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_UP_FILE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].tnc_up_file, sizeof(devices[i].tnc_up_file))) { devices[i].tnc_up_file[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_DOWN_FILE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].tnc_down_file, sizeof(devices[i].tnc_down_file))) { devices[i].tnc_down_file[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXDELAY", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].txdelay, sizeof(devices[i].txdelay))) xastir_snprintf(devices[i].txdelay, sizeof(devices[i].txdelay), "40"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_PERSISTENCE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].persistence, sizeof(devices[i].persistence))) xastir_snprintf(devices[i].persistence, sizeof(devices[i].persistence), "63"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_SLOTTIME", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].slottime, sizeof(devices[i].slottime))) xastir_snprintf(devices[i].slottime, sizeof(devices[i].slottime), "10"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXTAIL", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].txtail, sizeof(devices[i].txtail))) xastir_snprintf(devices[i].txtail, sizeof(devices[i].txtail), "30"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_FULLDUPLEX", sizeof(name) - 1 - strlen(name)); devices[i].fullduplex = get_int (name, 0, 1, 0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_INIT_KISSMODE", sizeof(name) - 1 - strlen(name)); devices[i].init_kiss = get_int (name, 0, 1, 0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SPEED", sizeof(name) - 1 - strlen(name)); devices[i].sp = get_int (name, 0,230400,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "STYLE", sizeof(name) - 1 - strlen(name)); devices[i].style = get_int (name, 0,2,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "IGATE_OPTION", sizeof(name) - 1 - strlen(name)); devices[i].igate_options = get_int (name, 0,2,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TXMT", sizeof(name) - 1 - strlen(name)); devices[i].transmit_data = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RELAY_DIGIPEAT", sizeof(name) - 1 - strlen(name)); devices[i].relay_digipeat = get_int (name, 0,1,1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RECONN", sizeof(name) - 1 - strlen(name)); devices[i].reconnect = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "ONSTARTUP", sizeof(name) - 1 - strlen(name)); devices[i].connect_on_startup = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "GPSRETR", sizeof(name) - 1 - strlen(name)); devices[i].gps_retrieve = get_int (name, 0,255,DEFAULT_GPS_RETR); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SETTIME", sizeof(name) - 1 - strlen(name)); devices[i].set_time = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNCEXTRADELAY", sizeof(name) - 1 - strlen(name)); devices[i].tnc_extra_delay = get_int (name, 0,9999999,0); } /* TNC */ log_tnc_data = get_int ("TNC_LOG_DATA", 0,1,0); if (!get_string ("LOGFILE_TNC", LOGFILE_TNC, sizeof(LOGFILE_TNC)) || LOGFILE_TNC[0] == '\0') { xastir_snprintf(LOGFILE_TNC, sizeof(LOGFILE_TNC), "%s", "logs/tnc.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_TNC, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_TNC, sizeof(LOGFILE_TNC), "%s", "logs/tnc.log"); /* NET */ log_net_data = get_int ("NET_LOG_DATA", 0,1,0); operate_as_an_igate = get_int ("NET_RUN_AS_IGATE", 0,2,0); log_igate = get_int ("LOG_IGATE", 0,1,0); NETWORK_WAITTIME = get_int ("NETWORK_WAITTIME", 10,120,10); // LOGGING log_wx = get_int ("LOG_WX", 0,1,0); log_message_data = get_int ("LOG_MESSAGE", 0, 1, 0); log_wx_alert_data = get_int ("LOG_WX_ALERT", 0, 1, 0); if (!get_string ("LOGFILE_IGATE", LOGFILE_IGATE, sizeof(LOGFILE_IGATE)) || LOGFILE_IGATE[0] == '\0') { xastir_snprintf(LOGFILE_IGATE, sizeof(LOGFILE_IGATE), "%s", "logs/igate.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_IGATE, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_IGATE, sizeof(LOGFILE_IGATE), "%s", "logs/igate.log"); if (!get_string ("LOGFILE_NET", LOGFILE_NET, sizeof(LOGFILE_NET)) || LOGFILE_NET[0] == '\0') { xastir_snprintf(LOGFILE_NET, sizeof(LOGFILE_NET), "%s", "logs/net.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_NET, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_NET, sizeof(LOGFILE_NET), "%s", "logs/net.log"); if (!get_string ("LOGFILE_WX", LOGFILE_WX, sizeof(LOGFILE_WX)) || LOGFILE_WX[0] == '\0') { xastir_snprintf(LOGFILE_WX, sizeof(LOGFILE_WX), "%s", "logs/wx.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_WX, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_WX, sizeof(LOGFILE_WX), "%s", "logs/wx.log"); if (!get_string ("LOGFILE_MESSAGE", LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE)) || LOGFILE_MESSAGE[0] == '\0') { xastir_snprintf(LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE), "%s", "logs/message.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_MESSAGE, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE), "%s", "logs/message.log"); if (!get_string ("LOGFILE_WX_ALERT", LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT)) || LOGFILE_WX_ALERT[0] == '\0') { xastir_snprintf(LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT), "%s", "logs/wx_alert.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_WX_ALERT, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT), "%s", "logs/wx_alert.log"); // SNAPSHOTS snapshots_enabled = get_int ("SNAPSHOTS_ENABLED", 0,1,0); // KML SNAPSHOTS kmlsnapshots_enabled = get_int ("KMLSNAPSHOTS_ENABLED", 0,1,0); /* WX ALERTS */ WX_ALERTS_REFRESH_TIME = (time_t) get_long ("WX_ALERTS_REFRESH_TIME", 10l, 86400l, 60l); /* gps */ gps_time = (time_t) get_long ("GPS_TIME", 1l, 86400l, 60l); /* POSIT RATE */ POSIT_rate = (time_t) get_long ("POSIT_RATE", 0l, 86400l, 30*60l); /* OBJECT RATE */ OBJECT_rate = (time_t) get_long ("OBJECT_RATE", 1l, 86400l, 30*60l); /* UPDATE DR RATE */ update_DR_rate = (time_t) get_long ("UPDATE_DR_RATE", 1l, 86400l, 30l); /* station broadcast type */ output_station_type = get_int ("BST_TYPE", 0,5,0); #ifdef TRANSMIT_RAW_WX /* raw wx transmit */ transmit_raw_wx = get_int ("BST_WX_RAW", 0,1,0); #endif // TRANSMIT_RAW_WX /* compressed posit transmit */ transmit_compressed_posit = get_int ("BST_COMPRESSED_POSIT", 0,1,0); /* compressed objects/items transmit */ transmit_compressed_objects_items = get_int ("COMPRESSED_OBJECTS_ITEMS", 0,1,0); smart_beaconing = get_int ("SMART_BEACONING", 0,1,1); sb_turn_min = get_int ("SB_TURN_MIN", 1,360,20); sb_turn_slope = get_int ("SB_TURN_SLOPE", 0,360,25); sb_turn_time = get_int ("SB_TURN_TIME", 0,3600,5); sb_posit_fast = get_int ("SB_POSIT_FAST", 1,1440,60); sb_posit_slow = get_int ("SB_POSIT_SLOW", 1,1440,30); sb_low_speed_limit = get_int ("SB_LOW_SPEED_LIMIT", 0,999,2); sb_high_speed_limit = get_int ("SB_HIGH_SPEED_LIMIT", 0,999,60); pop_up_new_bulletins = get_int ("POP_UP_NEW_BULLETINS", 0,1,1); view_zero_distance_bulletins = get_int ("VIEW_ZERO_DISTANCE_BULLETINS", 0,1,1); warn_about_mouse_modifiers = get_int ("WARN_ABOUT_MOUSE_MODIFIERS", 0,1,1); /* Audio Alarms*/ // Empty string is ok here. if (!get_string ("SOUND_COMMAND", sound_command, sizeof(sound_command))) xastir_snprintf(sound_command, sizeof(sound_command), "play"); sound_play_new_station = get_int ("SOUND_PLAY_ONS", 0,1,0); if (!get_string ("SOUND_ONS_FILE", sound_new_station, sizeof(sound_new_station)) || sound_new_station[0] == '\0') { xastir_snprintf(sound_new_station, sizeof(sound_new_station), "newstation.wav"); } sound_play_new_message = get_int ("SOUND_PLAY_ONM", 0,1,0); if (!get_string ("SOUND_ONM_FILE", sound_new_message, sizeof(sound_new_message)) || sound_new_message[0] == '\0') { xastir_snprintf(sound_new_message, sizeof(sound_new_message), "newmessage.wav"); } sound_play_prox_message = get_int ("SOUND_PLAY_PROX", 0,1,0); if (!get_string ("SOUND_PROX_FILE", sound_prox_message, sizeof(sound_prox_message)) || sound_prox_message[0] == '\0') { xastir_snprintf(sound_prox_message, sizeof(sound_prox_message), "proxwarn.wav"); } if (!get_string ("PROX_MIN", prox_min, sizeof(prox_min)) || prox_min[0] == '\0') { xastir_snprintf(prox_min, sizeof(prox_min), "0.01"); } if (!get_string ("PROX_MAX", prox_max, sizeof(prox_max)) || prox_max[0] == '\0') { xastir_snprintf(prox_max, sizeof(prox_max), "10"); } sound_play_band_open_message = get_int ("SOUND_PLAY_BAND", 0,1,0); if (!get_string ("SOUND_BAND_FILE", sound_band_open_message, sizeof(sound_band_open_message)) || sound_band_open_message[0] == '\0') { xastir_snprintf(sound_band_open_message, sizeof(sound_band_open_message), "bandopen.wav"); } if (!get_string ("BANDO_MIN", bando_min, sizeof(bando_min)) || bando_min[0] == '\0') { xastir_snprintf(bando_min, sizeof(bando_min), "200"); } if (!get_string ("BANDO_MAX", bando_max, sizeof(bando_max)) || bando_max[0] == '\0') { xastir_snprintf(bando_max, sizeof(bando_max), "2000"); } sound_play_wx_alert_message = get_int ("SOUND_PLAY_WX_ALERT", 0,1,0); if (!get_string ("SOUND_WX_ALERT_FILE", sound_wx_alert_message, sizeof(sound_wx_alert_message)) || sound_wx_alert_message[0] == '\0') { xastir_snprintf(sound_wx_alert_message, sizeof(sound_wx_alert_message), "thunder.wav"); } #ifdef HAVE_FESTIVAL /* Festival Speech defaults */ festival_speak_new_station = get_int ("SPEAK_NEW_STATION",0,1,0); festival_speak_proximity_alert = get_int ("SPEAK_PROXIMITY_ALERT",0,1,0); festival_speak_tracked_proximity_alert = get_int ("SPEAK_TRACKED_ALERT",0,1,0); festival_speak_band_opening = get_int ("SPEAK_BAND_OPENING",0,1,0); festival_speak_new_message_alert = get_int ("SPEAK_MESSAGE_ALERT",0,1,0); festival_speak_new_message_body = get_int ("SPEAK_MESSAGE_BODY",0,1,0); festival_speak_new_weather_alert = get_int ("SPEAK_WEATHER_ALERT",0,1,0); festival_speak_ID = get_int ("SPEAK_ID",0,1,0); #endif // HAVE_FESTIVAL ATV_screen_ID = get_int ("ATV_SCREEN_ID",0,1,0); /* defaults */ sec_old = (time_t) get_long ("DEFAULT_STATION_OLD", 1l, 604800l, 4800l); sec_clear = (time_t) get_long ("DEFAULT_STATION_CLEAR", 1l, 604800l, 43200l); aircraft_sec_clear = (time_t) get_long ("DEFAULT_AIRCRAFT_CLEAR", 0l, 604800l, 0l); sec_remove = get_long("DEFAULT_STATION_REMOVE", 1l, 604800*2, sec_clear*2); if (!get_string ("MESSAGE_COUNTER", message_counter, sizeof(message_counter)) || message_counter[0] == '\0') { xastir_snprintf(message_counter, sizeof(message_counter), "00"); } message_counter[2] = '\0'; // Terminate at 2 chars // Check that chars are within the correct ranges if ( (message_counter[0] < '0') || (message_counter[1] < '0') || ( (message_counter[0] > '9') && (message_counter[0] < 'A') ) || ( (message_counter[1] > '9') && (message_counter[1] < 'A') ) || ( (message_counter[0] > 'Z') && (message_counter[0] < 'a') ) || ( (message_counter[1] > 'Z') && (message_counter[1] < 'a') ) || (message_counter[0] > 'z') || (message_counter[1] > 'z') ) { message_counter[0] = '0'; message_counter[1] = '0'; } if (!get_string ("AUTO_MSG_REPLY", auto_reply_message, sizeof(auto_reply_message)) || auto_reply_message[0] == '\0') { xastir_snprintf(auto_reply_message, sizeof(auto_reply_message), "Autoreply- No one is at the keyboard"); } Display_packet_data_type = get_int ("DISPLAY_PACKET_TYPE", 0,2,0); bulletin_range = get_int ("BULLETIN_RANGE", 0,99999,0); vm_range = get_int("VIEW_MESSAGE_RANGE", 0,99999,0); view_message_limit = get_int("VIEW_MESSAGE_LIMIT", 10000,99999,10000); predefined_menu_from_file = get_int("PREDEF_MENU_LOAD",0,1,0); if (!get_string ("PREDEF_MENU_FILE", predefined_object_definition_filename, sizeof(predefined_object_definition_filename)) || predefined_object_definition_filename[0] == '\0') { xastir_snprintf(predefined_object_definition_filename, sizeof(predefined_object_definition_filename), "predefined_SAR.sys"); } Read_messages_packet_data_type = get_int ("READ_MESSAGES_PACKET_DATA_TYPE", 0,2,0); Read_messages_mine_only = get_int ("READ_MESSAGES_MINE_ONLY", 0,1,0); /* printer variables */ print_rotated = get_int ("PRINT_ROTATED", 0,1,0); print_auto_rotation = get_int ("PRINT_AUTO_ROTATION", 0,1,1); print_auto_scale = get_int ("PRINT_AUTO_SCALE", 0,1,1); print_in_monochrome = get_int ("PRINT_IN_MONOCHROME", 0,1,0); print_invert = get_int ("PRINT_INVERT_COLORS", 0,1,0); // 0 = no correction WX_rain_gauge_type = get_int ("RAIN_GAUGE_TYPE", 0,3,0); /* list attributes */ for (i = 0; i < LST_NUM; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "LIST%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "H", sizeof(name) - 1 - strlen(name)); list_size_h[i] = get_int (name, -1,8192,-1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "W", sizeof(name) - 1 - strlen(name)); list_size_w[i] = get_int (name, -1,8192,-1); } // 0 = no tracking track_me = get_int ("TRACK_ME", 0,1,0); // store_string (fout, "TRACKING_STATION_CALLSIGN", tracking_station_call); if (!get_string ("TRACKING_STATION_CALLSIGN", tracking_station_call, sizeof(tracking_station_call))) { tracking_station_call[0] = '\0'; } map_chooser_expand_dirs = get_int ("MAP_CHOOSER_EXPAND_DIRS", 0,1,1); // One hour default st_direct_timeout = get_int ("ST_DIRECT_TIMEOUT", 1,60*60*24*30,60*60); // Ten minute default dead_reckoning_timeout = get_int ("DEAD_RECKONING_TIMEOUT", 1,60*60*24*30,60*10); // 1ms default serial_char_pacing = get_int ("SERIAL_CHAR_PACING", 0,50,1); // 45 minutes default, 12 hours max trail_segment_time = get_int ("TRAIL_SEGMENT_TIME", 0,12*60,45); // 1 degree default trail_segment_distance = get_int ("TRAIL_SEGMENT_DISTANCE", 0,45,1); // 0 minutes default (function disabled) RINO_download_interval = get_int ("RINO_DOWNLOAD_INTERVAL", 0,30,0); // 5 minutes default snapshot_interval = get_int ("SNAPSHOT_INTERVAL", 1,30,5); input_close(); } Xastir-Release-2.2.2/src/xa_config.h000066400000000000000000000023131501463444000172420ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #define MAX_VALUE 300 extern time_t next_time; char *get_user_base_dir(char *dir, char *dest, size_t dest_size); char *get_data_base_dir(char *dir); void save_data(void); void load_data_or_default(void); extern char xa_config_dir[1000]; /* cmdline option user config dir */ Xastir-Release-2.2.2/src/xastir.h000066400000000000000000000171041501463444000166230ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* All of the misc entry points to be included for all packages */ #ifndef _XASTIR_H #define _XASTIR_H // Macros that help us avoid warnings on 64-bit CPU's. // Borrowed from the freeciv project (also a GPL project). #define INT_TO_XTPOINTER(m_i) ((XtPointer)((long)(m_i))) #define XTPOINTER_TO_INT(m_p) ((int)((long)(m_p))) // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif #define SERIAL_KISS_RELAY_DIGI #include //#include "database.h" #include "util.h" #include "messages.h" #include "fcc_data.h" #include "rac_data.h" #define MAX_CALLSIGN 9 // Objects are up to 9 chars // black #define MY_FG_COLOR colors[0x08] #define MY_FOREGROUND_COLOR XmNforeground,colors[0x08] // gray73 #define MY_BG_COLOR colors[0xff] #define MY_BACKGROUND_COLOR XmNbackground,colors[0xff] // Latitude and longitude string formats. #define CONVERT_HP_NORMAL 0 #define CONVERT_HP_NOSP 1 #define CONVERT_LP_NORMAL 2 #define CONVERT_LP_NOSP 3 #define CONVERT_DEC_DEG 4 #define CONVERT_UP_TRK 5 #define CONVERT_DMS_NORMAL 6 #define CONVERT_VHP_NOSP 7 #define CONVERT_DMS_NORMAL_FORMATED 8 #define CONVERT_HP_NORMAL_FORMATED 9 #ifndef M_PI /* if not defined in math.h */ #define M_PI 3.14159265358979323846 #endif // M_PI #define SPEECH_TEST_STRING "Greeteengz frum eggzaster" /* GLOBAL DEFINES */ extern char dangerous_operation[200]; extern GC gc; extern Pixmap pixmap; extern Pixmap pixmap_final; extern Pixmap pixmap_alerts; extern Pixmap pixmap_50pct_stipple; extern Pixmap pixmap_25pct_stipple; extern Pixmap pixmap_13pct_stipple; extern Pixmap pixmap_wx_stipple; extern Widget appshell; extern int wait_to_redraw; /*extern char my_callsign[MAX_CALLSIGN+1];*/ extern void pad_callsign(char *callsignout, char *callsignin); extern char *to_upper(char *data); extern void Send_message(Widget w, XtPointer clientData, XtPointer callData); extern void create_gc(Widget w); extern void Station_info(Widget w, XtPointer clientData, XtPointer calldata); extern void fix_dialog_size(Widget w); void resize_dialog( Widget form, Widget dialog); extern int debug_level; extern GC gc; extern Pixel colors[]; extern float f_center_longitude; // Floating point map center longitude extern float f_center_latitude; // Floating point map center latitude extern float f_NW_corner_longitude;// longitude of NW corner extern float f_NW_corner_latitude; // latitude of NW corner extern float f_SE_corner_longitude;// longitude of SE corner extern float f_SE_corner_latitude; // latitude of SE corner extern long center_longitude; // Longitude at center of map extern long center_latitude; // Latitude at center of map extern long NW_corner_longitude; // longitude of NW corner extern long NW_corner_latitude; // latitude of NW corner extern long SE_corner_longitude; // longitude of SE corner extern long SE_corner_latitude; // latitude of SE corner extern long scale_x; // x scaling in 1/100 sec per pixel extern long scale_y; // y scaling in 1/100 sec per pixel extern long screen_width; extern long screen_height; extern Position screen_x_offset; extern Position screen_y_offset; extern int long_lat_grid; //extern Pixmap pixmap; //extern Pixmap pixmap_final; //extern Pixmap pixmap_alerts; extern int map_color_levels; extern int map_labels; extern int map_lock_pan_zoom; extern int map_auto_maps; extern int auto_maps_skip_raster; extern time_t sec_remove; extern Widget da; extern Widget text; extern XtAppContext app_context; extern int redraw_on_new_data; //extern Widget hidden_shell; extern int index_maps_on_startup; #define MAX_LABEL_FONTNAME 256 #define FONT_SYSTEM 0 #define FONT_STATION 1 #define FONT_TINY 2 #define FONT_SMALL 3 #define FONT_MEDIUM 4 #define FONT_LARGE 5 #define FONT_HUGE 6 #define FONT_BORDER 7 #define FONT_ATV_ID 8 #define FONT_MAX 9 #define FONT_DEFAULT FONT_MEDIUM #define MAX_FONTNAME 256 extern char rotated_label_fontname[FONT_MAX][MAX_LABEL_FONTNAME]; #ifdef HAVE_LIBGEOTIFF extern int DRG_XOR_colors; extern int DRG_show_colors[13]; #endif // HAVE_LIBGEOTIFF extern int net_map_timeout; extern void sort_list(char *filename,int size, Widget list, int *item); extern void redraw_symbols(Widget w); extern Colormap cmap; /* from messages.c */ extern char message_counter[5+1]; extern int auto_reply; extern char auto_reply_message[100]; extern int satellite_ack_mode; extern void clear_outgoing_messages(void); extern void reset_outgoing_messages(void); extern void output_message(char *from, char *to, char *message, char *path); extern void check_and_transmit_messages(time_t time); extern Message_Window mw[MAX_MESSAGE_WINDOWS+1]; extern void clear_message_windows(void); /* from sound.c */ extern pid_t play_sound(char *sound_cmd, char *soundfile); extern int sound_done(void); /* from fcc_data.c */ /* from rac_data.c */ /* from lang.c */ extern int load_language_file(char *filename); extern char *langcode(char *code); extern char langcode_hotkey(char *code); /* from sound.c */ extern pid_t play_sound(char *sound_cmd, char *soundfile); /* from location.c */ extern void set_last_position(void); extern void map_pos_last_position(void); /* from location_gui.c */ extern char locate_station_call[30]; extern void Last_location(Widget w, XtPointer clientData, XtPointer callData); extern void Jump_location(Widget w, XtPointer clientData, XtPointer callData); extern void map_pos(long mid_y, long mid_x, long sz); extern char locate_gnis_filename[200]; // This needs to be quite long for some of the weather station // serial data to get through ok (Peet Bros U2k Complete Record Mode // for one). #define MAX_LINE_SIZE 512 // from main.c extern char gprmc_save_string[MAX_LINE_SIZE+1]; extern char gpgga_save_string[MAX_LINE_SIZE+1]; extern int gps_port_save; // from map.c extern double calc_dscale_x(long x, long y); /* from popup_gui.c */ extern void popup_message_always(char *banner, char *message); extern void popup_message(char *banner, char *message); extern void popup_ID_message(char *banner, char *message); /* from view_messages.c */ extern void all_messages(char from, char *call_sign, char *from_call, char *message); extern void view_all_messages(Widget w, XtPointer clientData, XtPointer callData); /* from db.c */ extern void setup_in_view(void); #endif /* XASTIR_H */ Xastir-Release-2.2.2/src/xastir_udp_client.c000066400000000000000000000152301501463444000210220ustar00rootroot00000000000000/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2023 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include //#include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #include #include #include "xastir.h" // Must be last include file #include "leak_detection.h" // Atttempt to send to one of the addresses, waiting for 10 seconds // for (hopefully) a response. Returns 1 on success or 0 if we didn't // get a response. (Any response is considered a success) int try_exchange(struct addrinfo *addr, char *buffer, int UNUSED(buflen) ) { int sockfd, n; socklen_t length; struct sockaddr_storage from; struct pollfd polls; sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sockfd < 0) { fprintf(stderr, "socket error: %s\n", strerror(errno)); return(0); } n = sendto(sockfd, buffer, (size_t)strlen(buffer), 0, addr->ai_addr, addr->ai_addrlen); if (n < 0) { fprintf(stderr, "Sendto error %s\n", strerror(errno)); close(sockfd); return(0); } polls.fd = sockfd; polls.events = POLLIN; // wait for up to 10 seconds for a response. n = poll(&polls, 1, 10 * 1000); if(n == 0) { fprintf(stderr, "Timeout waiting for response\n"); close(sockfd); return 0; } else if (n < 0 ) { fprintf(stderr, "poll() returned an error: %s\n", strerror(errno)); close(sockfd); return 0; } // Response should be waiting, get it. length = sizeof(from); n = recvfrom(sockfd, buffer, 256, 0, (struct sockaddr *)&from, &length); if (n < 0) { fprintf(stderr, "recvfrom: %s\n", strerror(errno)); close(sockfd); return(0); } close(sockfd); return 1; } #ifndef AI_DEFAULT #define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG) #endif // Loop through the possible addresses for hostname (probably IPv6 and IPv4) // Tries until we are successful (get a response) or we run out of addresses int exchange_packet(char *hostname, char *port, char *buffer, int buflen) { struct addrinfo hints, *res, *r; int error; int success = 0; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(hostname, port, &hints, &res); if (error) { fprintf(stderr, "Error: Unable to lookup addresses for host %s port %s\n", hostname, port); return 1; } r = res; while(!success && r) { success = try_exchange(r, buffer, buflen); r = r->ai_next; if(!success && r) { fprintf(stderr, "Trying next address to send to\n"); } } freeaddrinfo(res); return success; } // Send a UDP packet to a UDP listening port. This allows scripts // and other programs to inject packets into Xastir via UDP // protocol. // Inputs: // hostname (argv[1]) // port (argv[2]) // callsign (argv[3]) // passcode (argv[4]) // optional flags: -identify // -to_rf // -to_inet // APRS Packet (argv[5]) // Returns: // 0: Message sent, ack received // 1: Error condition // // // int main(int argc, char *argv[]) { char buffer[512]; char callsign[10]; char extra[100]; int passcode; char message[256]; int ii, success; if (argc < 6) { fprintf(stderr, "\nUsage: xastir_udp_client server port call passcode -identify\n"); fprintf(stderr, " xastir_udp_client server port call passcode [-to_rf] [-to_inet] \"APRS Packet\"\n"); fprintf(stderr, "\nExample: xastir_udp_client localhost 2023 ab7cd 1234 \"APRS packet goes here\"\n"); return(1); } // Fetch the callsign snprintf(callsign, sizeof(callsign), "%s", argv[3]); callsign[sizeof(callsign)-1] = '\0'; // Terminate it // Fetch the passcode passcode = atoi(argv[4]); // Check for optional flags here: // -identify // -to_rf // -to_inet // extra[0] = '\0'; for (ii = 5; ii < argc; ii++) { if (strstr(argv[ii], "-identify")) { //fprintf(stderr,"Found -identify\n"); strncat(extra, ",-identify", sizeof(extra)-strlen(extra)-1); } else if (strstr(argv[ii], "-to_rf")) { //fprintf(stderr,"Found -to_rf\n"); strncat(extra, ",-to_rf", sizeof(extra)-strlen(extra)-1); } else if (strstr(argv[ii], "-to_inet")) { //fprintf(stderr,"Found -to_inet\n"); strncat(extra, ",-to_inet", sizeof(extra)-strlen(extra)-1); } } // fprintf(stdout, "Please enter the message: "); // Fetch message portion from the end of the command-line snprintf(message, sizeof(message), "%s", argv[argc-1]); message[sizeof(message)-1] = '\0'; // Terminate it if (message[0] == '\0') // Empty message { return(1); } memset(buffer, 0, 256); // fgets(buffer, 255, stdin); snprintf(buffer, sizeof(buffer), "%s,%d%s\n%s\n", callsign, passcode, extra, message); //fprintf(stderr, "%s", buffer); success = exchange_packet(argv[1], argv[2], buffer, 256); if(!success) { fprintf(stdout, "No response received.\n"); return(1); } fprintf(stdout,"Received: %s\n", buffer); if (strncmp(buffer, "NACK", 4) == 0) { //fprintf(stderr,"returning 1\n"); return(1); // Received a NACK } else if (strncmp(buffer, "ACK", 3) == 0) { //fprintf(stderr,"returning 0\n"); return(0); // Received an ACK } else { //fprintf(stderr,"returning 1\n"); return(1); // Received something other than ACK or NACK } } Xastir-Release-2.2.2/stamp-h.in000066400000000000000000000000121501463444000162400ustar00rootroot00000000000000timestamp Xastir-Release-2.2.2/symbols/000077500000000000000000000000001501463444000160365ustar00rootroot00000000000000Xastir-Release-2.2.2/symbols/.vimrc000066400000000000000000000014331501463444000171600ustar00rootroot00000000000000" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.2/symbols/13pct.xbm000066400000000000000000000002141501463444000174750ustar00rootroot00000000000000/* Created with The GIMP */ #define 13pct_width 4 #define 13pct_height 4 static unsigned char 13pct_bits[] = { 0x01, 0x00, 0x04, 0x00 }; Xastir-Release-2.2.2/symbols/25pct.xbm000066400000000000000000000002141501463444000175000ustar00rootroot00000000000000/* Created with The GIMP */ #define 25pct_width 4 #define 25pct_height 4 static unsigned char 25pct_bits[] = { 0x01, 0x04, 0x01, 0x04 }; Xastir-Release-2.2.2/symbols/2x2.xbm000066400000000000000000000001721501463444000171610ustar00rootroot00000000000000/* Created with The GIMP */ #define 2x2_width 2 #define 2x2_height 2 static unsigned char 2x2_bits[] = { 0x01, 0x02 }; Xastir-Release-2.2.2/symbols/Makefile.am000066400000000000000000000006601501463444000200740ustar00rootroot00000000000000# # Copyright (C) 2000-2023 The Xastir Group # symbolsdir=${pkgdatadir}/symbols EXTRA_DIST=symbols.dat 2x2.xbm 25pct.xbm 13pct.xbm alert.xbm flood.xbm red_flag.xbm snow.xbm torndo.xbm wind.xbm winter_storm.xbm winter_weather.xbm icon.png icon.svg symbols_DATA= symbols.dat 2x2.xbm 25pct.xbm 13pct.xbm alert.xbm flood.xbm red_flag.xbm snow.xbm torndo.xbm wind.xbm winter_storm.xbm winter_weather.xbm icon.png icon.svg Xastir-Release-2.2.2/symbols/alert.xbm000066400000000000000000000055121501463444000176600ustar00rootroot00000000000000#define alert_width 109 #define alert_height 32 static unsigned char alert_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0xef, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x82, 0x20, 0x22, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x50, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0xe7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xbe, 0x2f, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/flood.xbm000066400000000000000000000055121501463444000176540ustar00rootroot00000000000000#define flood_width 110 #define flood_height 32 static unsigned char flood_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x17, 0x38, 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x10, 0x44, 0x51, 0x54, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0x39, 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/icon.png000066400000000000000000000303341501463444000174770ustar00rootroot00000000000000PNG  IHDRL\zTXtRaw profile type exifxڝi䶒< $h672ҳgS-ueg2I,rrmI=sxx=ϱgk~{o_8?Fϯ+~ݨzq\'~Kͩܯ\q.+Ok;U<kDWJ#>oׯW8>XqSϟپ]>p;6fw;M үW(O{]F*&Ngߟ?17;5smv?}X#lq-_. k9|k3 BEڕ=ǵ-R-:bu3)̀(HGQH?G;`=#2l8qQϞ4RIkvOMgc .}o_J\5ژq_3Ƽrߵ_3<)]~Zf<}[wo-=^7QJ-i4ƾzz.gI{K鸶>]8s;xYJ,=eۑKz[sTؘ[gjnLYv7𥳐g_׺Y;6ӷu)J=3tzT| 8fMJnwMrZmϙc˞ݟ+g lw}Ǽ^yZ[lϷ+VX,Қ׽1^y0ZӊX7c,yL(c̞yh%=Oj<{n6s>\Q^%xsGlkoZ>kΫ3gYVnGe/`z|O:Ԇ},t5Da7VWli嫚v?agI>0r5S^q_:j)>ǩdcL j/; Ӯ],%_Ye0uW-Iu.h"%G-w>ny\Q sTɷK^F9ɐ=)۸ʺXhIvO3*yEː{< =ۄwYZ:}C$Զ[dׄAݓkPzahJ}Ab#8(X m,ۛW&{ͦuRa ՠ~)WSm 8 tI%@@;@2"ڔU8ASm H}dlJy4l^Nu@)(p$s [Ju|a(X_eJvR{FQN&@ )vYs'f/O+acVJ%#Z15`nYW9lR▛&g n},~$HF&`Զe<@qڝփAuP?,)]?,#E0=|EǏ`@s&бsCTVr(Ƽ1LQRo Mۡ2fׯ<'_VmȌԵ~r@rr]]Aʙ _/ /QC\Vމ׻o*VXT=SWSl{XTK=Ԡ`6濒H)M[uw[ȣ@t[E/~X#{YķOW6_ J 2ڱyٖ.Pǩf@Z5##> B8}btHWTZy{@T#FĎug.<',ǧ[mox{DzbQl) jDʡ{S y9'UCOKJl}zxlU!Pz; (sfHPیX,)H(Pv`7Ի aO'Qezj*VGvFUV0 ĵ6DžϐPm?ytYMEx*ՂӘ0M\VXCmTŬtL9b5y?)n 8+e^x2fJ^:"[k0\굅an$1쫴S[@PJtCI`WiO .^lyPrV r (r!Fr aF->6Y4CPg1{B!y ˊ `Du;`^\CfcGL'Z4&mP X_} ͉_\q3Ġݟٔ=[cZ$G2)!=| I{_%Q㓅[><4؍؇EAc*O(aL1OR=ָ9=.Hym >iLeHsF""l/|!%iZX։>"Nf<*Ȇb N| .-w$j{%y46>>%IAI1 k+-UA($&Qn"OoFf@FS'$7A\$N B-f[Q*<[!d,T!3]]@TR5_kB_FG8%a%qU(sRRȸкgskOLU'+%Hzh=L]+4 px"xPKHF>!i[#HM΀=)"{9-fjIxF=/jO&6x"8̈́)2Sy1WfKѤJ #^X 46dCoJ>읤r?|=11<ЈaoL[!(~eX6K5KU Yw1h+a~dGAi ֏xRuHHl$Ynb@~qᑀO| &d)[|<9:BTf7]VX'-gpFsK v($zpa&Y~,T؏?R ُiHʄwɎZ'yl+>,a  pC;/ B.A>I:3 GR_:0|u,2jں&aF|D6r wJ7$" N%b2gX? !zPKEM2(˧,r+"Q;0)= ϦՀl.L`X)ů'Y8ԶYc^0!) qs)${^c3.aZH "]@\Њ2]>qVP Zt-/>'!n_@i\d 9a(mmȒopFPo_FV%=EXa=g;? naNVbqWXLZc'/-([+,b@RWp5jUʻَk'{x%-uQG,El &id,9qJ% Ì#, ăBlsF;V.!-&n2+X;5Tj,D37 ]:9>_bpܠƄkp KE45 {0ꩌ<#ܐ32C$͛ci8kJR͹ +&\Cv`BXuY9z[H-{Z]yʕiR)7R?lgdB}GiPD79GGelas@9xHG 3GF +%2xl#,~:M1b˜Rz/ج:У8--Y6ӤUC:jzXdoJ7+ɯu:w&s;BiA^("EoEϊf§| _ 6G'\HA4ygema&RBvמ0QB{O+BhsE~)~ߝ5xE'"eM@A&RsDҰ00pdF 篇z$ TLV:yPG䞂'.ك]wYl>*XtT "mӹoF`O*J#Q!LvNo7Ȕe4ew$fѷPoH~{Fͣ/AgDKsF(kŨQ[Sw#N>њvf?֌XXѤ6TI\,bd ɨ9p z'3S5huM}&~3mG#4R.6}[K |ݞ6GYP(7~gqG<^}mBM{xXXѣ%IV`0ǃfAEg4uOb-"rkE= $¢F ajIr <6<=P7%RP7bJ,p_Q_d F qq * 4'FúIOȢldg y|36(EX>vT[v>. P%^+9Z h *N7XW ɕc Ue "akF@ϝ~#V'ltZ md]hBQ g]hQbɃVqbMX m瑺6i|G>q]>^rm p=,]In'iy7;Ol8BaaOMAhsQZ**Ү᮲5K Ϯ)C37ZGXrx!587b8 -uc^kqhFD I>*Ƃqt25+8cS,>Z!3~fբ!bxo(ÄRN+>}z1fR3~?SFZڧ~F)Oau]Q<5_<ײƥ}Qh#;LKmUcC0βF qS>jyR:Iv^aa .+L Tg[ Gt=V7VF,G;WkJ5Yd̢ظmW?C\0&&WI6kU)'8@iqoNQ[TB? b`F-3d~jFWُ :^Xۣ+mGTW%"d#&=]geP'D9g"lqe6 QZ-8H԰.U싪@=8۠AsE& &F{􄃕ӰLm8/>g(> dW4srIӨq+3KE͖ F4{=@N/BkZm_[> Xɡhn}m_ךOăg@5k6@ ccF(h"E^Ǚߏǧo7~E<9}_DJsBITOIDATxylT2kۡشTSAcY( H-S *"(E) P Y (lP@;37o9KDQX,xOl6l;w.ɓ'hZsլV+qj:??رR(zzrgfYVP0 0 zҽUS`٬VkNNJbyhݺul -bW(/))_9A+( ?DVV/^t)0aSNynnGS;v50g}UiӦ1 V;vlII -A. 4oV*JիWp-ք`9sfxx89 &TWW r-(999,rT*jp6C2n8X_|#5k?0`qͥ?"4hPdd=ν_֭yǭ`fɓ'ثW/OJO j}aݝB"gdv`Ekk2FGŗ?0 ,bemxD[=SC 9y$k_ 641fYVX1KŲwׯ_zuvD8Z;!e?:m61v8k׮>*->ׯgdd7.''[UUUF.3gμƍꫯ0F%1V_v1ʹsXDu֑>C/'ivhLOOK޽\^߻wo\ l6h>|8E/^h5r` & {Gk׮+T\\ܳgO/_m/^0 rJj^p&i (Jw޼yd/XN,8S?߯T*9S(,"sӧO'+o%Kh\\\eeeᔲ:uכmA+"0< qf p*@EEȴEqP!RL&R+SXʕ+{y^R)ʍ7kc:Ḹr;_| Z@p΄=Y@}™cʿ'wA('n:R}XE & <,jU*W](sN^^^aa!IIsfYTѰ˗'NXXXsؙI_İbsFeTFc'$qZVPjeZa.]0 -f3fĈeɓ'ᅯogYG "ncA1L#FpuqO8͛ld@!Ѐ<۔)S8N٪T*eU*N tJ.T*Zo wy *_~QQQehľWF#=łN*@(?3J)]gٲewޭ5LfbXV:=zGAy敗f~_|A`#GqLrX*8 t 998ܹs^4vJHH}+:b{IMMyl6gee}ǨNڻk0DMtS=9+cbbZ-zy9Ie۷`ѪU.\(>8iҌs0wZǏX ^-[ЁXJ2;;*syXJPNYO?M :Jm]:,dM6+JJ3o}Qg͚E?n'xѣKKKOQׯ_y)\Ė-[_,XyȹqoM'l}'؜Nt&еYҒj]k}Q?#,B<0L( /R]]~9ȀEtgϞSb첗"ӡ'^zjvUTT=g@P߿刣BjjjΟ?h}BNIIILL<{, XꪩZ8JEL& @?0@Sު(A5k־}Z|V#,+MkAuuumf8uL#111jQ:@Z,`Z` xK,6kcPUc=܎ہqgaaaEE O&iBRCu•mєEEE3f040m% Zu(0 . Tq>|<cia_v-66f; nbHs'LwٳZ\\\tttxxxTTJ¨b`_ŋi6ŷwA;Mxmc\Op.͹ -Jb!Ey!Q O0V3=*<"&-ER_^qB=KG#إ%h=\EQ1gG"`ؿ>v"!@{L#yW!Z򰰰cǎ!Amo !W^v45h4ND!ZJg);gh ]TT۷oȐ! ƄI}ݫyyy{E8'W 9ZFC=z?NKh_cةM &!!U$Z#թ|>}T* ܟ9 VИc@Qn6a2m(Ja3S`=-kmۆ=}уPb`ϧk/ (ʤ$yV7<$$l XEm>z*}+ĈCxz聎!st6]tc 1 ׽ͩ6,2220bbb/z<""n-kZIL4  }(+@sXyRRROu_C*-8/HqN 2))o4(#GZmTZ-b@@CEDDg u:ݙ3g(}s96n܈3oTP:'P֭[5m۶` l9k5ثJ\/RP^zyuځf[br hҤIQ[dysPU$''a4WXAA^b.V54̘1IN2rKoÆ yp>SIEh 6+UpĕӦMCe_hY4\dz2{\ZPi&h*pɓIEoiAT^sΈ:}˩8([<4Wov؁G0uZL:>%%ޫ^׎pmGfJl"ı>::z֭ˡvpPDZc*T@yȐ!xx$)3p$22r8scfdd<䓎] Created by potrace 1.16, written by Peter Selinger 2001-2019 Xastir-Release-2.2.2/symbols/red_flag.xbm000066400000000000000000000055231501463444000203160ustar00rootroot00000000000000#define red_flag_width 110 #define red_flag_height 32 static unsigned char red_flag_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xf7, 0x00, 0x5f, 0x40, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0x40, 0x44, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x51, 0x10, 0x01, 0x41, 0xa0, 0x04, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x13, 0x01, 0x4f, 0xa0, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0xf0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0x10, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf7, 0x00, 0xc1, 0x17, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a }; Xastir-Release-2.2.2/symbols/snow.xbm000066400000000000000000000055071501463444000175430ustar00rootroot00000000000000#define snow_width 110 #define snow_height 32 static unsigned char snow_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x22, 0x27, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xa6, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xaa, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xb2, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xa2, 0x28, 0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x88, 0xa2, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x22, 0xe7, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/symbols.dat000066400000000000000000002765011501463444000202330ustar00rootroot00000000000000# XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 1999,2000 Frank Giannandrea # Copyright (C) 2000-2023 The Xastir Group # # # Symbol definitions for XASTIR # # If the 20th char in the APRS symbol line is a "l" (small letter L), # all four orientations of that symbol will be generated, in this # case the symbol graphic should be oriented to the left. # # The text behind the APRS symbol line is the definition text # according to the APRS Reference, optionally followed by the # current use of that symbol in [] braces. # # Symbol graphics are defined similar to XPM but with a fixed # palette. # # If an entry doesn't exist, it will display as the first entry # defined here (currently says "NO SYM YET"). # # Symbol colors are defined in: # draw_symbols.c:read_symbol_from_file() # # # ------------------------------- # TABLE ! description from APRS101.pdf [used here as] APRS # .................... ....q...q...qqq..... ....qq..q..q...q.... ....q.q.q..q...q.... ....q..qq..q...q.... ....q...q...qqq..... .................... ..qqq..q...q..q...q. .q......q.q...qq.qq. ..qq.....q....q.q.q. ....q....q....q...q. .qqq.....q....q...q. .................... .q...q..qqqq..qqqqq. ..q.q...q.......q... ...q....qqq.....q... ...q....q.......q... ...q....qqqq....q... .................... .................... # # # ----------------------------------- # Primary table section starts here # TABLE / # APRS ! Police, Sheriff .................... .........pp......... .........pp......... ........p##p........ ........p##p........ .......p####p....... .......p#####p...... ppppppp#######pppppp .p################p. ...p############p... ...p############p... .....p########p..... .....p########p..... ....p##########p.... .................... pp....pppppp.pp...p. pp....pp...p.pp.p.p. pp....pppppp.pp.p.p. pp....pp...p.pppppp. ppppp.pp...p.pppppp. #APRS " Reserved # APRS # Digi (green star with white center) .................... .................... .........kk......... .........kk......... ........kkkk........ .......kkkkkk....... ..kkkkkkkkkkkkkkkk.. ...kkkkkmmmmkkkkk... ....kkkmmmmmmkkk.... .....kkmmmmmmkk..... .....kkmmmmmmkk..... ....kkkmmmmmmkkk.... ...kkkkkmmmmkkkkk... ..kkkkkkkkkkkkkkkk.. .......kkkkkk....... ........kkkk........ .........kk......... .........kk......... .................... .................... # APRS $ Phone .................... .................... ..llllllllllllllll.. ..llllllllllmmmmll.. ..lllllllllmllllml.. ..lllllllllmllllml.. ..lllllllllmllllml.. ..llllllllllmlllml.. ..llllllllllmlllml.. ..lllllllllmlllmll.. ..llllllllmlllmlll.. ..llmmmllmlllmllll.. ..lmlllmmlllmlllll.. ..lmlllllllmllllll.. ..lmllllllmlllllll.. ..lmlllllmllllllll.. ..llmmmmmlllllllll.. ..llllllllllllllll.. .................... .................... # APRS % DX Cluster .................... .................... .mmmmmm..mmmm..mmmm. .mqqqqqm.mqqm..mqqm. .mqqqqqqmmqqm..mqqm. .mqqmmqqqmmqqmmqqm.. .mqqm.mqqmmqqmmqqm.. .mqqm.mqqm.mqqqqm... .mqqm.mqqm.mqqqqm... .mqqm.mqqm..mqqm.... .mqqm.mqqm..mqqm.... .mqqm.mqqm.mqqqqm... .mqqm.mqqm.mqqqqm... .mqqm.mqqmmqqmmqqm.. .mqqmmqqqmmqqmmqqm.. .mqqqqqqmmqqm..mqqm. .mqqqqqm.mqqm..mqqm. .mmmmmm..mmmm..mmmm. .................... .................... # APRS & HF Gateway .................... .................... .........qq......... ........qqqq........ .......qqqqqq....... ......qqqqqqqq...... .....qqq####qqq..... ....qqq######qqq.... ...qqq##qqqq##qqq... ..qqqq##qqqqqqqqqq.. ..qqqq##qqq###qqqq.. ...qqq##qqqq##qqq... ....qqq######qqq.... .....qqq####qqq..... ......qqqqqqqq...... .......qqqqqq....... ........qqqq........ .........qq......... .................... .................... # APRS ' l Small Aircraft (SSID -7) .................... .................... ........ooo......... .......oooo......... .......oooo......... .......oooo...oo.... .......oooo...oo.... .......oooo...oo.... .....ooooooooooo.... .....ooooooooooo.... .....ooooooooooo.... .....ooooooooooo.... .......oooo...oo.... .......oooo...oo.... .......oooo...oo.... .......oooo......... .......oooo......... ........ooo......... .................... .................... # APRS ( Mobile Satellite Groundstation .................p.. .................p.. ................ppp. ................ppp. .................... ..............p..... .................... ............p....... .................... ..........p......... p................... p.......p........... p................... p................... p................... p................... pp.p................ ppp................. pppp................ pppppppppp.......... # APRS ) Wheelchair (handicapped) .................... ..llllllllllllllll.. .llllllmmmlllllllll. .llllllmmmlllllllll. .llllllmmllllllllll. .llllllmmllllllllll. .lllllllmmlllllllll. .llllmmlmmmmmmmllll. .llmmmllmmlllllllll. .llmmllllmmmmmmmlll. .lmmllllllmmmmmmlll. .lmmlllllllmmlmmlll. .lmmlllllllmmlmmlll. .lmmlllllllmmlmmlll. .llmmlllllmmllmmlll. .llmmmllllmmllmmmml. .lllmmmmmmmllllllll. .llllmmmmmlllllllll. ..llllllllllllllll.. .................... # APRS * l Snowmobile .................... .................... .................... .................... ...........qq....... ..........qq........ .........qq......... ........qq.......... ......q###q......... .....q#####q.......q ....q######qqqqqqqqq ....q######qqqqqqqqq q....q######qqqqqqqq qqq..qqqqqqqqqqqqqqq .qqqqqqqqqqqqqqqqqqq .................... .................... .................... .................... .................... # APRS + Red Cross .................... .................... ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ .................... .................... # APRS , Boy Scouts .........n.......... ........nbn......... .......nbbbn........ .......nbbbn........ ....n.nbbbbbn.n..... ...nbnnbbbbbnnbn.... ..nbbbbnbbbnbbbbn... ..nbbbbbnbnbbbbbn... ..nbbnnbnbnbnnbbn... ...nn..qqqqq..nn.... .......qqqqq........ ......nbbnbbn....... .....nbbnbnbbn...... .....nnnbbbnnn...... .......nbbbn........ .ppp....nnn......p.. p................p.. .pp..pp.ppp.p.p.ppp. ...p.p..p.p.p.p..p.. ppp..pp.ppp.ppp..p.. # APRS - House QTH (VHF) .................... ......q............. ......q............. ......q...q......... ......q..qqq........ ......q.qqqqq....... ......qqqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... .................... .................... # APRS . X .................... .................... .................... .................... .................... .................... ......j......j...... .......j....j....... ........j..j........ .........jj......... .........jj......... ........j..j........ .......j....j....... ......j......j...... .................... .................... .................... .................... .................... .................... # APRS / Dot .................... .................... .................... .................... .................... .................... .................... ........jjjj........ .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... ........jjjj........ .................... .................... .................... .................... .................... .................... .................... # APRS 0 Numerical Circle 0 (obsolete, use overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqmmmmqqqqqq.. ..qqqqqmmmmmmqqqqq.. ..qqqqmmmqqmmmqqqq.. ..qqqqmmqqqqmmqqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqqmmqqqqmmqqqq.. ..qqqqmmmqqmmmqqqq.. ..qqqqqmmmmmmqqqqq.. ..qqqqqqmmmmqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS 1 Numerical Circle 1 (obsolete, use overlay) .................... .................... ..ffffffffffffffff.. ..ffffffffffffffff.. ..ffffffffmmffffff.. ..fffffffmmmffffff.. ..ffffffmmmmffffff.. ..fffffmmmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffmmmmmmmffff.. ..fffffmmmmmmmffff.. ..ffffffffffffffff.. ..ffffffffffffffff.. ..ffffffffffffffff.. .................... .................... # APRS 2 Numerical Circle 2 (obsolete, use overlay) .................... .................... ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjmmmmmmmmjjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjmmmjjjjmmmjjj.. ..jjjjjjjjjjmmmjjj.. ..jjjjjjjjjmmmjjjj.. ..jjjjjjjmmmjjjjjj.. ..jjjjjmmmjjjjjjjj.. ..jjjjmmmjjjjjjjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. .................... .................... # APRS 3 Numerical Circle 3 (obsolete, use overlay) .................... .................... ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaammmmmmmaaaaa.. ..aaaammmmmmmmaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaammmmmaaaaa.. ..aaaaaammmmmaaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaaaaaammaaaa.. ..aaaammmmmmmmaaaa.. ..aaaammmmmmmaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. .................... .................... # APRS 4 Numerical Circle 4 (obsolete, use overlay) .................... .................... ..################.. ..################.. ..################.. ..#####ooo#ooo####.. ..#####ooo#ooo####.. ..####ooo##ooo####.. ..####ooo##ooo####.. ..###oooooooooo###.. ..###oooooooooo###.. ..#########ooo####.. ..#########ooo####.. ..#########ooo####.. ..#########ooo####.. ..################.. ..################.. ..################.. .................... .................... # APRS 5 Numerical Circle 5 (obsolete, use overlay) .................... .................... ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmkkkkkkkkkk.. ..kkkkmmkkkkkkkkkk.. ..kkkkmmmmmmmkkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkkkkkkkmmkkkk.. ..kkkkkkkkkkmmkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmmmmmmkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. .................... .................... # APRS 6 Numerical Circle 6 (obsolete, use overlay) .................... .................... ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..lllllmmmmmmmllll.. ..llllmmmmmmmmllll.. ..llllmmllllllllll.. ..llllmmllllllllll.. ..llllmmmmmmmlllll.. ..llllmmmmmmmmllll.. ..llllmmllllmmllll.. ..llllmmllllmmllll.. ..llllmmmmmmmmllll.. ..lllllmmmmmmlllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. .................... .................... # APRS 7 Numerical Circle 7 (obsolete, use overlay) .................... .................... ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbmmmmmmmbbbbb.. ..bbbbmmmmmmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. .................... .................... # APRS 8 Numerical Circle 8 (obsolete, use overlay) .................... .................... ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccmmmmmmccccc.. ..ccccmmmmmmmmcccc.. ..ccccmmccccmmcccc.. ..ccccmmccccmmcccc.. ..cccccmmmmmmccccc.. ..cccccmmmmmmccccc.. ..ccccmmccccmmcccc.. ..ccccmmccccmmcccc.. ..ccccmmmmmmmmcccc.. ..cccccmmmmmmccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. .................... .................... # APRS 9 Numerical Circle 9 (obsolete, use overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmqqqqqqmmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmqqmmmmqqmmmq.. ..qmmmqqmmmmqqmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmmqqqqqqqmmmq.. ..qmmmmmmmmmqqmmmq.. ..qmmmmmmmmmqqmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmqqqqqqqmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS : Fire .................... .................... ....q............... ...q#q...........q.. ...qjq..........q#q. ...q#q.........q##q. ...qqq..qq.qq.q#qq.. ..q#q#qq#q.q#qq#q... ...qq#q##qq#jqqq#q.. ...q#q#jfj##j#f#qq.. ..q#j#jj#j#jj#jjq... ..qjjjfjjj#j#j#q.... ...qjjfjj#jjjjfq.... ....qjjffjjfjfjjq... ...qjjffjfjjfjjfqq.. ...qjfffjjfjfjfjjq.. ..qjffjjfffjjffjq... ..qjffjjfjffjjffjq.. ..qffffffffffffffq.. .................... # APRS ; Campground (Portable Ops!) .................... .................... ..........e......... ..........e......... ..........e......... ..........e......... .........iei........ .........iei........ ........ikeki....... .......ikkekki...... ......ikkceckki..... .....ikkkoeokkki.... ....ikkkcieickkki... ...ikkkkoieiokkkki.. ....kkkciieiickkk... ....kkkoiieiiokkk... ....kkciiieiiickk... ..eeeeeeeeeeeeeeee.. .................... .................... # APRS < l Motorcycle (SSID -10) .................... .................... .................... .......ppp.......... .......p............ .......ppppp........ ......pp.........p.. .....pppppp....pp... .pppppp####pppppppp. p.pmppp####pppppmp.p .pmppp.ppppppqpmmmp. pmmpmmppppppppppppmp pmpmmmppppppppmmmmmp .pmmmp..ppppp.pmmmp. ..pmp..........pmp.. ...p............p... .................... .................... .................... .................... # APRS = l Railroad Engine .................... .................... .....cmccmcccc...... ....ccccmc.......... ....pp.............. ..qqqqqq...qqqqqqq.. ...qqqq....qqqqqqq.. ....qq.....qq...qq.. ....qq.....qq...qq.. ....qq.....qq...qq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ...q..q..qmmq.qmmq.. ..qmqqmq.qmmq.qmmq.. ...q..q...qq...qq... .................... .................... # APRS > l Car (SSID -9) .................... .................... .................... .................... .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppdqdddddddddp.. ..pjjjjdjjjjdjjjjjp. .pjjjjjdjjjjdjjjjjdp p#jjoojdjjjjdjjoojjp pjjonnodjjjjdjonnojp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # APRS ? File Server .................... .................... pppp..p..p.....pppp. p.....p..p.....p.... p.....p..p.....p.... pppp..p..p.....pppp. p.....p..p.....p.... p.....p..p.....p.... p.....p..pppp..pppp. .................... .................... .................... .ppp.pp.ppp..p.p.ppp p....p..p..p.p.p.p.. p....p..p..p.p.p.p.. .pp..pp.ppp..p.p.ppp ...p.p..p.p..p.p.p.. ...p.p..p.p..p.p.p.. ppp..pp.p..p..p..ppp .................... # APRS @ Hurricane Future Prediction (dot) ppp..ppp...ppp..ppp. p..p.p..p..p....p..p ppp..ppp...ppp..p..p p....p.p...p....p..p p....p..p..ppp..ppp. .................... ....ll.....ll....... ...ll....ll..ll..... ...ll...llll...ll... ....ll.lllllll...... ......lllllll.ll.... ...ll...llll...ll... .....ll..ll...ll.... .......ll....ll..... .................... ppp...ppp...ppppp... .p...p...p....p..... .p...p........p..... .p...p...p....p..... ppp...ppp.....p..... # APRS A Aid Station .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhmmmmmmmmmmmmhh.. ..hhmmmmmmmmmmmmhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS B BBS or PBBS .................... .................... .................... .................... .................... ...ggg..ggg...gg.... ...g..g.g..g.g..g... ...g..g.g..g.g...... ...ggg..ggg...g..... ...g..g.g..g..g..... ...g..g.g..g...g.... ...g..g.g..g....g... ...g..g.g..g.g..g... ...gggg.ggg...gg.... .................... .................... .................... .................... .................... .................... # APRS C l Canoe .................... .................... .................... .................... .................... .............p...... pppp........p...pppp peeppppppppppppppeep peeeeeeeeepeeeeeeeep .peeeeeeepeeeeeeeep. ..peeeeepeeeeeeeep.. ...pppppppppppppp... ......p............. .....p.............. ...ppp.............. ..ppp............... .ppp................ .................... .................... .................... # #APRS D # APRS E Eyeball (eye catcher) .................... .................... ........pppp........ ......pmmmmmmp...... ....pmmmmmmmmmmp.... ..pmmmmmhhhhmmmmmp.. .pmmmmhhhhhhhhmmmmp. .pmmmmhhhhhhhhmmmmp. pmmmhhhhhpphhhhhmmmp pmmmhhhhpppphhhhmmmp pmmmhhhhpppphhhhmmmp pmmmhhhhhpphhhhhmmmp .pmmmmhhhhhhhhmmmmp. .pmmmmhhhhhhhhmmmmp. ..pmmmmmhhhhmmmmmp.. ....pmmmmmmmmmmp.... ......pmmmmmmp...... ........pppp........ .................... .................... # APRS F l Farm Equipment .................... .................... .................... .................... .................... ............qqqqqqq. ............qkkkkkq. ...qq.......qkmmmkq. ...qq.......qkmmmkq. ...qq.......qkmmmkq. ..qqqqqqqqqqkkkkkkq. .qkkkkkkkkkkkqqqqqq. .qkkkkkkkkkkqqqqqqq. ..qqqkkkkkkqqqkkkqq. .qqqqqqqqqqqqqkkkqq. .qqqqq......qqkkkqq. .qqqqq......qqqqqqq. .qqqq........qqqqq.. .................... .................... # APRS G Grid Square (6-character) .................... ..q.q.q......q.q.q.. ..q.q.q.qjjq.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.qjjq.q.q.q.. ..q.q.q.qjjq.q.q.q.. ........qjjq........ ........qjjq........ ........qjjq........ ........qjjq........ .......qqjjqq....... .......qjqqjq....... ...qq..qqjjqq..qq... ..q..q.qqjjqq.q..q.. ..q....qjqqjq..q.... ..q.qq.qjqqjq...q... ..q..q.qqjjqq.q..q.. ...qq..qqqqqq..qq... .................... .................... # APRS H Hotel (blue bed icon) .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhmmhhmmmmmmhmh.. ..hmhmmmmmmmmmmhmh.. ..hmhmmhhmmmmmmhmh.. ..hmhhhhhhhhhhhhmh.. ..hmmmmmmmmmmmmmmh.. ..hmhhhhhhhhhhhhmh.. ..hmhhhhhhhhhhhhmh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS I TCP/IP on air network station .................... .................... .................... .#################.. .##iiiii#iii#iii##.. ..###i###i#i#i#i#... ..###i###i###iii#... ..###i###i#i#i###... ...##i###iii#i##.... ...#############.... ...#############.... ...###iii#iii###.... ....###i##i#i##..... ....###i##iii##..... ....###i##i####..... .....#iii#i###...... .....#########...... .....#########...... .................... .................... # #APRS J # APRS K School .........pp......... ........p##p........ .......p####p....... ......p######p...... .....p########p..... ....p##########p.... ...p############p... ..pppppppppppppppp.. ..p##############p.. ..p##pp##ppp##pp#p.. ..p##pp##ppp##pp#p.. ..p######ppp#####p.. ..pppppppppppppppp.. .................... .................... .pp....p...........p p......p...........p .p..pp.ppp.ppp.ppp.p ..p.p..p.p.p.p.p.p.p pp..pp.p.p.ppp.ppp.p # APRS L Logged-on Internet User (Desktop Computer) qqqqq.qqqqqqqqqqqqqq qmqmq.qqqqqqqqqqqqqq qqmqq.qqmmmmmmmmmmqq qmqmq.qqmmmqmmmqmmqq qqmqq.qqmmmmqmqmmmqq qmqmq.qqmmmmmqmmmmqq qqmqq.qqmmmmqmqmmmqq qmqmq.qqmmmqmmmqmmqq qqmqq.qqmmmmmmmmmmqq qmqmq.qqqqqqqqqqqqqq qqmqq.qqqqqqqqqqqqqq qmqmq.q............q qqqqq.qqqqqqqqqqqqqq .................... .................... ....qqqqqqqqqqqqqqqq ...qmqmqmqmqmqmqmqq. ..qqmqmqmqmqmqmqmq.. .qmmqmqmqmqmqmqmq... qqqqqqqqqqqqqqqq.... # APRS M MacAPRS .................... .................... ...........kk....... ..........kkk....... .........kkk........ .........kkk........ .....kkkkkkkkkk..... ....kkkkkkkkkkkk.... ...############..... ...###########...... ...aaaaaaaaaaa...... ...aaaaaaaaaaa...... ...jjjjjjjjjjjj..... ...jjjjjjjjjjjj..... ....bbbbbbbbbbbb.... ....bbbbbbbbbbbb.... .....llllllllll..... ......llllllll...... .................... .................... # APRS N NTS Station .................... .......gggggg....... ......gggggggg...... .....ggmmgggmgg..... .....ggmgmggmgg..... ....gggmggmgmggg.... ....gggmgggmmggg.... ...gggggggggggggg... ...ggggmmmmmmgggg... ..gggggggmmggggggg.. ..gggggggmmggggggg.. ...gggggggggggggg... ...gggggmmmmmgggg... ....gggmgggggggg.... ....ggggmmmmgggg.... .....gggggggmgg..... .....ggmmmmmggg..... ......gggggggg...... .......gggggg....... .................... # APRS O Balloon (SSID -11) .................... .................... ......hffjffh....... .....h##kjk##h...... ....h###jjj###h..... ...h####jjj####h.... ...###jj###jj###.... ...jjjjj###jjjjj.... ...jjjjj###jjjjj.... ...jjjblllllbjjj.... ....lllllllllll..... .....lllllllll...... ......lllllll....... .......h.a.h........ ........pcp......... .......fefef........ .......fefef........ .......oqqqo........ .................... .................... # APRS P l Police .................... .................... ..........ll........ ..........ll........ .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppnqnnnnnnnnnp.. ..pmmmmkkkkkkmmmmmp. .pmmmmmkccckkmmmmmep p#mmoomkkkkkkmmoommp pmmonnokkkkkkmonnomp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # #APRS Q # APRS R l Recreational Vehicle (SSID -13) (motor-home) .................... .................... .................... .................... .................... ........pppppppppp.. ..pqqqqqqqqqqqqqqqqq .pmmmmmmmmmmmmmmmmmq ppppmmmmmpppmmpppmmq qpppmmmmmpppmmpppmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmqmmmqmmmqmmq qmmmmmmmmmmmmmmmmmmq qqqqqqqqqqqqqqqqqqqq .qqqq.......qqqq.... ..qq.........qq..... .................... .................... .................... .................... # APRS S l Space Shuttle ................qqq. ...............qmcq. ..............qmmcq. .............qnmecq. ............qnmmhcq. ..........qqnmmmmcq. ........pqnmmmmmcnqq ...oqqqonnnnnnnncmmq .qqomcmmmmmmmmmcmmmq qqmqcnmmmmmmmmmcqqqn .qqomcmmmmmmmmmcmmmq ...oqqqonnnnnnnncmmq ........pqnmmmmmcnqq ..........qqnmmmmcq. ............qnmmecq. .............qnhlcq. ..............qmmcq. ...............qmcq. ................qqq. .................... # APRS T SSTV ..pppp.......pppp... .p....p.....p....p.. p......p...p......p. p....... ..p........ .pppppp.....pppppp.. .......p..........p. p......p...p......p. .p....p.....p....p.. ..pppp.......pppp... .................... .................... ppppppp....p.......p ...p.......p.......p ...p.......p.......p ...p........p.....p. ...p........p.....p. ...p.........p...p.. ...p.........p...p.. ...p..........p.p... ...p...........p.... # APRS U l Bus (SSID -2) .................... .................... .................... .................... .................... .....aaaaaaaaaaaaaa. ....a##############a ...ac#cc#cc#cc#cc#ca ..acc#cc#cc#cc#cc#ca aa#################a a##################a a##################a aannaaaaaaaaaaaannaa .qooq..........qooq. ..qq............qq.. .................... .................... .................... .................... .................... # APRS V ATV .........pp......... ........p..p........ .......p....p....... ......p. ....p...... .....p........p..... ....pppppppppppp.... ...p............p... ..p..............p.. .p................p. .................... .................... ppppppp....p.......p ...p.......p.......p ...p.......p.......p ...p........p.....p. ...p........p.....p. ...p.........p...p.. ...p.........p...p.. ...p..........p.p... ...p...........p.... # APRS W National Weather Service Site .................... .................... .......gggggg....... .....gghhhhhhgg..... ....ghhhhhhhhhhg.... ...ghhhhhhhhhhhhg... ...ghhhhhhhhhhhhg... ..gmmhhhmmhmmhhmmg.. ..gmmhhhmmhmmmmmmg.. ..gmmhhhmmhhmmmmhg.. ..gmmhmhmmhhmmmmhg.. ..gmmmmmmmhmmmmmmg.. ..gmmmhmmmhmmhhmmg.. ...ghhhhhhhhhhhhg... ...ghhhhhhhhhhhhg... ....ghhhhhhhhhhg.... .....gghhhhhhgg..... .......gggggg....... .................... .................... # APRS X l Helicopter (SSID -6) .................... .................... .................... ..mqqmqqmqqmqqm..... qmqmqmqmqmqmqmqmq... ..qmqqmqqmqqmqq..... .......mq........... ...qqqqqq........... ..qqqqjjq.......mmm. .qmmmqjjjq.....mqqqm qmmmmqjjjjqjqjqmqmqm qqqqqqjjjjjqjqjmqqqm .qjjjjjjjq......mmm. ..qjqqjqq........... ...jq.jq............ j..jq.jq............ qjjjjjjjjjjj........ .qqqqqqqqqqq........ .................... .................... # APRS Y l Yacht (sail boat) (SSID -5) .................... .................... ...........q........ ..........qqq....... .........qcqcq...... ........qccqcq...... .......qcccqcq...... ......qccccqccq..... .....qcccccqccq..... ....qccccccqcccq.... ...qcccccccqcccq.... ..qqqqqqqqqqqqqqqq.. ...qkkkkkkkkkkkkq... ....qkkkkkkkkkkq.... .....qqqqqqqqqq..... .................... .................... .................... .................... .................... # APRS Z WinAPRS .................... .................... .................... .........qqqqqq..... ........qjjjqkkqq... .qq...qqjjjjqkkkkq.. ...qqq.qjjjjqkkkkq.. .qq...qqjjjjqkkkkq.. ...qqq.qjjjjqkkkkq.. .qq...qqjjqqqqkkkq.. ...qqq.qqqllq#qqkq.. .qq...qqllllq###qq.. ...qqq.qllllq####q.. .qq...qqllllq####q.. ...qqq.qllllq####q.. .qq...qqllllq####q.. ...qqq.qlqqqqq###q.. .qq...qqq.....qq#q.. ...qqq..........qq.. .................... # APRS [ l Jogger .................... .................... .................... .................... .......qq........... .......qq........... .......qqllpp....... ...p...lelleep...... ...pe...lll..ep..... ....pe..lll..ep..... .....ppqqll..ep..... ......qqqqqq........ .....qqqqqqq........ .....qqq..qqqqq..... ......llq..qllq..... .....qqq......q..... .................... .................... .................... .................... # APRS \ Triangle (DF station) .................... .................... .........qq......... ........q##q........ ........q##q........ .......q####q....... .......q####q....... ......q######q...... ......q######q...... .....q########q..... .....q########q..... ....q#qqq##qqq#q.... ....q#q##q#q###q.... ...q##q##q#qq###q... ...q##q##q#q####q... ..q###qqq##q#####q.. ..q##############q.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS ] Mail/Post Office .................... .................... .....llllllllll..... ...llllllllllllll... ..llllmhmhmhmhllll.. ..lllmhmhmhmhmhlll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llmlmllmllmlmlll.. ..llmmmlmlmlmlmlll.. ..llmhmlmmmlmlmlll.. ..llmlmlmlmlmlmlll.. ..llmlmlmlmlmlmmll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llll........llll.. ..lll..........lll.. ..lll..........lll.. .................... .................... # APRS ^ l Large Aircraft .................... .................... .........oo......... .........oo......... ........ooo......... ........ooo......... ........ooo......o.. .......oooo.....oo.. .......oooo....ooo.. ..oooooooooooooooo.. ..oooooooooooooooo.. .......oooo....ooo.. .......oooo.....oo.. ........ooo......o.. ........ooo......... ........ooo......... .........oo......... .........oo......... .................... .................... # APRS _ Weather Station (blue) .................... .................... .......hhhhhh....... .....hhhhhhhhhh..... ....hhhhhhhhhhhh.... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ..hmmhhhmmhmmhhmmh.. ..hmmhhhmmhmmmmmmh.. ..hmmhhhmmhhmmmmhh.. ..hmmhmhmmhhmmmmhh.. ..hmmmmmmmhmmmmmmh.. ..hmmmhmmmhmmhhmmh.. ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ....hhhhhhhhhhhh.... .....hhhhhhhhhh..... .......hhhhhh....... .................... .................... # APRS ` Dish Antenna .................... .................... ..q................. ..qq................ ..qoq............... ..qooq.............. ...qooqqqqqqqq...... ...qoooq....qq...... ...qooooq..q.q...... ...pqooooqq..q...... ....qoooooq..q...... .....qoooooq.q...... ....qpqoooooqq...... ...qqqpqoooooq...... ..qqqqqpqoooooq..... ..qqqqqq.qqooooq.... ..qqqqqqp..pqqooq... ..qqqqqqqp....qqqq.. .................... .................... # APRS a l Ambulance (SSID -1) .................... .................... .................... .................... .................... .......qqqqqqqqqqq.. ......qqmmjjmmmmmq.. .....qoqmmjjmmmmmq.. ..qqqqqqjjjjjjmmmq.. ..qmmmmmjjjjjjmmmq.. ..qmmmmmmmjjmmmmmq.. ..qmqqqqmmjjqqqqmq.. ..qqqqqqqmmqqqqqqq.. ..qqqoqqqqqqqqoqqq.. ....qqoq....qoqq.... .....qq......qq..... .................... .................... .................... .................... # APRS b l Bicycle (SSID -4) .................... .................... .........q.......... .........qqq........ .........q.......... ........q........... .......qq...qqq..... ....qqqmqq..q....... ...qq..m.qqqq....... ..qq......qqqq...... ..q....m...q.qq..... ..q...m....q..qq.... ..q....m...q...qq... ..q.....m..q...qq... ..qq......qq..q..q.. ...qq....qq...q..q.. ....qqqqqq.....qq... .................... .................... .................... # APRS c Incident Command Post qqqqqqqqqqqqqqqqqqqq qmmmmmmmmmmmmmmmmmlq qmmmmmmmmmmmmmmmmllq qmmmmmmmmmmmmmmmlllq qmmmmmmmmmmmmmmllllq qmmmmmmmmmmmmmlllllq qmmmmmmmmmmmmllllllq qmmmmmmmmmmmlllllllq qmmmmmmmmmmllllllllq qmmmmmmmmmlllllllllq qmmmmmmmmllllllllllq qmmmmmmmlllllllllllq qmmmmmmllllllllllllq qmmmmmlllllllllllllq qmmmmllllllllllllllq qmmmlllllllllllllllq qmmllllllllllllllllq qmlllllllllllllllllq qllllllllllllllllllq qqqqqqqqqqqqqqqqqqqq # APRS d Dual Garage (Fire Department) .................... .........qq......... ........qjjq........ .......qjjjjq....... ......qjjjjjjq...... .....qjjjjjjjjq..... ....qjjjjjjjjjjq.... ...qjjjjjjjjjjjjq... ..qqqqqqqqqqqqqqqq.. ..qjjjjjjjjjjjjjjq.. ..qjmmmjmjmmmjmmjq.. ..qjmjjjmjmjmjmjjq.. ..qjmmjjmjmmmjmmjq.. ..qjmjjjmjmjmjmjjq.. ..qjmjjjmjmjmjmmjq.. ..qjjjjjjjjjjjjjjq.. ..qqqqqqqqqqqqqqqq.. .................... .................... .................... # APRS e l Horse (equestrian) .................... .................... .................... ..........qq........ .........qqqq....... ..........qq........ .........qqq........ ...qq...q.qq........ ..qqqq....qq........ .qqqqqqqqqqqqqqqq... .qq..qqqqqqqqqqq.q.. ......qqqqqqqqqq..q. .......qqq....q.q... ......q.q....q...q.. .....q...q....q..q.. .....q....q....q..q. .................... .................... .................... .................... # APRS f l Fire Truck (SSID -3) .................... .................... .................... .................... .................... .................... ...jjjjmmmmmmmmmmmm. ..jcccjjmjjmjjmjjmj. .jccccjjmjjmjjmjjmj. .jjjjjjmmmmmmmmmmmm. .jjjjjjjjjjjjjjjjoo. .oojqjjjjjjqjjjqjoo. ...qqq....qqq.qqq... ....q......q...q.... .................... .................... .................... .................... .................... .................... # APRS g Glider .................... .................... .................... .................... ..jjjj.............. ..jaaajjjj.......... ..jaaaaaaajjjj...... ..j###########jjjj.. ..jjjjjjjjjjjjjjjj.. ....p..........p.... .....p........p..... ......p......p...... .......pccccp....... .....gggggggggg..... .....ggggggg.gg..... .................... .................... .................... .................... .................... # APRS h Hospital .................... .........qq......... ........qmmq........ .......qmmmmq....... ......qmmmmmmq...... .....qmmmmmmmmq..... ....qmmmmmmmmmmq.... ...qmmmmmmmmmmmmq... ..qqqqqqqqqqqqqqqq.. ...qmmmmmjjmmmmmq... ...qmmmmmjjmmmmmq... ...qmmmjjjjjjmmmq... ...qmmmjjjjjjmmmq... ...qmmmjjjjjjmmmq... ...qmmmmmjjmmmmmq... ...qmmmmmjjmmmmmq... ...qqqqqqqqqqqqqq... .................... .................... .................... # APRS i IOTA (island on the air) .................... ......k..k.......... ....kkkkkkkkkk...... ....kkkiiiik#kkk.... ..kk##kkii#kk#k.kk.. ..k#kkk#ffk#k.#k.... .k.k.k#.ffk....k.... k..k..k.ff.......... ........ff.......... ........ff.......... ........ff.......... ....aeaeffaeaea..... ..eaeaeaeaeaeaeaea.. .haeaeaeaeaeaeaeaeh. .hhaeaeaeaeaeaeaehh. ..hhhhhhhhhhhhhhhh.. ...hhhhhhhhhhhhh.... .................... .................... .................... # APRS j l Jeep (SSID -12) .................... .................... .................... .................... ..........koooooo... .........k...o...o.. ........k...co...co. .......kkp..no...po. .kkkkkkkkc..nkkkkkkq k#kkkkkkk..okkkkkkkq nkqqqkkkkpppkkqqqkkq nqqcqqkkkkkkkqqcqqnn .qcmcqoonnnnnqcmcqq. .oqcqo.......oqcqo.. ..oqo.........oqo... .................... .................... .................... .................... .................... # APRS k l Truck (SSID -14) .................... .................... .................... .................... ........jjj......... .......jjmj......... ......jjmmj......... .....jjmmmj......... ..jjjjpjjqpjjjjjjj.. ..jjjjpjjjpjjjjjjj.. ..jjjjjpjjpjjjjjjj.. ..qpppjppppjjpppjq.. ..qpcpjjjjjjjpcpjq.. ...ppp.......ppp.... .................... .................... .................... .................... .................... .................... # APRS l Logged-on Laptop .................... .................... ....qqqqqqqqqqqqqqqq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmqmmqmmmmmq ....qmmmmmmqqmmmmmmq ....qmmmmmmqqmmmmmmq ....qmmmmmqmmqmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qqqqqqqqqqqqqqqq ...qmqmqmqmqmqmqmqq. ..qqmqmqmqmqmqmqmq.. .qmmqmqmqmqmqmqmq... qqqqqqqqqqqqqqqq.... .................... .................... # APRS m Mic-Repeater .................... .......g....g....... .......gg..gg....... .......g.gg.g....... .......g....g....... .......g....g....... .................... ........gggg........ .........gg......... .........gg......... ........gggg........ .................... ........gggg........ .......g....g....... .......g............ .......g....g....... ........gggg........ ..ggggg......ggggg.. .................... .................... # APRS n Node .................... .................... .................... .................... .................... .................... ......qqq..qq....... ......qqq..qq....... ......qqqq.qq....... ......qqqq.qq....... ......qq.qqqq....... ......qq.qqqq....... ......qq..qqq....... ......qq..qqq....... ......qq...qq....... .................... .................... .................... .................... .................... # APRS o Emergency Operations Center .................... .........pp......... ........pjjp........ .......pjjjjp....... ......pjjjjjjp...... .....pjjjjjjjjp..... ....pjjjjjjjjjjp.... ...pjjjjjjjjjjjjp... ..pjjjjjjjjjjjjjjp.. ...pjmmjjmjjjmjjp... ...pjmjjmjmjmjmjp... ...pjmjjmjmjmjjjp... ...pjmmjmjmjmjjjp... ...pjmjjmjmjmjjjp... ...pjmjjmjmjmjmjp... ...pjmmjjmjjjmjjp... ...pjjjjjjjjjjjjp... .................... .................... .................... # APRS p l Rover (puppy dog) .................... .................... .................... .................... ....qqqq............ ....qqqq.........q.. ...qmqmq........qq.. ..qqmmmqq......qmq.. ..qqqqmmmqqqqqqmmq.. .....qmmmmqqqqmmqq.. ......qqmmmmmmmmq... ......qqmmmmmmmmq... ......qmqqqqqmmmq... ......qmq....qmmq... ......qmq.....qmq... .....qqqq....qqmq... .....qqq.....qqq.... .................... .................... .................... # APRS q Grid Square Above 128m .................... ..q.q.q......q.q.q.. ..q.q.q.ikki.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.ikki.q.q.q.. ..q.q.q.ikki.q.q.q.. ........ikki........ ........ikki........ ........ikki........ ........ikki........ .......iikkii....... .......ikiiki....... ...qq..iikkii..qq... ..q..q.iikkii.q..q.. ..q....ikiiki..q.... ..q.qq.ikiiki...q... ..q..q.iikkii.q..q.. ...qq..iiiiii..qq... .................... .................... # APRS r Antenna, like radio station .................... ..q.q.q......q.q.q.. ..q.q.q.lhhl.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.lhhl.q.q.q.. ..q.q.q.lhhl.q.q.q.. ........lhhl........ ........lhhl........ ........lhhl........ ........lhhl........ .......llhhll....... .......lhllhl....... .......llhhll....... .......llhhll....... .......lhllhl....... .......lhllhl....... .......llhhll....... .......llllll....... .................... .................... # APRS s l Ship (power boat) (SSID -8) .................... .................... .................... .................... .................... .................... ........qqqq.....q.. .......qqccq....q... ......qqqqqq...q.... ..iiiiiiiiiiiiiiii.. ..iiiiiiiiiiiiiiii.. ...iiiiiiiiiiiiiii.. ....iiiiiiiiiiiiii.. .................... .................... .................... .................... .................... .................... .................... # APRS t Truck Stop .................... .................... ..gggggggggggggggg.. ..gggggggggggggggg.. ..gmmmmmmmmggggggg.. ..gmmmmmmmmggggggg.. ..ggggmmggggmmmmgg.. ..ggggmmgggmmmmmmg.. ..ggggmmgggmmggmmg.. ..ggggmmgggmmggggg.. ..ggggmmggggmmgggg.. ..ggggmmgggggmmggg.. ..ggggmmggggggmmgg.. ..ggggmmgggggggmmg.. ..gggggggggmmggmmg.. ..gggggggggmmmmmmg.. ..ggggggggggmmmmgg.. ..gggggggggggggggg.. .................... .................... # APRS u l Truck (18-wheeler) .................... .................... .................... .................... .................... .................... .llll.llllllllllllll .lcll.llllllllllllll .lcll.llgggllgglggll lllll.llllllllllllll lllll.llllllllllllll lnlnlqnnnllllllnnnll oqoqooqoqo....oqoqo. .o....o.o......o.o.. .................... .................... .................... .................... .................... .................... # APRS v l Van (SSID -15) .................... .................... .................... .................... .................... .......hhhhhhhhhhh.. ......hccchccchccch. .....hcccchccchccch. ....hccccchccchccch. ..hhhphhhhhhhhhhhhh. .hhhhhhhhhhhhhhhhhj. .hhhhhhhhhhhhhhhhhh. .ohqqhhhhhhhhhhqqho. .hqccqhhhhhhhhqccqh. ..qccq........qccq.. ...qq..........qq... .................... .................... .................... .................... # APRS w Water Station .................... .................... ..gggggggggggggggg.. ..gggggggggggggggg.. ..gmggmgggggggmmgg.. ..gmggmggggggmggmg.. ..gmggmggggggmggmg.. ..gmggmggggggmggmg.. ..gmmmmggmmggmggmg.. ..gmggmgmggmgmggmg.. ..gmggmggggmgmggmg.. ..gmggmggggmgmggmg.. ..gmggmgggmggmggmg.. ..gmggmggmggggmmgg.. ..ggggggmggggggggg.. ..ggggggmmmmgggggg.. ..gggggggggggggggg.. ..gggggggggggggggg.. .................... .................... # APRS x X-APRS (Unix) .................... .................... .................... .qqqq............qq. ..qqqq..........qq.. ...qqqq........qq... ....qqqq......qq.... .....qqqq....qq..... ......qqqq..qq...... .......qqq.qq....... .......qq.qqq....... ......qq..qqqq...... .....qq....qqqq..... ....qq......qqqq.... ...qq........qqqq... ..qq..........qqqq.. .qq............qqqq. .................... .................... .................... # APRS y Yagi at QTH .................... ..q.q.q.q.q......... ..qqqqqqqqq......... ..q.q.q.q.q......... ......q............. ......q..qqq........ ......q.qqqqq....... ......qqqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... .................... # #APRS z # #APRS { # #APRS | Reserved - TNC Stream Switch # #APRS } # #APRS ~ Reserved - TNC Stream Switch # # # # ----------------------------------- # ----------------------------------- # # Secondary table section starts here # ----------------------------------- # ----------------------------------- # # # TABLE \ # APRS ! Emergency .................... .........jj......... ........jjjj........ ........jjjj........ .......jjmmjj....... .......jjmmjj....... ......jjmqqmjj...... ......jjmqqmjj...... .....jjmmqqmmjj..... .....jjmmqqmmjj..... ....jjmmmqqmmmjj.... ....jjmmmqqmmmjj.... ...jjmmmmmmmmmmjj... ...jjmmmmqqmmmmjj... ..jjmmmmmqqmmmmmjj.. ..jjmmmmmmmmmmmmjj.. .jjjjjjjjjjjjjjjjjj. ..jjjjjjjjjjjjjjjj.. .................... .................... # #APRS " Reserved # APRS # Digi (green star) (w overlay) .................... .................... .........kk......... .........kk......... ........kmmk........ ........kmmk........ ..kkkkkkkmmkkkkkkk.. ...kmmmmmmmmmmmmk... ....kmmmmmmmmmmk.... .....kmmmmmmmmk..... .....kmmmmmmmmk..... ....kmmmmmmmmmmk.... ...kmmmmmmmmmmmmk... ..kkkkkkkmmkkkkkkk.. ........kmmk........ ........kmmk........ .........kk......... .........kk......... .................... .................... # APRS $ Bank or ATM (green box) .................... .................... ....kkkkkkkkkkk..... ...kkkkkmkmkkkkk.... ..kkkkkmmmmmkkkkk... ..kkkkmkmkmkmkkkk... ..kkkkmkmkmkkkkkk... ..kkkkmkmkmkkkkkk... ..kkkkkmmkmkkkkkk... ..kkkkkkmkmkkkkkk... ..kkkkkkmmmkkkkkk... ..kkkkkkmkmmkkkkk... ..kkkkkkmkmkmkkkk... ..kkkkkkmkmkmkkkk... ..kkkkmkmkmkmkkkk... ..kkkkkmmmmmkkkkk... ...kkkkkmkmkkkkk.... ....kkkkkkkkkkk..... .................... .................... # APRS % Power Plant (w overlay) nnoooooooooonn...... ..nnnooooooooon..... .....nnnooooooonn... ........nnnoooooon.. ...........nnnoooon. ..............nnnoon ................qqqq ................qqqq ..........q...q.qqqq .........qq..qq.qqqq ........qqq.qqq.qqqq ......qqqqqqqqqqqqqq ......qqqqqqqq#qqqqq ......qqqqqqq#qqqqqq ......qqqqqq#qqqqqqq ......qqqqqqq#qqqqqq ......qqqqqqqq#qqqqq ......qqqqqqq#qqqqqq ......qqqqqq#qqqqqqq ......qqqqqqqqqqqqqq # APRS & Any Gateway (diamond) (w overlay) .................... .................... .........qq......... ........qqqq........ .......qqqqqq....... ......qqmmmmqq...... .....qqmmmmmmqq..... ....qqmmmmmmmmqq.... ...qqmmmmmmmmmmqq... ..qqqmmmmmmmmmmqqq.. ..qqqmmmmmmmmmmqqq.. ...qqmmmmmmmmmmqq... ....qqmmmmmmmmqq.... .....qqmmmmmmqq..... ......qqmmmmqq...... .......qqqqqq....... ........qqqq........ .........qq......... .................... .................... # APRS ' Crash Site ..ppppppppp......... ....pppppppp........ .......ppppp........ .......ppppp........ .......pppp......... ......pppp.......... .....ppp........j... .....ppp.......jmj.. ......ppp.....jmmj.. .......ppp....jmaj.. ..jjj....pp...jamj.. ..jmmj...pp..jammj.. ..jmmmj.p...jmmmj... ...jmmmjj..jmmmj.... ....jmmmj.jmmmj..... .....jmmjjjjjj...... ..kkkkjjjjjjjkkkkk.. ..ffffffffffffffff.. j.....j.j........... ..jj..j..j.......... # APRS ( Cloudy .................... .................... ..ccccccccc......... ...ccccccccccc...... .....ccnccccccc..... ........ncccccccc... ...cccccccccccccc... ..ccccccccnccccccc.. ..cccccccccncccccc.. ..cccccccccncccccc.. ..ccccccccnccccccc.. ..nnnccnnnccccccnn.. ...nnpppnnnppppnn... .................... .................... .................... .................... .................... .................... .................... # APRS ) MEO (MODIS EARTH OBSERVATION) .................... .................... .................... .................... .................... ....jjjjjqqjjjjj.... ....jqqjjqqjjqqj.... ....jjjqjqqjqjjj.... ....jjjjqqqqjjjj.... ....jqqqqqqqqqqj.... ....jqqqqqqqqqqj.... ....jjjjqqqqjjjj.... ....jjjqjqqjqjjj.... ....jqqjjqqjjqqj.... ....jjjjjqqjjjjj.... .................... .................... .................... .................... .................... # APRS * Snow .................... .................... ............h....... ...........hh....... ....hh....hhh....... ....hhhh..hhh....... .....hhhh.hhh....... ......hhhhhh..hhhh.. ......hhhhhhhhhhh... .......hhhhhhhhh.... ....hhhhhhhhh....... ...hhhhhhhhhhh...... ..hhhh..hhhhhh...... ........hh.hhhh..... .......hhh..hhhh.... .......hhh....hh.... .......hh........... .......h............ .................... .................... # APRS + Church .................... .................... .........qq......... .........qq......... .........qq......... ...qqqqqqqqqqqqqq... ...qqqqqqqqqqqqqq... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .................... .................... # APRS , Girl Scouts .................... .................... ......jjjjjjj....... ......j.....j....... .......j...j........ ..jj...j...j...jjj.. ..j.jjjj...jjjj..j.. ..j..............j.. ..j..............j.. ..j..............j.. ..j..............j.. ..jjjj.......jjjjj.. ......j.....j....... .......j...j........ ........j.j......... .ppp.....j.......p.. p................p.. .pp..pp.ppp.p.p.ppp. ...p.p..p.p.p.p..p.. ppp..pp.ppp.ppp..p.. # APRS - House (HF) .................... .........qqq........ ..q..q....q...qqqq.. ..q..q....q...q..... ..qqqq....q...qqq... ..q..q....q...q..... ..q..q...qqq..q..... ........qqqqq....... .......qqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... # APRS . Ambiguous Plot (Big Question Mark) .....jjjjjjjjjj..... ....jjjjjjjjjjjj.... ..jjjj........jjjj.. .jjj............jjj. jjj..............jjj jjj..............jjj .................jjj ................jjj. ...............jjj.. ..............jjj... ...........jjjjj.... ........jjjjjj...... ........jjjj........ ........jjjj........ ........jjjj........ .................... .................... ........jjjj........ ........jjjj........ ........jjjj........ # APRS / Waypoint (destination) ..q.......q.qqqqqq.. ..q.......q.q....q.. ..q.......q.q....q.. ...q..q..q..qqqqqq.. ...qq.q.qq..q....... ....qq.qq...q....... .................... ........jjjj........ .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... ........jjjj........ .................... .................... .................... .................... .................... .................... .................... # APRS 0 Circle (w overlay) ........qqqq........ ......qmmmmmmq...... .....qmmmmmmmmq..... ...qmmmmmmmmmmmmq... ..qmmmmmmmmmmmmmmq.. .qmmmmmmmmmmmmmmmmq. .qmmmmmmmmmmmmmmmmq. qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq .qmmmmmmmmmmmmmmmmq. .qmmmmmmmmmmmmmmmmq. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... .....qmmmmmmmmq..... ......qmmmmmmq...... ........qqqq........ # #APRS 1 # #APRS 2 # #APRS 3 # #APRS 4 # #APRS 5 # #APRS 6 # #APRS 7 # #APRS 8 # APRS 9 Gas Station (blue pump) .................... .................... ......llll.......... .....llllll......... ....llmmmmlll....... ....lllllllll....... ....llmmmmll.l...... ....llllllll.l...... ....llllllll..l..... ....llllllll..l..... ....llllllll..l..... ....llllllll..l..... ....lllllllll.l..... ....llllllll.l...... ....llllllll........ ....llllllll........ ....llllllll........ ....llllllll........ .................... .................... # APRS : Hail .................... .................... .........qq......... ........qmmq........ .......qmmmmq....... ......qmmmmmmq...... .....qmmmmmmmmq..... ....qmmmmmmmmmmq.... ...qqqqqqqqqqqqqq... .................... .................... ...qqqqqqqqqqqqqq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS ; Park/Picnic Area .................... .................... ....hhhhhhhhhhhh.... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ...hhhhmmmmmmhhhh... ...hhhhhmhhmhhhhh... ...hhhhhhmmhhhhhh... ...hhhhhhmmhhhhhh... ...hhhhhmhhmhhhhh... ...hmmmmmmmmmmmmh... ...hhhmhhhhhhmhhh... ...hhmhhhhhhhhmhh... ...hmhhhhhhhhhhmh... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ....hhhhhhhhhhhh.... .................... .................... # APRS < NWS Advisory (gale flag) .................... .................... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjjqq...... ........qjqq........ ........qq.......... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... .................... .................... # #APRS = # APRS > l Car (w overlay) .................... .................... .................... .................... .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppnqnnnnnnnnnp.. ..pmmmmmmmmmmmmmmmp. .pmmmmmmmmmmmmmmmmep p#mmoommmmmmmmmoommp pmmonnommmmmmmonnomp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # APRS ? Information Kiosk (blue box with ?) .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhmmmhhhhhhh.. ..hhhhhmmmmmhhhhhh.. ..hhhhmmhhhmmhhhhh.. ..hhhmmhhhhhmmhhhh.. ..hhhmmhhhhhmmhhhh.. ..hhhhhhhhhhmmhhhh.. ..hhhhhhhhhmmhhhhh.. ..hhhhhhhhmmhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS @ Hurricane/Tropical Storm .................... .................... .....l...lggggl..... ....g..lgllllllgl... ...lg..glllgggllg... ...g..llllglllglll.. ..ll..gllglllllglg.. ..gl..lllglllllllg.. ..ll..llgllgll.lll.. ..ll..lll..lll..ll.. ..ll..lll..lll..ll.. ..gll.llgllgll..lg.. ..glllllllglll..lg.. ..glglllllgllg..ll.. ..lllglllgllll..g... ...lllggglllg..gl... ...lgglllllgl..g.... .....lggggl...l..... .................... .................... # APRS A Box (w overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS B Blowing Snow .................... .................... .................... ..qq..q...q..q...q.. ..q.q.q..q.q.q...q.. ..qq..q..q.q.q.q.q.. ..q.q.q..q.q.qq.qq.. ..qq..qq..q..q...q.. .................... ..qq.q.q..q..q...q.. ..q..qqq.q.q.q...q.. ...q.qqq.q.q.q.q.q.. ...q.qqq.q.q.qq.qq.. ..qq.q.q..q..q...q.. .................... .................... .................... .................... .................... .................... # APRS C Coast Guard .................... .................... .................... .................... .................... ...qqqq.....qqqqq... ..q....q...q........ ..q........q........ ..q........q........ ..q........q..qqqq.. ..q........q.....q.. ..q....q...q.....q.. ...qqqq.....qqqqqq.. .................... ..g.g.g.g.g.g.g.g... ...g.g.g.g.g.g.g.g.. .................... .................... .................... .................... # APRS D Drizzle .................... .................... .................... ..qq..qqq..q.qqqqq.. ..q.q.q..q.q....q... ..q.q.qqq..q...q.... ..q.q.q.q..q..q..... ..qq..q..q.q.qqqqq.. .................... ..qqq....q...q.q.q.. ..q..q..q.q..q.qqq.. ..qqq..qqqqq.q.qqq.. ..q.q..q...q.q.qqq.. ..q..q.q...q.q.q.q.. .................... .................... .................... .................... .................... .................... # APRS E Smoke .................... .................... ...mqqqqqqqqqqqm.... .mqqqqqqqqqqqqqqm... ...mqqqqqqqqqqqm.... ......mqqqqqqqqqqm.. ........mqqqqm...... ..........mqppqm.... ........mqqqqm...... .......mqppqm....... ........mqjjqm...... ........mqjpqm...... ......mqqjjqqqm..... ....mqqqjjqqqqqm.... ...mqqqjjjqqqppqm... ..mqqqqqjjppqqqqqm.. .mqqqqqqqjjqqqqqqqm. .mqqqqqqppjjjjrqqqm. .mmmmmmmmmmmmmmmmmm. .................... # APRS F Freezing Rain .................... .................... .................... ..qqqqq.qqq..qqqqq.. ..q.....q..q....q... ..qqqq..qqq....q.... ..q.....q.q...q..... ..q.....q..q.qqqqq.. .................... ..qqq....q...q.q.q.. ..q..q..q.q..q.qqq.. ..qqq..qqqqq.q.qqq.. ..q.q..q...q.q.qqq.. ..q..q.q...q.q.q.q.. .................... .................... .................... .................... .................... .................... # APRS G Snow Shower .................... .................... .......q....q....... ........qq.q........ .........qqqqq...... ......qqqqq......... ........q.qq........ .......q....q....... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS H Haze q..q................ q..q................ qqqq................ q..q................ q..q................ ......q............. .....q.q............ ....q...q........... ....qqqqq........... ....q...q........... ..........qqqqq..... .............q...... ............q....... ...........q........ ..........qqqqq..... ................qqqq ................q... ................qqqq ................q... ................qqqq # APRS I Rain Shower .................... .................... ........qqqq........ .......qqqqqq....... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .......qqqqqq....... ........qqqq........ ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS J Lightning .................... .................... ..............qqqq.. .............qq##q.. .............q###q.. ............qq##qq.. .......q....q###q... ......qqq...q##qq... ......q#qq.q##qq.... .....qq##qqq##q..... .....q####q##qq..... ....qq#qq###qq...... ....q#qqqq#qq....... ...qq#q..qqq........ ...q#q....q......... ..qq#q.............. ..q#q............... ..qq................ ..q................. .................... # APRS K Kenwood .................... .................... .................... .......jjjjjjj...... ....qqq.jjjjj.qqq... ....qqq..jjj..qqq... ....qqq..jjj..qqq... ....qqqq.cqc.qqq.... .....qqqqcqcqqqq.... ......qqqqqqqqq..... ......qqqqcqqqq..... .......qqq.qqq...... .......qqq.qqq...... ........qq.qq....... ........q...q....... .................... .................... .................... .................... .................... # APRS L Lighthouse .................... .................... ....q..........q.... .....q..qqqq..q..... ......q.qmmq.q...... ......qqqmmqqq...... .....q.qqqqqq.q..... ....q..qqqqqq..q.... .......qqqqqq....... .......qqqqqq....... .......qqqqqq....... .......qqqqqq....... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .................... .................... # #APRS M # APRS N Navigation Buoy .................... .................... ........qqqqq....... ........q...q....... ........q...q....... ........qqqqq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ...qqqqqqqqqqqqqqq.. hh.....hhh.....hhh.. ..h...h...h...h...h. ...hhh.....hhh.....h ....h.......h......h .................... .................... # APRS O Rocket ..........q......... ..........q......... ..........q......... ..........q......... .........qmq........ ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmqmq....... ........qmqmq....... .......qqmqmqq...... ......qqqmqmqqq..... .....qqqqmqmqqqq.... ....qqqqqmqmqqqqq... ....qqqqqqqqqqqqq... # APRS P Parking .................... .................... ....hhhhhhhhhhh..... ...hhhhhhhhhhhhh.... ...hhmmmmmmmmhhh.... ...hhmmmmmmmmmhh.... ...hhmmhhhhhmmhh.... ...hhmmhhhhhmmhh.... ...hhmmhhhhhmmhh.... ...hhmmmmmmmmmhh.... ...hhmmmmmmmmhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhhhhhhhhhhhh.... ....hhhhhhhhhhh..... .................... .................... # APRS Q Earthquake .................... .................... .......qqqqqq....... .....qqmmmmmmqq..... ....qmmmmmmmmmmq.... ...qmmmmqqqqmmmmq... ...qmmqqmmmmqqmmq... ..qmmmqmmmmmmqmmmq.. ..qmmqmmmmmmmmqmmq.. ..qmmqmmmqqmmmqmmq.. ..qmmqmmmqqmmmqmmq.. ..qmmqmmmmmmmmqmmq.. ..qmmmqmmmmmmqmmmq.. ...qmmqqmmmmqqmmq... ...qmmmmqqqqmmmmq... ....qmmmmmmmmmmq.... .....qqmmmmmmqq..... .......qqqqqq....... .................... .................... # APRS R Restaurant .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhmhhhhhhh.. ..hmhhhmhhmhhhmhhh.. ..hmhmhmhhmhhmhmhh.. ..hmhmhmhhmhmhhhmh.. ..hmhmhmhhmhmhhhmh.. ..hmhmhmhhmhmhhhmh.. ..hhmmmhhhmhhmhmhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhhhhhhmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS S Satellite/Pacsat .................... ..........q......... ..........q......... ..........q......... ..........q......... ....n...qqqqqqqq.... ....cn.q..q...qq.... ....cnqqqqqqqq.q.... ....cnqqqqqqqq.q.... ....cnqqqqqqqq.q.... ....n.qqqqqqqq.q.... ......qqqqqqqq.q.... ......qqqqqqqqq..... ......qqqqqqqq...... .....q........q..... ....q..........q.... ...q............q... ..q..............q.. .................... .................... # APRS T Thunderstorm .................... .................... .....qqqqqqqqqqq.... ...qqqmmqqqcmmmmq... ...qmmmmmqqcmmmmq... ..qmmmmmmqqqcmpppq.. ..qmmmccqqqqcppppq.. ..pqqqqccqqqcppppq.. ..pppqpcpppppppppp.. ..pppppppppppppppp.. ..ppppppppppppppp... ...pppppppppppp..... .........q#q........ ........q#q......... .......q###q........ ........q#q......... .......q#q.......... .......qq........... .................... .................... # APRS U Sunny .................... .................... .................... ......a..a..a....... .......a.a.a........ ....a.........a..... .....a.#####.a...... ..a...#######...a... ...a.#########.a.... .....#########...... ..aa.#########.aa... .....#########...... ...a.#########.a.... ..a...#######...a... .....a.#####.a...... ....a.........a..... .......a.a.a........ ......a..a..a....... .................... .................... # APRS V VORTAC Nav Aid .................... .................... .................... .................... ...qq..........qq... ..qqqqqqqqqqqqqqqq.. .qqqqq........qqqqq. qqqqq..........qqqqq qqqq.....qq.....qqqq .qq.....qqqq.....qq. ..q.....qqqq.....q.. ...q.....qq.....q... ....q..........q.... .....q........q..... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .................... .................... # APRS W NWS Site (w overlay) .................... .................... .......hhhhhh....... .....hhmmmmmmhh..... ....hmmmmmmmmmmh.... ...hmmmmmmmmmmmmh... ...hmmmmmmmmmmmmh... ..hppmmmppmppmmpph.. ..hppmmmppmpppppph.. ..hppmmmppmmppppmh.. ..hppmpmppmmppppmh.. ..hpppppppmpppppph.. ..hpppmpppmppmmpph.. ...hmmmmmmmmmmmmh... ...hmmmmmmmmmmmmh... ....hmmmmmmmmmmh.... .....hhmmmmmmhh..... .......hhhhhh....... .................... .................... # APRS X Pharmacy Rx .................... .................... ..pppppppp.......... ..ppppppppp......... ..pp.....pp......... ..pp.....pp......... ..pp....pp.......... ..ppppppp........... ..pppppp............ ..pp..pp............ ..pp...pp........... ..pp....pp.....pp... ..pp.....pp...pp.... ..pp......pp.pp..... ...........ppp...... ...........pp....... ..........pp.pp..... .........pp...pp.... ........pp.....pp... .................... # #APRS Y # #APRS Z # APRS [ Wall Cloud .................... .................... ................ll.. ..............llcl.. ............llcccl.. ..........llccllcl.. ........llccclllcl.. ......llccccllcccl.. ....llcccllcllcccl.. ..llcccccllcllcccl.. ..lccccccllcllcccl.. ..lcllcccllcllcccl.. ..lcllclcllcllcccl.. ..lclllllllcllcccl.. ..lclllclllcllllcl.. ..lcllcccllcclllcl.. ..lccccccccccccccl.. ..llllllllllllllll.. .................... .................... # #APRS \ # #APRS ] # APRS ^ l Aircraft (w overlay) .................... .................... .........nn......... .........nn......... ........n.n......... ........n.n......... ........n.n......n.. .......n..n.....nn.. .......n..n....n.n.. ..n.n.n.n.n.n.n..n.. ..n.n.n.n.n.n.n..n.. .......n..n....n.n.. .......n..n.....nn.. ........n.n......n.. ........n.n......... ........n.n......... .........nn......... .........nn......... .................... .................... # APRS _ WX Stn with digi (green) (w overlay) .................... .................... .......kkkkkk....... .....kkkkkkkkkk..... ....kkkkkkkkkkkk.... ...kkkkkkkkkkkkkk... ...kkkkkkkkkkkkkk... ..kmmkkkmmkmmkkmmk.. ..kmmkkkmmkmmmmmmk.. ..kmmkkkmmkkmmmmkk.. ..kmmkmkmmkkmmmmkk.. ..kmmmmmmmkmmmmmmk.. ..kmmmkmmmkmmkkmmk.. ...kkkkkkkkkkkkkk... ...kkkkkkkkkkkkkk... ....kkkkkkkkkkkk.... .....kkkkkkkkkk..... .......kkkkkk....... .................... .................... # APRS ` Rain .................... .................... pppppppppppppppppppp pppppppppppppppppppp pppppppppppppppppppp pppppppppppppppppppp ...pp...pp...pp...pp .................... .................... ..p..p..p..p..p..p.. .................... .................... .p..p..p..p..p..p... .................... .................... ...p..p..p..p..p..p. .................... .................... .p..p...p...p...p... .................... # APRS a A=ARES R=RACES W=Winlink etc. (w overlay) .........j.......... ........jjj......... .......jjjjj........ ......jjjjjjj....... .....jjjjjjjjj...... ....jjjjjjjjjjj..... ...jjjjjjjjjjjjj.... ..jjjjjjjjjjjjjjj... .jjjjjjjjjjjjjjjjj.. jjjjjjjjjjjjjjjjjjj. .jjjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjj... ...jjjjjjjjjjjjj.... ....jjjjjjjjjjj..... .....jjjjjjjjj...... ......jjjjjjj....... .......jjjjj........ ........jjj......... .........j.......... .................... # APRS b Blowing Dust/Sand .................... .................... .....qqq............ ...qqqmmq.......q... ...qmmmmmq....qq..q. ..qmmmmmmq..qq..qq.. ..qmmmmqqqqqqqqq.... ..qnmnmccqqqqq...... ..qmnmncqqqq..qqqq.. ..qnmnmnmnq.qqq..... ..qmnmnmnmq....qqq.. ...qqqqqqq.......q.. .................... ..qq..q...q..q...q.. ..q.q.q..q.q.q...q.. ..qq..q..q.q.q.q.q.. ..q.q.q..q.q.qq.qq.. ..qq..qq..q..q...q.. .................... .................... # APRS c Civil Defense (R=RACES, C=CERTS) (w overlay) .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ...qqqq...qqqq...... ..q.......q...q..... ..q.......q...q..... ..q.......q...q..... ...qqqq...qqqq...... .................... .................... # APRS d DX spot (by callsign prefix) .................... ..q.q.q......q.q.q.. ..q.q.q.lhhl.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.lhhl.q.q.q.. ..q.q.q.lhhl.q.q.q.. ........lhhl........ ........lhhl........ ........lhhl........ ........lhhl........ .......llhhll....... .......lhllhl....... .......llhhll....... ..qqq..llhhll.q..q.. ..q..q.lhllhl.q..q.. ..q..q.lhllhl..qq... ..q..q.llhhll.q..q.. ..qqq..llllll.q..q.. .................... .................... # APRS e Sleet .................... .................... .....qqqqqqqqqqq.... ...qqqmmqqqqmmmmq... ..qmmmmmmqqqmmmmmq.. .qmmmmmmmqqqcmppppq. .qmmmmqqqqqqcpppppq. .ppqqqqccqqqcpppppq. .pppqpccppppppppppp. .pppppppppppppppppp. ..pppppppppppppppp.. ...ppppppppppppp.... .................... ...qq.q..qq.qq.qqq.. ..q...q..q..q...q... ...q..q..qq.qq..q... ....q.q..q..q...q... ..qq..qq.qq.qq..q... .................... .................... # APRS f Funnel Cloud .................... .................... ..qqqq....cnnnnnc... ..q......cnnppppnc.. ..qqq....nnppppppn.. ..q......cnpppppnc.. ..q.......cnpppnc... ..q........cpppn.... ............npppc... ............cpppc... ...qq......cnppn.... ..q..q.....pppc..... ..q.......npp....... ..q.......pppc...... ..q.......pppc..c... ..q..q....npncc.c... ...qq......cppcc.... .............pq..... .................... .................... # APRS g Gale Flags .................... .................... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjqqq...... ........qjq......... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjjqq...... ........qjqq........ ........qq.......... ........q........... ........q........... ........q........... .................... .................... # APRS h Ham Store .................... .........pp......... ........p##p........ .......p####p....... ......p######p...... .....p########p..... ....p##########p.... ...p############p... ..p##############p.. .pp##############pp. ..p##############p.. ..p#p##p##p##p#p#p.. ..p#p##p#p#p#ppp#p.. ..p#pppp#ppp#p#p#p.. ..p#p##p#p#p#p#p#p.. ..p#p##p#p#p#p#p#p.. ..p##############p.. ..pppppppppppppppp.. .................... .................... .................... # APRS i Indoor Short Range Digi (w overlay) .................... .................... ..ppp............... ..p..p.............. ..p..p.............. ..p..p.............. ..ppp...p........... ........p........... ........p........... ........p........... ........p...ppp..... ...........p........ ...........p.pp..... ...........p..p..... ............ppp..p.. .................p.. .................p.. .................p.. .................p.. .................... # APRS j l Work Zone (steam shovel) .................... .................... .................... .................... ........pp.......... .......pppp......... ......pp..pp........ .....pp....pp....... p...pp......pppppp.. .ppppp......p#pp#p.. .p###p......p#pp#p.. .ppppp....pp#####p.. ..........p######p.. ..........ppppppppp. .........pmmmp.pmmmp .........ppppp.ppppp .................... .................... .................... .................... # APRS k l SUV .................... .................... .................... .................... ..........ddddddddd. .........d...d....d. ........d....d....d. .......ddp...d....d. .ddddddddddddddddddq d#dddddddddddddddddq ndqqqddddpppddqqqddq nqqcqqdddddddqqcqqnn .qcmcqoonnnnnqcmcqq. .oqcqo.......oqcqo.. ..oqo.........oqo... .................... .................... .................... .................... .................... # APRS l Area Symbols (box, circle, etc) .................... .................... .................... .................... .................... .................... .................... .................... .................... .........jj......... .........jj......... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS m Value Signpost (3-char display) .................... .................... .........qq......... ...qqqqqqqqqqqqqq... ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ...qqqqqqqqqqqqqq... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .................... .................... # APRS n Triangle (w overlay) .................... .................... .................... .................... .................... .................... .........jj......... .........jj......... ........jjjj........ ........jjjj........ .......jjjjjj....... .......jjjjjj....... ......jjjjjjjj...... ......jjjjjjjj...... .................... .................... .................... .................... .................... .................... # APRS o Small Circle .................... .................... .................... .................... .................... .................... .................... .........jj......... .......j....j....... ......j......j...... ......j......j...... ......j......j...... .......j....j....... .........jj......... .................... .................... .................... .................... .................... .................... # APRS p Partly Cloudy ............q....... ........i.i.k.i.k... .........k......i... ...........q#q...i.. ......iqqq#####k.k.. .....qooooq#####i.ik ....ioooooo#####q... ...iioonnooqqq###.ki ..qooqqncoqqonq##... .qoonooonooooooqk.ik .qnncnonnnonnooq.... .qoonnnccnnccnoq.i.. ..qqoonnnnnnoqi.k... ....qqqqqqqqq.i.i... ....hlhlh.lhq.k..... ....h.h.l.hh........ ....l.lh.l.l........ ....h.hh.h.h........ ...l.l.l.lh......... .................... # #APRS q # APRS r Restrooms hhhhhhhhhhhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhmhhhhmhhhhhmhhhh hhhmmmhhhmhhhhmmmhhh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhhmhhhh hmmmmmmmhmhhmmmmmmmh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhmmmhhh hhhhmhhhhmhhhhmmmhhh hhhmhmhhhmhhhmmmmmhh hhmhhhmhhmhhhmmmmmhh hmhhhhhmhmhhmmmmmmmh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhhhhhhhhhhhh # APRS s l Ship/Boat (top view) (w overlay) .................... .................... .................... .................... .................... .................... ........qqqq.....q.. .......q...q....q... ......q....q...q.... ..iiii.....iiiiiii.. ..i..............i.. ...i.............i.. ....iiiiiiiiiiiiii.. .................... .................... .................... .................... .................... .................... .................... # APRS t Tornado .......mmmmmmmm..... ......mmqqqqqqmm.... ....mmqjnnnnnnnqjmm ...mmqjnnnppppnnjqmm ...mmqjnnppppppppjqm ....mmqjnpppppnjqmm. .....mmqjnpppnjqmm.. ......mmqjpppnqmm... .......mmqnpppqqmm.. .......mmqjpppqqmm.. ......mmqjnppnqmm... ......mmqpppqqmm.... .....mmqnppqmm...... .....mmqpppbmmqmm... .....mmqpppbmmbqmm.. .....mmqnpnbbmbqmm.. ......mmqcppmbqmm... ........mmqpqqmm.... .........mmqmm...... ..........mmm....... # APRS u l Truck (w overlay) .................... .................... .................... .................... ........jjj......... .......j..j......... ......j...j......... .....j....j......... ..jjj......jjjjjjj.. ..j..............j.. ..j..............j.. ..qpppj.....jpppjq.. ..qpcpjjjjjjjpcpjq.. ...ppp.......ppp.... .................... .................... .................... .................... .................... .................... # APRS v l Van (w overlay) .................... .................... .................... .................... .................... .......hhhhhhhhhhh.. ......h...........h. .....h............h. ....h.............h. ..h...............h. .h................j. .h................h. .ohqqh........hqqho. .hqccqhhhhhhhhqccqh. ..qccq........qccq.. ...qq..........qq... .................... .................... .................... .................... # APRS w Flooding .................... .................... .................... .................... .................... ...c.....c.....c.... ....h.....h.....h... ...lll...lll...lll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..cchclhchlhchlcch.. ..cllclclclclclclc.. ..cclclclclclclclc.. ..cllcchchlhchlcch.. ..llllllllllllllll.. .................... .................... # #APRS x # APRS y Skywarn qqqqqqqqqmmqqqqqqqqq qqqqqqqmqqqqmqqqqqqq qqqqqmqqqqqqqqmqqqqq qqqqmqqqqqqqqqqmqqqq qqqmmqqqqqqqqqqmmqqq qqmmqqaqqqqqqaqqmmqq qmmmqqaaqqqqaaqqmmmq qmmqqaaaqqqqaaaqqmmq mmmqqaaaqqqqaaaqqmmm mmmqqaaaqqqaaaaqqmmm mmmqqaaaqqqaaaaqqmmm mmmqqaaaaqqaaaaqqmmm qmmqqaaaaaqqaaaqqmmq qmmmqqaaaaqqaaqqmmmq qqmmqqaaaaqqaaqqmmqq qqqmmqqaaqqaaqqmmqqq qqqqmqqaaqaaaqqmqqqq qqqqqmqqqqqqqqmqqqqq qqqqqqqmqqqqmqqqqqqq qqqqqqqqqmmqqqqqqqqq # APRS z Shelter (Evacuation) w overlay .................... .........pp......... ........pjjp........ .......pjjjjp....... ......pjjjjjjp...... .....pjjjjjjjjp..... ....pjjjjjjjjjjp.... ...pjjjjjjjjjjjjp... ..pjjjjjjjjjjjjjjp.. ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... .................... .................... .................... # APRS { Fog .................... .................... .................... .................... .................... ..qqqq..qqq...qqq... ..q....q...q.q...q.. ..q....q...q.q...q.. ..qqq..q...q.q...... ..q....q...q.q...... ..q....q...q.q..qq.. ..q....q...q.q...q.. ..q....q...q.q...q.. ..q.....qqq...qqq... .................... .................... .................... .................... .................... .................... # #APRS | Reserved - TNC Stream Switch # #APRS } # #APRS ~ Reserved - TNC Stream Switch # # # ------------------------- # TABLE # # APRS 0 Overlay Characters, etc .................... .................... .................... .................... .........cc......... ........cqqc........ .......cqccqc....... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... .......cqccqc....... ........cqqc........ .........cc......... .................... .................... .................... .................... .................... # APRS 1 .................... .................... .................... .................... .........ccc........ ........ccqc........ ........cqqc........ ........ccqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS 2 .................... .................... .................... .................... ........ccccc....... .......ccqqqqc...... ......ccqcccqc...... ......cqcc.cqc...... ......ccc.ccqc...... .........ccqcc...... ........ccqcc....... .......ccqcc........ ......ccqccccc...... ......cqqqqqqc...... ......cccccccc...... .................... .................... .................... .................... .................... # APRS 3 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......cccccqcc...... ........ccqcc....... .........qqcc....... ........cccqcc...... ..........ccqc...... ......ccc.ccqc...... ......cqcccqcc...... ......ccqqqcc....... .......ccccc........ .................... .................... .................... .................... .................... # APRS 4 .................... .................... .................... .................... ...........ccc...... ..........ccqc...... .........ccqqc...... ........ccqcqc...... .......ccqccqc...... ......ccqc.cqc...... ......cqccccqcc..... ......cqqqqqqqc..... ......ccccccqcc..... ...........cqc...... ...........ccc...... .................... .................... .................... .................... .................... # APRS 5 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......cqcccccc...... ......cqcccc........ ......cqqqqqc....... .......cccccqc...... ...........cqc...... ......ccc..cqc...... ......cqccccqc...... ......ccqqqqc....... .......cccccc....... .................... .................... .................... .................... .................... # APRS 6 .................... .................... .................... .................... .........ccc........ ........cqqqc....... .......cqccc........ ......cqcccc........ ......cqqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS 7 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......ccccccqc...... ..........cqcc...... .........ccqc....... .........cqcc....... ........ccqc........ ........cqcc........ ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS 8 .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqccccqc...... ......ccqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS 9 .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqqc...... ........ccccqc...... ........cccqcc...... .......cqqqcc....... ........cccc........ .................... .................... .................... .................... .................... # APRS A .................... .................... .................... .................... .........ccc........ .........cqc........ ........ccqcc....... ........cqcqc....... .......ccqcqcc...... .......cqc.cqc...... ......ccqc.cqcc..... ......cqqqqqqqc..... ......cqcccccqc..... ......cqc...cqc..... ......ccc...ccc..... .................... .................... .................... .................... .................... # APRS B .................... .................... .................... .................... ......cccccc........ ......cqqqqqc....... ......cqccccqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqccccqc...... ......cqc...qc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS C .................... .................... .................... .................... .......cccccc....... ......ccqqqqcc...... ......cqccccqc...... ......cqc..ccc...... ......cqc........... ......cqc........... ......cqc........... ......cqc..ccc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS D .................... .................... .................... .................... ......cccccc........ ......cqqqqcc....... ......cqcccqcc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqcccqcc...... ......cqqqqcc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS E .................... .................... .................... .................... ......ccccccc....... ......cqqqqqc....... ......cqccccc....... ......cqc........... ......cqcccc........ ......cqqqqc........ ......cqcccc........ ......cqc........... ......cqccccc....... ......cqqqqqc....... ......ccccccc....... .................... .................... .................... .................... .................... # APRS F .................... .................... .................... .................... ......ccccccc....... ......cqqqqqc....... ......cqccccc....... ......cqc........... ......cqcccc........ ......cqqqqc........ ......cqcccc........ ......cqc........... ......cqc........... ......cqc........... ......ccc........... .................... .................... .................... .................... .................... # APRS G .................... .................... .................... .................... .......cccccc....... ......ccqqqqcc...... ......cqccccqc...... ......cqc...c....... ......cqc.cccc...... ......cqccqqqc...... ......cqc.ccqc...... ......cqc...qc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS H .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqqc...... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS I .................... .................... .................... .................... ........ccc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS J .................... .................... .................... .................... ..........ccc....... ..........cqc....... ..........cqc....... ..........cqc....... ..........cqc....... ..........cqc....... .....ccc..cqc....... .....cqc..cqc....... .....cqccccqc....... .....ccqqqqcc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS K .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc.cqcc...... ......cqccqcc....... ......cqcqcc........ ......cqqcc......... ......cqcqcc........ ......cqccqcc....... ......cqc.cqcc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS L .................... .................... .................... .................... ......ccc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqccccc....... ......cqqqqqc....... ......ccccccc....... .................... .................... .................... .................... .................... # APRS M .................... .................... .................... .................... ......ccc...ccc..... ......cqcc.ccqc..... ......cqqc.cqqc..... ......cqcqcqcqc..... ......cqccqccqc..... ......cqcccccqc..... ......cqc...cqc..... ......cqc...cqc..... ......cqc...cqc..... ......cqc...cqc..... ......ccc...ccc..... .................... .................... .................... .................... .................... # APRS N .................... .................... .................... .................... ......cccc.ccc...... ......cqqc.cqc...... ......cqqc.cqc...... ......cqcqccqc...... ......cqcqccqc...... ......cqccqcqc...... ......cqccqcqc...... ......cqc.cqqc...... ......cqc.cqqc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS O .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS P .................... .................... .................... .................... ......ccccccc....... ......cqqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqccccc....... ......cqc........... ......cqc........... ......cqc........... ......ccc........... .................... .................... .................... .................... .................... # APRS Q .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......cqccqcqc...... .......cqqqqc....... ........ccccqc...... ............cc...... .................... .................... .................... .................... # APRS R .................... .................... .................... .................... ......ccccccc....... ......cqqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqcqccc....... ......cqccqcc....... ......cqc.cqcc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS S .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc...c....... ......cqcccc........ .......cqqqqc....... ........ccccqc...... ......ccc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS T .................... .................... .................... .................... ......ccccccccc..... ......cqqqqqqqc..... ......ccccqcccc..... .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS U .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS V .................... .................... .................... .................... ......ccc...ccc..... ......cqc...cqc..... ......cqc...cqc..... ......cqcc.ccqc..... ......ccqc.cqcc..... .......cqc.cqc...... .......ccqcqcc...... ........cqcqc....... ........ccqcc....... .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS W .................... .................... .................... .................... .....ccc.....ccc.... .....cqc.....cqc.... .....cqc..c..cqc.... .....cqc.cqc.cqc.... .....ccqccqccqcc.... ......cqcqcqcqc..... ......cqcqcqcqc..... ......ccqc.cqcc..... .......cqc.cqc...... .......cqc.cqc...... .......ccc.ccc...... .................... .................... .................... .................... .................... # APRS X .................... .................... .................... .................... .......ccc.ccc...... .......cqc.cqc...... .......cqc.cqc...... .......ccqcqcc...... ........cqcqc....... .........cqc........ ........cqcqc....... .......ccqcqcc...... .......cqc.cqc...... .......cqc.cqc...... .......ccc.ccc...... .................... .................... .................... .................... .................... # APRS Y .................... .................... .................... .................... ......ccc.ccc....... ......cqc.cqc....... ......cqc.cqc....... ......cqc.cqc....... ......ccqcqcc....... .......cqcqc........ .......ccqcc........ ........cqc......... ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS Z .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqq...... ......ccccccqc...... ..........ccqc...... .........ccqcc...... ........ccqcc....... .......ccqcc........ ......ccqcc......... ......cqcccccc...... ......cqqqqqqc...... ......cccccccc...... .................... .................... .................... .................... .................... # APRS > .................... .................... .................... .................... .....d.............. .....dd............. .ddddddd............ ndddddddd........... nddddddd............ nnnnndd............. ....nd.............. .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # APRS < .................... .................... .................... .................... ...d................ ..dd................ .dddddddd........... ddddddddd........... ndddddddd........... .nddnnnn............ ..nd................ .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # APRS * .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ..ddddddd........... .nddddddd........... .nddddddd........... .nddddddd........... .nddddddd........... .nnnnnnn............ .................... # APRS ^ .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # # # ------------------------- # TABLE ~ # APRS 0 ..gggggg............ .gggggggg........... gggggggggg.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 1 ..hhhhhh............ .hhhhhhhh........... hhhhhhhhhh.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 2 ..iiiiii............ .iiiiiiii........... iiiiiiiiii.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 3 ..aaaaaa............ .aaaaaaaa........... aaaaaaaaaa.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 4 ..######............ .########........... ##########.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 5 ..llllll............ .llllllll........... llllllllll.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 6 ..kkkkkk............ .kkkkkkkk........... kkkkkkkkkk.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 7 ..jjjjjj............ .jjjjjjjj........... jjjjjjjjjj.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 8 npllllllpn.......... lnllllllnl.......... lhhhhhhhhl.......... npllllllpn.......... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS # ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... # APRS $ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ DONE Xastir-Release-2.2.2/symbols/torndo.xbm000066400000000000000000000055201501463444000200550ustar00rootroot00000000000000#define tornado_width 110 #define tornado_height 32 static unsigned char tornado_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0xf8, 0x9c, 0x27, 0x22, 0x1e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x68, 0x22, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0xa8, 0x52, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x27, 0x53, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x28, 0xfa, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x28, 0x8a, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x28, 0x8a, 0x1e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/wind.xbm000066400000000000000000000055071501463444000175160ustar00rootroot00000000000000#define wind_width 109 #define wind_height 32 static unsigned char wind_bits[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x12, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x32, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x12, 0x45, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x49, 0x12, 0x45, 0x54, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x12, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/winter_storm.xbm000066400000000000000000000055261501463444000213120ustar00rootroot00000000000000#define wntr_strm_width 110 #define wntr_strm_height 32 static unsigned char wntr_strm_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0xf4, 0x7d, 0x0f, 0xe0, 0x7c, 0xce, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0xc9, 0x44, 0x04, 0x11, 0x10, 0x11, 0x51, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x45, 0x04, 0x11, 0x10, 0x10, 0x51, 0x54, 0x05, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x46, 0x3c, 0x0f, 0xe0, 0x10, 0xd1, 0x93, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x44, 0x04, 0x11, 0x00, 0x11, 0x51, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x44, 0x04, 0x11, 0x10, 0x11, 0x51, 0x14, 0x04, 0xaa, 0xaa, 0xaa, 0xaa, 0xfc, 0x48, 0x44, 0x7c, 0x11, 0xe0, 0x10, 0x4e, 0x14, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/symbols/winter_weather.xbm000066400000000000000000000055261501463444000216050ustar00rootroot00000000000000#define winter_wx_width 109 #define winter_wx_height 32 static unsigned char winter_wx_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0xdf, 0xf7, 0x00, 0x49, 0x11, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x4a, 0x92, 0x4c, 0x44, 0x10, 0x01, 0x49, 0x8a, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x54, 0x44, 0x10, 0x01, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x64, 0xc4, 0xf3, 0x00, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0x44, 0x10, 0x01, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0x44, 0x10, 0x01, 0x49, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x44, 0xc4, 0x17, 0x01, 0x3f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.2/testdbfawk.1000066400000000000000000000024551501463444000165740ustar00rootroot00000000000000.TH testdbfawk 1 2009-12-22 "The Xastir Group" .SH NAME testdbfawk \- scan dbfawk files for matching dbf file for map rendering in xastir .SH SYNOPSIS .B testdbfawk .I [-f file.awk| -D dir] -d file.dbf .SH DESCRIPTION Scan dbfawk files for matching dbf file for map rendering in xastir .br .PP .B --help prints command line usage .br .B -D for dir containing *.dbfawk files. .br .B -f for file containing awk rules. .br .B -d for dbf file to parse .SH EXAMPLES testdbfawk \-D . \-d tgr36119lkA.dbf 2>&1|less testdbfawk scans the current directory for dbfawk files with signatures that match tgr36119lkA.dbf's signature. testdbfawk dumps its output to standard error, so in the example standard error is redirected to standard out and piped into "less" for paging. .SH NOTES Dbfawk hints and kinks: You have to think like an awk programmer and realize that the order that rules are listed matters, that it's important to use "next" as soon as it makes sense so other rules aren't looked at unnecessarily and, to use "skip" when you want to fix bad dbf data. .SH SEE ALSO README.MAPS in xastir documentation .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2023 The Xastir Group Xastir-Release-2.2.2/update-xastir000077500000000000000000000054551501463444000170770ustar00rootroot00000000000000#! /bin/sh # Copyright (C) 2000-2023 The Xastir Group # See README.sudo for instructions on setting up SUDO for # Linux/Unix/MacOSX systems, specifically the /etc/sudoers file. CYGWIN=false uname=`uname` case "$uname" in CYGWIN*) CYGWIN=true ;; *) ;; esac (date 2>&1) | tee make.log (git pull 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log (./bootstrap.sh 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log (mkdir -p build 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log (cd build; ../configure 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log if $CYGWIN then (echo "************************************") | tee -a make.log (echo "Building for Cygwin Operating System") | tee -a make.log (echo "************************************") | tee -a make.log (cd build; make clean 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log (cd build; make install 2>&1) | tee -a make.log # chmod 4755 /usr/local/bin/xastir chmod 755 /usr/local/bin/xastir echo "" | tee -a make.log (date 2>&1) | tee -a make.log else (echo "************************************************") | tee -a make.log (echo "Building for Unix/Linux/MacOSX Operating Systems") | tee -a make.log (echo "************************************************") | tee -a make.log (cd build; sudo make clean 2>&1) | tee -a make.log echo "" | tee -a make.log echo "" | tee -a make.log (date 2>&1) | tee -a make.log (cd build; make 2>&1) | tee -a make.log (cd build; sudo make install-strip 2>&1) | tee -a make.log # sudo chmod 4755 /usr/local/bin/xastir sudo chmod 755 /usr/local/bin/xastir echo "" | tee -a make.log (date 2>&1) | tee -a make.log fi Xastir-Release-2.2.2/worldhi.map000066400000000000000000010301741501463444000165230ustar00rootroot00000000000000WU2ZBetaWolrdMap.MWDB.Map HiWorld Map HighWU2ZC `Ź`ck&@+p @+p X8+ + 0+ , {`, r, ,h p,x fH, y, P,p ,k 6,K 4,1H + S,3 h,, jp, +(+0 o , z, B+ v(+ @+ UX+x +( +` l+ +X +@ +` +@ `+ ʈ+ 4+ B+q +4( + P + * h*X x* ո* * * *h@ * 0*e @*Z0 p*8 * )h )H () ) ) )X ( [( b(( Rx( Y( 8(u 8(| (M0 p(T8 x(,` ( l' l' B' a' W'| ('i 0'p &0 H& p&s h&N@ l& @& v(% % % % % %@ %@ %x /P%0 ?%( 1%i(+ P i(+ P f*0 + p0+ P+(p ~@+(p {+F +x x+u 0+M ٨+x 0+H + + + @+hP. P. - - - ]- #`-yh -p -O8 x-) -0 -O8 -r` !-yh x,P , P, ,Tp c0,[x n,F` Wx, e+0 Wx+p j8+p c0+X +sp +8 X* P*{ *E *! *x #`) [* H*}X Հ*}X H* * *8 * * p* :H*Ѹ <*H i(+ P- - 8.)0 .h ,. /8 H/;h 1p/N( / 0/` x/ p0 J0l p0 0 0X 0 08 0P 0H 0 +0X 0 / / /` 0/8 (.@ {.o ..4  . P.8+ 8+ h, H,b ,y 8, , ݘ, , `, X,޸ , , !- K- G-5p g-` %\ Ԡ%\ %` %} % 0%8 Ԡ% 8% % & &0 Ԡ& &` & (& & P& P'h p& ('` '  x'( ' '/@ x'K` 'K` h'[ 'n h'l0 @'ǘ $P(] >( ^(( oP(x e( hH( (P hH( {)'( ()G )E x)O X){ )( ) *^ *^ *c /* K*p ?* z+1 p+8 +0 +H +X ژ, , (+ , ̈,: ژ,[x , ,P X, ', w-  , `, ,p A0,Y (,i J,R 7,: rh+( +x h+( h+M h+M +4( +;0 +1 * * *@ و)h ) )h * @) 0)` )o و)'( X(p 0@(P EX( Q( ax(ĸ (r `(pX (V (* H( ' h'b l &H &H (& & & `& & @& &0 & C& T(&xp 3X&a X&v &= &P x& 0&@ p% 0%8 `% N%N )p% S%Eh Z% ]%v d% f`%X v%h }%a 0%p @%>` %c P%G H%p `%{P %h %a %f8X# X# # p# #( %(# <# 0# ː# # (#z #uX # f@#0 q# h#|` P#gH /#s UP#] 0#8 }(# ш# x# $ @$5 `$7 X$Q ($_ =X$b B$Q P$m Rp$T W $b} 0 } 0 }h }` H } }@ 0 } H }h } h ~ h ~ ~N` ` ~e h ~j ~!@ ~!o` ~!x ~@! ~h! "` 6h"# sX"&0 P"D "\ `"j( :" bh"Ő "Ő P" :" Z"0 rH" Ը"@ X" ;"@ \#Fx #K( H#[ /#d Ph#|` 0#~ # @#~ #X#w ,# # X#}7x ( }7x ( }5 p }9 } 0}y!h }y!h }J8!P }!L8 }9!) }U!4 }7x (~# ~# ~p# ~#z ~l#R0 ~}@#[ ~e#*X ~W#( ~Z# ~j##P ~v8# ~v8" ~Uh" ~o0"̘ ~(" ~" }"H }ۈ"^p }P"\ }H"P` }"D }X"&0 }"&0 }y!h# # @# !P# ;#H &#k 4#6 # ~#, ~#[ ~P#i ~H#s ~8#p ~## # #V #H # # #( ("x " Ͱ# # # x#H d8#b E# # H# #@ H# $h $. O$:8 $) $. |$HH W8$A@ P0$0 R$ 6h$ X 4$  8$ *# # # (M0 (M0 P(H @(H 7'H S'p Ը'` ': X'# ' 8& P&UH 8& 8&; h&9( & z%0 %< % % ( ($ G$J #z`*x z`*x {*` {H*x {``*e {*q {*a8 {*oH {`*P {*@ |X*0 | ) }>)x }) })y0 })fp H) x(( ( 0( (Jz`(n z`(n zg( zU0(p ze) ` zIx) zl) zv)9 z) z) z8)X z0*& z̸*vPv!N v!N u@! up" u0! v8" vH# wh# w#Fx wMh#( wTp#` wF`# wr$ w$" w$_ x7$٘ xC$P xO8$ xa%"@ xQ%q xE%f8 x]H% xf% x&B x&N@ yB& y}& y'8 yH'p z'X z&P(H z&P' z@( zW(? z`(pXv!4 v!4 v!Nv!4 v!4 v!4v(pA v(pA uH u8 :vPg vPg vu( vsp v(pAvPg vPg vH vX vH vH vH v}8 vxNX vX& vlhD v(D vI@^ u9@ uH u}X}8 ua8 th tP tv\h s28 s28 s s.X rܰs rXL rGP r- rz@; rl0D rFZ rRh9@ qI rF; rDX( rpp q0p q@ r r  q qр q q` q0X q q qr q} p qIk qqhU q^Q8 qcX2 qfP q0S qQ8 qQ8 q5 q q@ q qx` q0 q;Ę q60 q=~H q? rM r*? r,@ rF3H r:F rC rX5 r(. rH0 sQx r p r r s%X s%X s0@ tp0 t  tup u0[ ue vXO v8[ v(pi vB8 vH v vx v w8Px w~ w wX xx8 xX yPxـx xـx yQ y yHup yPwhx whx x3w x8 xXw xr`{ xx wP w(Ƹ xH w w0@ x& w w& wHEH wP$x w& w_ wc w wK@ wA w0{0 w@ w( w. vX wOx ww w w` x)@ xxw8P w8P wb wP( wxs,` s,` s#v s'EH s5ah sV@ s~h>@ sh( t"x t'( t> t+p tfp to tQX{ tvp tp t t0x tG t{ tX` t(" u!  u>$x uUh uW4 ul4 uI tx uNx uP u4 uZ0 u( u v&֘ vc vx vڐp vH v`} v} v`H vB8} v v*P v4(0 vKH v" v8 v v wp w:Hs,` s,` sP rΠ r rP r( rǘ r(X rΠ r  rx r@ r8 rgrg rg r rM r3@ r3 q r(#h rDX`XrDX`X rDX`X r^  rܰ rH q qߐ q7 qBp8 qG8J q" q9(" q-p q-p q-p q/ pH p px oPx o? pGb( ohC oPOh p (f p (~H oHVp opb( o op{ ohVp orxAX oy0 oHH5 oJt o o o{P om o@0 o o> o' oh5 oJ0 oJ0 pt` p0 oҐx o o o oxh oˈ0 o o[p oH= ol o]`9@ oA@D o:8s o,(e o X nx nD n6 nP n nw n0r n(aov ov op  o o{h odho oQZ oCh o.Q8 o,(a nHfP nQ8 n~fP ngH2 nD  nH n8 nOx nR0 n?p8 n n mXmX mX m@r mx8< mX:P mz mH mX m m m@ mw msms ms m( m# l lX l9x` l@ l& kp kx kxqH k2* kC` kh@ k k j j j0 jJt( jihcjihc jihc jQI j<Z` j`LP jX_ i{0 ix ip i i@ i( i&H j[X j j`RH k5Pi ki kH|x kp k( l m hd lP` l lOh lo`H` lS@< lc0 lB. l8i0 k lNˠ lS@ lE0 k k0S k8 kv kvo kG k7p kH' k k{r kC`r k(Vp k? jh jx' j0 jH jihx j ( i`YP iB3 hp% h h h8 h h hlBh gP gNR gc8gc8 gc8 fgf(g f(g flf j@ f j@ fp fP fCX e0 e( eP( ep eP ep e eup e( e,h e  e!z e dp dp d` d!d! d! d1x dx? dnh d  cj cEH c_x cG c2" b~H b b @ b b$ b9 b{h bf b{h b" ax8 aB a4 abxGP `shD `Rcp `o( __P _P _x_x _x _ʨ _ _h8^ _WB _x& _a09@ _S & _0X _8H _ ^͈X^͈X ^͈X ^0x ^'  ] ]X ^` ^ mX ]L ^' U ^@ ]U ]+ ]HP ]H ^ Xf ]]x ^ ^+ ^  ^ ^ Ո ^P ^ ]( ^b^b ^b ]M ^$, ^ X: ^ ! ]@` ^` ] ]0 ]H ]( ]`p ] ^c8 ^@s ^` ^(j@ _ _qH `j `` a8H a] a0 a a a b ` b.`h bO0 bG bV8SX b>>@ bL& bCx a` aP aɘ0 ap ay` ah a|@t aX aOX adE a*8J a']@ a'5h a0 `@ `zp.` `q `F `( `qp `` `^P` `8 `n` `P `B0` `?ɘ `X `0 ` `( ` a(` a*8 ag( a a8 aɘɘ aР b"0 b0 bg( aO aР b0#0 bA V bV c&A b8< b c8 c( dG`dG` dG` dH6xd8 d8 eAD e6(1 dP!` e:(h eX e1xX e#h dx e0 eX eO ez W eW f) fx fX/g@E g@E gx0 g gp gx g͈ hGP g@ g@Ԑ g! g gfP gfP g\ g@X f f f$@ fp( f2Pg@G g@G g' g)x g' g8 gr@ gQ8 gZ g_H g}P gfP gU gU| gr gX@[8 gfPM( go_ g[8 g(< gۀ_ h] g. hW gH g gx? g] gh:h g h ` hW h h( h" hW h%P hJ hsJ hxk hH[8 hXpP h0 h0 h h hxİ hLX hap hxp hI( hp h4 h50 h=JH h(C@ hhShP͈ hP͈ h8x hp` h  h hs hz hL8 hZZ hhQPj j jwxۘ ju p jCp j P iX i@ i i ihp i iDpp i*Ԑ i(( hP͈j@ j@ jPۘ j jj j jnh jr( jH jwxۘ j@m m mWhH mp8 mXX m8mp lQP ky( k jrFh rFh qh p p p`h p{P p<p p0x p8 oĀ o  o  o(0 o(0 o01 oe ps0 p>`^ p_0gx p7X pG o%P o oJ( nh n8 np8 nkd ndy n@ n(> np nuX nO"p n@ mP@ mpr/@+ r/@+ r r+ r;x r~+ r`D r` s:p` s~hp spX rըp r08 rP ru rM rFhp& H p& H pq : pa H pm@ b pȨ r ph ¨ p P pȨ h p X p\ o٘E odh{ oHHrp o. o8 o.H o% ` n n nh nɸ҈ nw nE` npc nhx n8( n n8( n6 nx( n6 oOPB oA@^ oI orxe o`v ox ohxh orx oq` o p>`q` paq` p\e pe pG0 qY qPB q9(K q6 qWG0 qh6 qxp&` ql9 q0@( q( q;x r/@+i(P i(P iP h` i e i(PW i#n i6`e i8R` i1s0 ige iI p iM0 ie@ inh i8,X i8T0 im iθr ip iH j i0 j. j` j jİ j8 j j kh kxAp k  l  k( lH0 k l  kX lPh l8w lXw lgx kR` l-P l? kH: l;* lj* l l l lX l m( mp l؀ l lU8 lc( lh l$`x k kx k l lqh lm lh l@ l  lj l l l m\@ m* m? mY( m6jX m4@z m*jX mq` lHP m Y l&` lPP lE0 l\ l>( lL8X l}p lhXh l@ lf l  l lր m8 l mBP m-8 mY mz@ m m0 n=d` n nz ( nnP  nX n n@ n( p o` nH np V o. p o d o) A oQ R( o Y0 o Fp p& Hsh  sh  sp su ) s - s1  s3h 8 s0  s. 0 r p s| p s@ Ԩ sH s[@ sx siP s1  rx  rܰ rX ` rDX rp 0 r, rl0 r rT ` rg X rX t r _x r v q v rp q ` qp qv H qxp q( p qY p q0 v p p p p 0 q` pϰ t pH X p { p t pc t ph X p5 P pv p@ 8 oˈ o ( oh  o h o p o~0 ` o'x ` n@ n h nP n ` n x oP  n o oP " n8 ( n H n[  n] 8 n P nT E( n 7 n E( m e n 4 n m 8 m8 ) mh 7 m 7 m P m0  mIX 2h mP` I m j m \ m;H ; m I mP` aH m  aH l E( l \ l t l0 { lt 0 lP lx lH H lW H l8 X l X k p lx p l lS@ 0 lf P lI 0 kP l  kH 8 k k P lH ` k ` k # kƠ  k( 1 k kh  kE  k h k # j 1 k.H ;@ k IP kQp * kP 48 k D k7 K kQp Y kp R kh ` kP x0 k]( ` k7 Y kp ` k'@ R j` \ j k kS kd0 k) k k j jx H j  jO  j jn ň jQ 8 j0 j%p 8 jh @ jh @ j* jk ڠ jC P j: i X j x jO  j 8 jX x jb` 0 jy  i % j P % jh D i0 3 iθ D i( b i8 i i( |X i  i i( i x i@ p i i  iM ɰ i ix i` i# i4 iY 8 i* iF i 0 i@ P h h( hH h P h( h^:0 hU`OH hWS hxQ hxi h@Hi h!w hli h@Hw h\h hkh hߨVP hpd` i7 i1H@ hp]X i*f hÈ hߨ h@H hjx h@` hGPX h6{ g8 h g@P h g gx@ g g g g\x g@8 g g gQ8 g5 g gC(ِ f`҈ fx fX f0 fph gZ g f( g' g0 fPp fˠ fĘ fOhx fX fM"8 f"8 fp9 f8< f0Q fҨSp fSp f"8 fb(- fw@Sp fX- f%8>X f]xZx f(Zx fE` f U e8G eZx eXG e_( eo f'm8 ft@ f0 f"v ext@ eH e e e8 e ex f  e e e e  e eְ e f  fi0ݸ f f{Ϩ fְ f`8 g( fH gPP f fH f  fְ f_ f<ݸ e e e e ep eܐ! e@ @ ehX ehX e -h eH f X e@( eI e8h fhG0 ee f } fF9 f( f4p f4p f`= fto fP@( f[ G0 f5` fTjX e f) fVp f p eP e8 e@ eh eܐ eH e eX߈ f(( e f ` fAXh f"( fVp fOh fy f,@؀ fM؀ fm f f0p fX f<h fC f(  fh e e* f.^ fs0 fgx fn f fh fz8 fH fP f fX g5 gGu gc g@6@ gۀ, h `% gP h6 h  hGPh h@ hh hX h}8@ h h@ hp( hʐ0 h h@ h i@ i(P ( c ( c \ x +` O @ 3 +`  0 *` j ] 0  8 P R ( P H 8 @ 0 X ݐ ( W h Ch h  P ` ` 8 , , 8 ݀ bh X 8 R 0   `   8  ø ~ 0 } ( }  }0 IP }' PX } |[( |t |" x { { q( {Έ ;@ | / |%@ {` z z {, {%  {F ` {  z {A P {[ @ {h x {% A z 8 zH #H z 3 z *P z 0 z h z8 y  xh d x y"( p y @ x x8 x h wH 0 w ` w  w w0 v ¨ vX wMhX w˜ wE w~b vE v% vjvI@` vI@` u8 v p u8 p u u u |X u K v V u0  u- x uh@  t X uL t` u- Ә t 8 t td tp tX u ( uL 8 u` u 0 ux @ u` w #H xp  x ( y y @ yf = yx 8 x P xh  x, w v q v/x c u Z@ uGp t ux ( u9` t u@h I tX ^ u G tX L0 tp 9p tv 9p t  t` 7 u0  tk 0 t  tL  tX` ) sh   (  VǨ Pp * ( [P P h 8  e8 8( K < B [P u d $ . @ ' x =` 8(8 J  J`l@ W  ۰ ` G ;` q aH 7  PX  0 }0 O l GH ,I #e Sh -  h( ` h D p  { O( K8ch hz Fe (jp  \( 8 % Pp 0 &@@ vx  À (h _(    T`X @ 18h  8 18À x WX (p H 5(/P (H ; Ĩ? 0u :`W( e8 h| ` b8 Hpx 8( p P hp  Ĩ (  h X  x h 0 (  * "0 8( P ?0 EX [P 7H @ v   h  ׈ I p ( _x 0  ͠ qX D  h 0 jP o 0 x  ` x &X  J` } 7  0  G ׈  b 0 P i  8 (  uH E @

H S ) 5 ) A   0  0 P 3  H H  R   v   h B Ѐ X E  p P H  #h d b 8 ` G p j@ Ѐ j@ H X ̰ .@ K .@  x h 0 X

 P  IP0 7 P p ' 8 k x I n ; H h X 0 06( 06( àX @  @  @ I8 j KŨ 0 0Ũ x @ p ڈ ( P n0  Cxg ~ G 6rX c8,  @ x X5 @ *pH   A8 H Ѱ ʨ g` z h8 *pB iUx B 8+H b X (x  j@ (P (  x 8( ƀ p N 0 LP @ + I 2 H Xk )d 'XC@ @ \ wX ϐpP (] " P 6(i 3H x p  H @H ^ X Kx g  px xh  PP X ` 0h X p 5P0 X @ h k8p X p P 8 S@8 }pX  (  `  8 PX ( ( I   Ϩ p b} Tm8 `  `h P X (ݸ  p @( hH 5 ` ` ` 9( a` j`x 8` cX} ( * "8 X"8 x4 ?"8 h<  X@     Y @( cP x XR` P  p  H  O U' h8   ڨ? xc h|  X a0 0P c ,(P +H ˈE ` x  x hۘ Ґ` <y( @0 (Z  p -p u \PpP sk &h Y  F K? Dh  @0 P  ` 6@ o Y X s  } pv  z  #o K`v i8 v h F(4p P0 ]z 8= -h Ԙ$ ex K h;x (-h  T8 T( ^X8 x  ^X h (` h  0 0 8P ~x ɠx ɠc P_( '`J  @   7@ Zh EPx Bp9 ň U0 n  4`X   0 @0  { H@ C  ĵ, U P J  ( Þ @  x Ó0 ɰ dP ²0 ( f  × ¨ p 4  p  2 H q x   8 xX h xX h*0 0 *0 0 ` p  6 *0 8 ix 8 R r h P  , ' נ T r  d $p w >8 H {(   ` # xH  p % p`  =( P  8    @  R@  x A x O uP , g@ x Y0 3 ] |p p [ w  w  Fp  d 3@ ] ' D  /  @ ]p  Q  " 0 C x  h X X (  h  ( h Š X xH X ;X R ! n Ih  Ih      @ H ݘ x0 h ^h 8 q(  D rP L d@ X h Cp   H ø C (ŝ x ŝ x ń x \8 c  ^ 4` W +` Þ    P @ `   S( 2h 4 p 0 @  x H ( }h QX hP   E( B 4 X P  +`d9 d9 x h (H ٰ 0 0r ]x 05 ۘ( ! 8 1x 06(y y  rP d  u   ( x @H h! _ iH+0 T0 Hx; Ap! 3`- '= ApW HxB M(P ]D [8jx mh kP ]X wX  m p y hʐ XP wX` ] C T04 :h% C? T0; M(T iHDp uP( J[ mlH [8n JlH <b Ox b@sP _( p xh W0 ` Hx  p p pP( P( lH P( F 8 C@F _`=h kM tx6` fh1 /X  (P 1 ( h (h   d91i0 1i0 DPt * M T gx   ` x. 7p 2 >x wa Hr [  H8  ( H ` 8 ܨ * M( yy y [ Sph q  h 0 Xw@  ( v8 8 P `ˠ  ( f0 q+     H p 0     1i0h h p0h h Hh 0  3( bˠ p yf- f- HX pߨ p 8H H  +H -o( Sp^ 4S `GP h4 = B ݸ p+0  4 ++0 / p 2 G0 0 p    2   h X _ 5 LX ){h {h hp"| p"| +"Wh $"1 C" 0!X N" U!X h! o! X! h! 0! ! {H! j! p!P ! ! !( ! 0!t !j !W 0!W !f Ƞ!N !hX ݸ!f h!0 Ƞ!>( !I h!9x ! 8 0  P $ h < ( ` @ Lh X } X m $OP $% ¨$ # $ ɰ#( и#@ # # # #p # #ɸ <# ># :0#0 .x#x E#x J# Q#x p#x L#|` kh#`@ # #s H#h ~(#T #T P#( _#( L# ~(#*X @#@ #( p"x "x " " "H 8"H 8"0 "( "x "̘ " ҈"0 "X @" 0"p " " "H "s "z1% 1% T% P % [% b%X u%p % sH%h %a % % %tH %h `% P%0 `% %( @% P%} `% 1 % F8%( A% ,p% `%8(& 8(& *& 3x&+ O&6 :&; A&R u&P &6 wp&X | & (% bX%8 i`% %ϰ ~x%0 8%@ 0%X P%P %0 % ސ% `%0 % 2%x H%h 9%x Qh%` f%{P Xp%f8 k0%v X% h%{P h%Q %a 0%{P X%_0 %f8 0%< %U )%@ % 0%@ @x%@ B% ( )$ 9p$ $ 7$٘ +`$ hP$x > $Ā E($@ G$٘ G$P m% p% t%& %5 % ( `% ( %8 % h$ $ % % X$ H$ 6$ *$X =$ \$ `$ F$٘ s$@ |$` $@ $8 $@ P$h $ ($ $H 0$H $p /$ ?h$w(}Q8 }Q8 }ۈ ~q8 ~ ~pB lPW D $( R/ 89@ |0}S }S }pp }8 }Ԁ } ~` } ~b( ~GXC ~Vp ~a %8 ~  } }up}up }up } | }PW |W | |0e |Ұ&H |X | |X }hp |N } j |8LP }$c })hSX }aLP }000 }HEH } }ۈh } }PX }}H }H } }@ }Px ~p0 ~ x ~(0 ~GXx x P0   H  h    j @ Mx H  8 ~߰x ~X 4 ~HX ~v8 ~ ~(   H DxH eH  8  8  @O ( 8 000 0 XT [`H |0T 0   P h € g V ?@ 3  p H 7  p8  t O{ 88 d8 8 ' h8  pP MPҨ MP ]( dp  pxG |0W#]X W#]X Ve_ VhP< VL Vp< V 'p V W#X V W VP V V( h U Ux ` V$X H V- X Ve Vx P V V V` V{ 0 V |X V |X V g@ V}h b VoX r Vc uP VS8 d U@ ` Uf uP U b U͠ p U͠ g@ Up K Up g@ VH ] U V V" Mx U@ A V Fp UH , V / U`  U  VW : Vj ' VoX Fp V 3 V Fp V #H V@x 0 V0 V4 x V-  V  V , W( , W 6 W/ : W( T V8 O W* g@ Wh ~ W;@ ~ WK 0 Wc W` i W w W ] Wh #H WP #H X/ T X1X % X  X % X `8 X  Y< : Yt  Y #H Y Y Zm8  Z(  Zh  ZX  Z / Z R( Z R( Z uP [ `8 [cP z [cP z [/ [l [+ [v @ [ [Y X [+ X [P ` [$ x Z [ @ Zݸ 8 [ Zh Z% Za Zm8 h Y҈VP YS Yf Ykh Y Xи X@ W̐ Wrp Wxm Wh_ WPrp W[ Wq(f W?[ WPXOH W#]X^0 ^0 _   _P _h _2 _QP _xmp _`mp _H _àv _Ѱ _ _q_o@ _o@ _Xƀ _^8 _p _ _vH! _W _W _a0 _0 _  ^Ѱ ^y( ^E( ^QP ^0 ]* ]- ] ]wX ] ]M( ] ]O@ ]*( ] ]  ][8 ] ]iH ] ^` ] ]k ]vH ]`> ]4 ](2P ]( ]~` ]Hx ]F  ]pP ] ]0Ԑ ]k@ ]8 ]k ]Qp ]~` ]`P ]  ] ^2` ^H ^mpo ^ fh ^C@] ^.(S ^NQP ^S$ ^$ ^ ^`' ^ ^$ ^> ^(' ^ ` ^` ^P _ ^0`!`: `!`: `P@F `B0T `YA `jT `? a8H: a*8`p ` ` `sh@ `@ `P a  a@ a|@] ay aHm au8 `ڈ aP a b:r b8 b b( bP b@ b b b~ bX b c; bc chs c-W ce c c( c} c cEH@ cf@ cSXP cf ch- cG- ch4 cWH cP b b` bm b@x b" a88 aH a aY `@ `8ڈ `p `D `ڈ `@ _@ _Ӏ `- `` `eXj `R a:M a?P6x aX a 6x `p `!` ` ` ` `zp8 `* `P `1 ` ` _ `0 `h `Xx `a0 `eXs `I8h8 `$@ a.2P a#0 a` $@ a, aR a1@ aTh` a' a a` `} aL a8H<8 `<8 `Z `uE `xfh `8L `4 mp `N `!`G `WH `-p `1 `j `6x `/p( `# `P `@İ _( `* _ _˸ _ظP _ _İ _àİ _Ѱ _ _X~` _8pP _iH __ _Q `J _8J `:h _iH _hT0 _ѰM( _sHx _8? _ 1 _0 _ظ _8 _p _H 0 _x _@ _ _X _0 _ظՠ _ǐ _0 _ʨ _ʨ ` _` ` _ _8H _xp `(hs0 ` e `!`:uؠ uؠ u u=h u^=h u b usP tY t- t`!H th ux uؠ~#0 ~#0 ~x# ~p#Fx ~#0`-C `-C 0- H.  .- .` - P- X-p -0 , ,H q, , Sh, C,Tp , p @, ,. , , )8,?X ,*@ ,= و,F` ,[x , - @ - , P, `-C(0 (0 h0 H0p P0 (0p% p% t%& %5 % 0% H%0 8% (#8 #8 # # #ɸ X# $5 $x Sp% @%h 0H%c "8%0P % $ˈ ҈$ $w( X # #81 1 l`Y TTP I8?8 T,x * = 4 8  8 ظ h @ W LX 7 4' (h 3 Ig -d 8C 8g 7wx & Uxn a08 z~ xd Wd Z(?8 h85 n  0 h` c0 c x ( o@ .H Z( 0 j E S C` 0  @   0 h C` )  5P 1РH РH  ( . V x . O y hr ] ] @5 # X eX  @@ θ :ǰ ?P  ר0 Рg` g` @` @" xQ  Ո  @5 k ~X@ YPk M{h V @ D8 ` # @F #  0 h Pؠ  x#  R N I &Hn =h /1 8% F ϐp ve@ $xp SX^8 $xW0 B pb `[ * (` h   t @h %@ @( H(u 7^8 @lH T ^8 rp Hp r *8  x h X  8   j q ? θ ` à( Xh h   XX % pX 'Xʐ 5hp H(X ph @ 8  H@H P Gx U0 ` )(h 28 >@@H  # u{h X ̰`  XX "  8x #h , D8 i` up 30 H g`8ox 8ox TP ٰ6 6 .K _HPx 9 X e 0 H   Ӹ fP (p ( i  P RH3 1x P : pz RH0 |x  ̰X `X : H 00 `   l  l K  P {0 ܐqvq$ vq$ v^X$HH v8$L v- # u`"̘ u"p uGp"? uU"? uB"&0 uS("# t`! t8!x t!S@ t`!- tƈ tH!0 u! u!!h u"4@ u" u!8 u!W v!4u8 : u8 : ue V u O tH d0 t S t8 a t S t A tX Xx ty0 S tS > td  t A tfp  s  s 8 s + s 0 s0  sx " su C` s H sV E r r| ]( r6H Z r, E r Qp q ) q ( pȨ " p8 xp8 x p8 x p o oh( o` oH0 o XV nhV n, m` mH  m k8 m0 m@ ͨ mD ͨ l X lj ]( k )V YS)V Yp)d Y) YX) Y) Y) Y)ƈ Y)P Y҈)ƈ Y҈)۠ Yp) Y ) Y0) Y)Y) Y) Y* Y@*@ ZU* Zx* Y* Y*& Y*0 Yx* Y`* YP*@ Y*GpY*E Y*E Y*s Y* Y *j Yp*{ Y* Z(*q ZJ* ZX *h@ Zm8*c ZJ* Z(* Yx* Y* Y*8Y*8 Y*8 Y8*P Z * Y*ʰ Z*( Z@*h Z)@*p Z0*@ Z2*( Z0H* Zf0*p Z *p Z*0 Z* Z* Zf0*( ZU+ Zh+H Zc+ Z* ZP+ Z+ ZX+ P Zt@+XZ\+6 Z\+6 Z{H+- Zf0+;0 Zq+R Z+D ZP+e` Z+D Z+j Z+lhZ+lh Z+lh Zx+0 Z+` Z+` ZȠ+j Z+| ZH+ Zְ+( ZP+ Zp+u Z+ Zh+` Zx+ [+ڐ [+ [/+ [&`+P [G0, [\H+ [R, [l,x [W,8P [ ,A [ ,V [0,Mh [,d [H,d [0,y[0,y [0,y [, [, [,h [H,˜ [H, [X,8 [,( [ , [, [X,װ [, [, [, [,0 [(- [-P [-5p \`-) \`-J \/8-C \-X \p-a \-a \-\P-@ \P-@ \- \-@ \p- ]3`. ]. ^ / ^ / ^ / _(. `!`.` _x.` _.P `(h.` `.P `=. `P@. `M.P `(. ` .{8 `Ӏ. `. `. ap. a%.} a.P aO. a?P.h a. a,.ha,.h a,.h a`. a.֠ b.`.h b.Zh c .B c>@.G c00.& b.p c)(.x cB.G chp.@ c@.pc@.p c@.p cȈ.c0. c0. d`-d^- d^- dH- d- d0- d- eK@- e.G ex.2 e.EP e.\ e΀.LX e(.Zh eH._ e._ e.t0 e.f e.{8 e΀. e0. e. eՈ. e@.8 f/ f7/( f:P/@ fM/ fM.p f[ / fOh/ f~H/ fy.p f/ f/( f`.` f/ f / f.Ȑ f / f/ 0 f0. f/ fҨ. f@.H f.p f.` g8.P g. g.p go.h gy. g_H.x gx.P g.@g. g. g. gH. g.֠ g. g. gp// g/;h h/K h /;h h/-X h$(/;h h;/+ h(/D h=/D h;/W h&/W hx/W h+0/v hD/s h-/` hZ/ hD0%hD0% hD0% hD0b h(0 h9@0@ h&0 hX0 h$(0 h60 hB0hB0 hB0 h!0 h&1. h1 h 1 gP1%@ hp1Hh hcp1Vx h=1] hD1m hX1Vx hX1< g1Vx gP1x g 1x g1X g1 gH1P g2' g27x h2' g2L h!2S g2S g2 gH2th h2v h 2 g2v h(2h hNX2 hq2( ha2 h42 i3i3 i3 iW03 izX41izX41 izX41 ih4/` izX44 i 4n i 4i 4 i 4 iH4 i848 jh4@jh4@ jh4@ i(4 i5< i05k j:6 ( j:6<` j6m j`6O jH6m jO7& jpp7N ju 7 jF@8N i8u i@8` i8P i9( i9 ix: iR:" iW0:iW0: iW0: i[;_8 iǰ;0 jh< j<8 jЈ>%`jЈ>%` jЈ>%` j> k?2 kp?X k0?` k)@ kH@q kX@p kxA#kxA# kxA# lXAj l^B8 lB0 lC]P lրCrh lCyp lpC l(C lC mCP lHD4 mDN mD+ m;HD2 m6DSh m`DU mx8DX mzDt8 mDX n#PD_ n DSh o XD+ oHHD o D- oD( pD9 pD pD"0 qC qsCX r3C sB׸ s]Bx tpA thA t@0t@0 t@0 t?8 t? t ?( t? tX?@ u?V v!h>P v`>P ve`> vI@>8 vq> v^X= vg= vc= v`= vT= vR=P vI@= v?=T v= v*< u< u< uH9X yG9 y29 yQ9p yJ9Y@ y29p yB9H y$98p y49#X y$8 y-8 y8 y48s y 8N y)08@ y8-@ yx7 y 7 y)07 y7t y087c yx7ZP y47N yp72xyp72x yp72x y7 x7X xـ7@ x(7 x6( x6 x`6h x6( xH6~ x6V( x6V( xp67 xt6 x(5x xp5x xyh5u( x85H x: 4 x.h4 xi4xi4 xi4 x(3 x3 x83p x3p x3 x3h( x 3E x3; x3 xH2 y22 yQ2P y_2 yS`2 y_28 yc2} yhx2 y2 y2Zyx2Z yx2Z y2 y1 y1 z 1 zX1 {z(0~ |'0 }7x. }(.h ~=-0 ~@P- ~h(,x ~,D ~P+x + ~+P + ~+ ~+ ~+6  8*0 ~* ~cx+ }+B8 }(+8 }Q@+R | +K |d+ |p+u {+h {3+ z8+( zX+/x z8+z8+ z8+ z + P z;h+` z* z@* z*vPz*vP z*vP z`*Z0 zv*j z`*a8 z=*+P z&P*- z) z) y8) y})fp yEP)] y"()0 x)7 x8) x( x( xh)p x)'( x(8 xr`( xV@(H x'Pvq$ vq$ v$P v%p w%%U w%%h wY % wF`% w=%p wR&( wp'x wp'* w޸'n x'Pz=s@ z=s@ zŰ=Yx z=% z8= {H9 }@9z }X9u` }P9[ } 9?x }5 9D( }29, }@96 }C09F }@9P }0p8 }<(8ڰ }S8 }fX98 }o8 }8` }x8 }8Ө }8 }p8z }8D }p8D }8( }8 ~`8&8 }8( ~ 88 ~&8x@ ~;8x@ ~P8 ~z9x ~9( ~x:5 ~\p:' ~I9 ~$09 ~-:> ~E:X ~2@:` ~B: ~:( ~ h:` ~ h;h } z >p` z>bP z= z0= z=s@"@ "@ "sO"sO "sO "?X !X !ր( ! !q !7 h 8 sP # } }p  HU` h6  Hx H h @ۀ ( p .H(  hx {h P ɀx Xy P H [X O TPo g 0 @  7    P 8^8^ 8^ ux p( 8h xx l 8n ϐ pox X x   80`    X@ p h (    8  8 5h ^8 `x A d@ r  P n

hZ 9 5  + @    ` X ΀ H0 iX (` nh b 8h V` b  lp 1xT0 T0 *p:h 05   ̰h ph Θ zΘ xP0 `   g s~ U(X = eKX /w ^ (!( @ j  j w t(P v`p 78^ EH? " !( N $x h *    !( !( 3 =H =H e 0W i e u e H(? a6@   ` D A} ] ]0  ?Ps  -( F} 6xh  zjX Xv ƀs ^ C@P o I 9  !  @ QP  J T0 ph r` %P   Θ` @  ( H  ~ݸ [ ~ e  1 T @ 6@ `p Yh! s0 w! 3;x T/ s0;x H&` 2 ^R W` we ~e 8x s  jX `   p   v   Ph \H 9  4p X (@  ݸ X c߈ h p  8  q D  Bp 8 q` 8  zP 6 +  X Zx &R R xo x     8  [ mp OH "H .x H  /8 :0P l( 7l( `H Hw 8  p b TH *P   " %P @Ap ep5 `V X] &(k (m X H Xp ( @ `8 p P( H L0˸ ; 2h0 "X x   h L )P + ]  0( 8 + 7 @+ +  @ 2 5+ O@ 'V *)x  ` Z 0 p  +H  j -j - j - r B  hP { (   X ah  8   / c X G p - , - H ) 8 P  " K@ )    H  p X p   (  9p ^ >  q  aH  j  x  }h  ̰ x 8 %    #h hP ` { 1x hP ? v`  P 8 G  Z@  G  \ x 7  U  2h 8 \  ; H v`  W C &  0 p H  ) _H  x   Ԩ t` Ƙ  x  > p \ * I ߨ N % E(  ) P( $X   i @  u h | " P &  W  N TP  ) P ԰ S8 "H #H " #1` # $OP ݀ $> #` # #8 h #i # # 1 $ D %h BH % 8 &h  &@ = & = '( q( ', IP 'I q( ' x0 'h X '8 H 'B X 'l0 x 'x ' 0 '8 ' '  ( ( '` ' ? '8  'h  'x  (:p  (O (iP (d ( ( (x (X  (X (5 ( ( @ 'p '@ P 'M 'M 'M '( @ '[ ` ( (@ ( ( )+ )@ )k )y0  )  * P *  * BH + BH + * , ? , 1 ,x  ,8  - ? -{ K -w  -7 h -8 !x - -0 , !x ,8  ,޸ P ,x 0 -.h 0 - X h -p - 8 - h .2 . ;@ - U . ep .X 8 .J lx .hx q( .; .t0 @ .@ .f .- h .+ . h - .>H .U . .  .o IP .LX ;@ .o ` . ` / /`  /Y  /2 8 /2 . H .` /= t / t / \ /z I /` \ /U0 q / \ /p E( / 0 E( . ) .Ȑ 9p .B " -ـ .X .B . .>H .  - -0 H .x 5H .f H .{8 '8 .2 ( . . H . @ . h /(  /!  /g h / A /Ű 0? x 0  0  0 x 0`` ( / & / +` 0/( +` 0s E( 0ǀ - 0H B 1F I 1 I 0h e 0X W 13P 1 x 1M 1 X 1p 1X e 2 hP 20 2 ݀ 2 2m` 0 2Q@ 2d 1 2 | 2x 3 8 3 8 32@ g 3Z q( 3Z BH 3Ѡ 4M 4 ( 4K ( 4q 3 c 3߰ @ 4& P 4 & 5 0 5k 7 5H B 5p > 5p P 5 hP 63 oX 58 6+ 6<` 5 ( 5 5y 5 5ט 50 # 6> ` 6 ` 5ט  5( 8 5` 4X 4Ǹ 4@ ̐ 4p  4b 4  4lP p 4 40 8 4sX 4p  4 3h 36 3I x 3x 8 3p *P 3Uh ] 2  2x h 2P b 2N b 1 8` 1p@ 6 1 H 0P 6 0H K 0 : 1t Mx 1 3p 3 2.x 2"`L 1`0 10OH 1OH 1C 1% 1p@3( 1Q 1JH@ 1tb 1[({ 00 /]X /\8.x /nX /]X 0Ap 0`8 0wp 0 1( 10ˀ 0hX 0 0gh 0O 0H 0 "8 /(0H 0Lh /8- /G /Lh /Sp /c /\ /0q /sh /8 /@ /-X /@ .-h .@4p .D . .X( . X .H /(/8 /!# /P /P / 0u /&P(0 /@* /XYh 0h /. 03@ 0 2P8 2pP 2h@ 3p 4 3<8 4/` 4p 4' 40 5MP 5O+ 50 5$ 5 N 5P 5€H 5+H 5W 6 5 6$ 6x 68 6_g 6@= 7"j 7L@8 7X[ 74 7L@ 70R 7(h 7vp 7π 7p 78vH 7c 7}xP 70- 7j 7p 7fX 70H 7h`͈ 7}x( 7SH 7t 7E8` 72xtx 7Pk 750 8x 8 8 8H 7=H 7  7  84H 8x 8( 8g 8I` 8j0 8Wpx 8zs 8;Pq` 8\ h 8*@( 8Y-h 80! 8K 7 81 8# 8R 8X 72 8R 9T9 9/Lh 94 9(Lh 9 >X :f :>X :Q :x ;G ;G ;)Pp ;Z ;p ;c0 ; ;mH ; <h M >HP >iXx >=H >gx >DP >0(0 >`x >p > > >X >H >h >x >߈ >0h ?.8x >H >ވ@ > ?.8 ? ( ?CPG0 ?W ?cP ?E} ?h ?o ?s ?h} ? ?8 ? ?P ? ? ? x ?X ?Ԡ ?( ? @8߈ @(P ?x @- @- @x @S0# @P? @0KX ?i @R` @-`p @hP @S0u @u @@X @ z8 @P @t` @ @( @hP @( @h @8 A* A-(' @< AV @Hx @Hx @p? @ʸ8 @h8 @xV @HV Ab@ @m A Xh @hp A-( A8 A=8 A@ AM AX Aeh A A0 A` A ˸ A8 A Ax A AH"p A9 AӐ A A7 B x A)x B:' A`] B`0 BA> Br$ BN C_tx C.p CVH8 C:( B Bh B'x Bа B0 Br A@ A@ Aq  AjX A Ah! Ah- Aژ- Ah Bk B͈ C" Bɨ B CS C{ Cx CC CdX C]P0 C C C`` Dp C D>P9X DNp D9j Dl D@ C0` D@p D; D` DShH C1 BI8 BWH Bwj BuH Bn@| A@ @H A X8 @8 @lx @0ڈ ?vx ?vx >H( >8 >]Ӏ >]@ = =V =u` =[i =M~ =Fk <p F0u8 >` ?PP ?h ?k( ?0 ? ?L ?@ >P >'@ > >H( ?$'X ?Xh7 ?0w >P( ?H( ?9P ?Sh ?V ?o ? ?p)( ?ۨB @$PG @HSX @tLP @hHah @ ah @x; @(X AX A=q A Ac @X Ah @\ @0 ? ?x ? ? ? ? ?P ?0 ?X@ ?d / ?CP^ ?'0n ? ` >e >@ >0 > >` >qH >Y > >X >x ( > >֘ >hP ?{ ?t@ ?` ?hx ?h @ ?5@ ?LP ?; ?oLP ?O ?h@ ?Oah > > > >@v > @ >8 >bP >  >X =X=X =X > x = >Pϐ = =H =0 =x = ( =~ =l8 =Kh ( =D`p ==X! =( =% ( = <Bh <Bh <(;` <D <Y <Bh ( 08!) 0! 0i!X 0np! 0:!P 0T!+h 0/(!7 /! /U0! /Y /\8 /\8 /D! /R!" .!N .!2p .@!4 .H! .0!$` .!X .!N .!f .`!{ .}! .LX! .! .&!X . !P -H!X -! -! -! -(! -@! -!8 -P!( -H! -!@ -!X -~! -" -" -{"( -O8"! -t"8 -_"l -,"Y -: "q0 -,"s -]H"u -H0"` -H0" -t#*X - #,O3 @ O3 @ OYH O/  O 0 O8 h OP ( O0 p OP O ڠ P  P P7 ň P7 Pt Pb Pk n P j P BH Q9 * QL  Q 8 QC Q  QL @ Q Qv  Q  R+( ` Q @ Ra X R; Rh Rx ( Rx Rؘ S| x Sx S( T Tx }h U 0 x Uh c UZ e UJ` L0 Up N UH 4 U` ; U  V  V  V>  V4  V V h U U 0 T U Tn ` T X Sΰ  S, p TX TQ ST 0 R@ @ Si p S SDh t S t S ] SP y@ TTH t T Xp TH J` T ) S ) S=` " S  S=` S* Ѐ T%h " T]  T $ U( E UXp > U(  V Vt 8 V V Vp Ƙ W VP X V W v V t VH f V h V _x W CX V '8 V L V + V  Vv` 0 V  V2h  V@x  Vp P UH UԨ  U_x U  T T׈ T׈ UZ U9 ~x T0 n TV Tk | T* ~x T` wp Sո k T u U p ` U J TX : S F8 S ` S C T3x C TbX 5 SX X T 3x UO P T Uo U V^  V VhP H U0 U(  V 3x W  W X W(h V@ V8 V V V Vx Vh VXw VP Wp X0 Xr X=i X w WIPn Wb W4 VDh V% V@? WX* W V W  Vߠ W0 WӘ Wh(H XA Wx Vp W  X W` WN WX WF VH WXs Vpqx Vl VHh VXW Vch V ; WUX Wu; V@4 Wu6 WY&x XI X+( X XuP8 X6P X08 Wx0 WPX W Wc` WX XFp XK P Wj ( W48ȸ V@x Wp V Wep@ Wp< W=$ WH W X?h Xd X  W X XO Xh YJw8 XHp0 W  Wp0 X0Vh Yyx]p Z7 X0 W" Wz7 W48. WH( X8' Y h Z ZϨX [+ \3@ Zn` YCw YX X X/ W W` Uo3@ V VYH Ub U0 S S@P TXx Ue Re P P P|p RsV QhH Uk0H V6 W* V8x U( U TP0 UEڸ U Se8X RchŠ Q} Pth PC Op Ob OR@p Q0Ӱ P~@H TXH T  Sո S* RGH P PC O N@` N N4P N M8p M@ NH M@ Ng` Mc` M M4h Kk J@ KRP I߸Š K  JP Ih̨ I; I Ix Kx L@ L1p L  K! Kˆ I0 Jp6 KF J^H=( J[( G`X F8! Gp F@n` G| Ep`P EjP EsT Dx1p DU=( DO D+? B8V B6gX C8 A@n` A( AWX8 @܈ @c ?܈ =ΨO` > w8 ?9t ?`[ ?i( ?"{ ?E >` =Ψ AX > >A >~p =H8  >g _x =pP > @ >] >  >@ >h >P ?d  ?H ? @8}0 @c @ Asx A AHh AHh B x BY(À Bn@ Bؘ B B ( B B6X C0I Cl@ D`| C D C C( CdX D ( C D$ DU D$ D8 Dh # Dh 3x DG M@ DȘ V D` ph D u D u D E H DQ D֨ DU D E D D  D+  D} 9 D + D@ > EBx 0 E( p EU8  EBx  E X E= Es  EK E  E @ E8 p F8 ( F  EŸ 5H Fh + F* > F Z F8

X G< GLh GN GpQ G@U G a Gp_( GE` GU H PX Gj G} Go GҸX Hc GX HH Gh H0x G˰ G HQH H> Ha G HS H)pP HXPϨ HG` H@ Hvh HPX Hp HJ@ H Ha H H I x I$8 @ I Ich Iz Iqh Ixh IX I@ IѨ` I I I߸ Ih J  IP @ I}H I Ix J80 IXP I( IѨX Iذ9 I J I4p JX J = J[ J @h Js`2 Jq` J?xh J; e JW@l J`} JK JD JcP K3l K\H K5W KhG0 K*0B J@P K;x J;x J! J-h J0 K%9 K-h KY+ K,&` Kd K  K`H J K` @ J KC Kk J` Ku0 K'Ϩ Kp Kx@ Ku0H K K5 K KX KT`P K K Kxt@ Ka Kh K7P KC K+ K K, Kkh KH Ky K@ K KhP L(8 K@҈ K K0 K L KP@ K LJx L L: L H0 LJx L30 LQ LX L~8 Lhyx L(i L[ Lrp LrPOH L7 L]8< L 0" L LJx 8 L H L L L L 0 M x M ` L uP MH uP M` [ M9 p ME@ p MB R( Mj nH M k MH Y0 M b M K M , N 8` N 0 N* M N Ns N ?h Nq@ O N % N Fp N #H Np : N / O 8` O3 @- #, - #, -E# -%$_ -.h$rx -3$dh -0$ -% -5p%_0 -kX%p -]H% -S%0 -dP% -)%N -p& -8& -P&р .G' .-' .7@'(8 ._'* .X'* .Ϙ'DX . 'w /Y'g /z'T /xX'Rh /'^ /'P /8': /@'P /'6H 0', 0``', 0i': 0O'? 0gh'? 0s 'W 0s 'I 0'I 0'/@0' 0' 0'h 0'( 1 &( 1(& 10&xp 1,H&+ 1A`% 1A`%p 1% 2J8%p 2% 3%p 2ۈ% 3%h 3-%0 3;% 20&UH 2Ԁ&8 2(&xp 2`&P 2& 2`& 2ۈ&X 2& 2& 2Ԁ& 2P'Rh 2's8 2 'F 2' 2th'* 2_P'I2a'I 2a'I 2U'b 2}'n 2a' 2r'P 2_P' 2m`(P 2XH(_ 2\(H 2>( 2(P2(P 2(P 20p(p 2E(X 25 ( 2k(2k( 2k( 2( 2Ԁ(ĸ 3q( 3( 3( 3( 44( 4( 4i( 4( 4( 4( 4( 4H) 4Ǹ) 4p) ` 4P( 4)X 4() 4)  4) 5)h 4) 55)255)2 55)2 5)> 5)O 5p)S 5.) 4H* 5* 4* 4H*h@ 4* 4* 4* 4* 4*P 4p* 40* 48+ 4+8 48+q48+q 48+q 4+8 5*(+@ 5,.5,. 5,. 5`,D 5,b 5,b 5,~ 5,X 5,~ 5P,g0 5p,~ 6, 6f, 6,V6,Y 6,Y 7,K7,K 7,K 70 ,' 7,1H 7(,K 8,] 8I`, 8`,(8(-w 8(-w 7-8 7,0 7ݐ, 7, 8-@, 8h, 7X, 7,Ш 7,X 7H,@ 70,Ш 7π, 7,` 7, 7,p 7oh, 7}x,i 7j, 70 ,70 , 70 , 7&,7&, 7&, 7, 7,8 6, 68- 6-O8 6-t 6k@-t 6Z-P 6Ch-P 6Ch-C 6-5p 5h,x 5x, 5x,` 5bh,h 5V-5V- 5V- 53, 510,0 5,( 5 ,@ 5 ,װ 4,8 4, 4,y 4,= 4eH,. 4T+ 4+( 4+P 4B , 4,1H 3(, p 3Ѡ, 3+ 3P+H 3Ѡ+0 3+u 3ʘ+q 3H+\3H+\ 3H+\ 3\p* 34* 2*Z0 2*@h 2@*P2*Nx 2*Nx 2x*& 2* 2* 2X* 2*02*0 2*0 2*$H 2*7 2$*& 2J8*4 2*+P 1Ұ*( 1* 1b0)1b0) 1b0) 1) 0) 03)r(/)'( /)'( 03)r( /0)p /G (@ /K( / 0(| /(( /Bp(@ .( .(y .(iP .( .(p .H( .(x .v( -(x -{( -)( ,0( ,(y ,p(X ,0(C +^X' *'X *s' *('^ )0' )2&( (&x (&; )&$ )X& (& )% )% (% (x%\ (% (k$ (%X$T ' #H 'P$` '# '`#0 'X#0 'X#P '#h '^ # 'z@#P 'w# '# '# 'Yp# '!0#~ '!0#gH &#i '#D &#b &8#T &H#gH & #[ &؈#O &p#Fx &##P &8" &" &#( &8" &"0 &" &" &xp"P &+"q0 &"? &+"! %"&0 %" %0! %! %a! %o!@ %C! %>`!W %$!S@ $!8 $  $(  $( H $w( : $t " $E $> " $% 8 #H # x # S # t #0 $ ! $f!P $! $! $x! $! $! $! $"6 %)H"P` %<"@ %a"P %U"` %o"@ %"Ӡ %o"p %"X %#Fx &#° &$ X &I$'x &@0$0 &UH$ &xp$:8 &$:8 &H$p & $ &$ &z$ &cX$ &G8$~0 %$ %#8 %v# %Z# %_0# %Lp# %Lp# %Q #O %"@# $"8 $ " $" $"x $y" $A@" #"` #H"4@ #"! $"( $h"4@ $E"6 $"! $,(" $." h $7! #!L8 #R0!P #?p Ơ ##P 8 # " m " Jh "  "Ӡ "x@ "?O ?O= 'W = 'W > @'DX >('Yp >׀'l0 >'X > ' ='` = 'W;tP& ;tP& ;`& ; &} ` 4%x 5'$ 5А$ 6$ 68$ 6O $h 6:$x 6Jp$0 6@$@ 7 $ 7$ 7$ 7L@%"@ 7P%$ 8%N 8(%m@ 8#%_0 8*%v 8U%x 8c(% 8=%j 8j0%} 8% 8`% 8n%( 8% 8% 8p% 8Ө%H 8%X 8p% 9V% 9D(% 9`H& 9A& 9F&P 9& :X&K :'&Y 9p&l 98&( 9&l 9|h&( 9@&v 84H& 8R&^ 8&@0 8x@& 7& 7p%p 7% 7%` 6P%h 6%@ 6%U 6rH%U 6S%Lp 6H%2 6Ch%Sx 6>%Eh 5%@ 5%"@ 6x% 5$h 5g$h 5%>` 4Ǹ%C 4P%f8 4|%{P 4u%c 4I(%tH 4;%f88(-w 8(-w 84H- 84H- 8I`- 8e- 8Ph. 8q8.J 8G.j 8\ .q 8q8. 8^x/ 8s/ 8Wp/# 8Wp/;h 8`/Ix 8n// 8x@/9 8q8/U0 8/Ix 8x@/` 8/l 8g/} 8g/ 8R/ 81/X 8=/ 8!/0 8*0 7ֈ0 7x0 70 70: 70w 7(0w 7t0 70;* ;* ;ϸ*ʰ ;* ;p*x ;*( ;f@*0 ;X0* ;Z*è ;X0*@ ;<* ;0X*( :+;0 :%(+4( :X+ 9+ 9+u :h+e` 9`+R 9b+P 9d+ 9H+ 9b+8 9H,0 9Y@, 9T,?X 9H,O 8x, 8h, 80, 8- 8- 8, 8`,70 70 7}x08 7t0( 7;0@ 7"0 7$h0 70 6 0 6 1f 601 61P 61P 6x1 6m2 62+ 6v2Q@ 6`2 6X2@ 6_2 6m2 6X2 6ƨ2 6(2` 62x 62x 6 2ۈ 620 7@2 62 7P2 7@2 72 632@ 63I63I 63I 6:3 604 6V(41 6E4K 6t4 6m4 6L4 6H4 65' 795h 76'H 76{ 76 84H7q 887P 8x@7 8z8 88= 98P 89 89 89 8(98p 9@9A 9*`9~ 990 :dp:[ ;: ;C:8 ;: ;8;)P <4;<4; <4; <;;  <6> <> <>X <6>g <>@ <-x?] <?` <? ;@E ;@^ ;@ ;p@ ;ȰA ;xAY ;HA ;B ;B( ;{XBA ; C ` ;C_ ;pC8 ;vC ;`C ;Q(D2 ;5D0 :D( ;xE :E4h :8E0 :E :Ex :E :tEx :fE@ :i F* :FW :~8F :F :G] :bGf :<HH :THE :H> :]hH_X :~8Hf` : H_X :H9 ;HU ;)PH+ ;)PHQH :HHv ;H} ;H : HH :H ;H0 :H0 :`I :ҘI :xIL :Ie :Iv@ :I :ĈI :xI :I :I :I ;xI : I :`J :J& :J=x :JP8 :PJb :hJR :~8Jg :tJ :J :i JP :fJ :J :_K ::@KX :[J0 :JJ :7Jx :OXJ8 :0J :38J 9J ::@Jh :38J :"J :"J 9J 9J 9܀J8 9Jx 9J 9Jx 9J8 9K0K 9gPK: 9|hK. 9pKp 9Y@Kp 9J 9HKx 9K3 9PK. 9K% 9K% 9K% :'K*0 :'K?H :CKFP :>Kd :'Kd :,0Kr :"K` : `Kd 9@K~ :5KX :K :K : xK 9HK : K 9K 9 Kh :CK( :XKh :bK :_Kh :hK@ :mK0 :kxK :K :`K :yKh :[K : K :K 9K 9KИ 9K :K :.K :pKx :HPL :<L" : L8 :L$ :38L5` 9PL> 9L :pL :"L : xLyX :ELZ :5Lf :OXL :38L` :,0L :)L :fL :.L : `LH :0LX : L` :0L :HPL :JL8 :L( :MM : M : L8 9M :M :hM :hM$p :7M :)M$p :JM4 :M+x :38M\ :w0M :bM70 :@ME@ :XMG :V`Mop :EMa` :Mj : M{( :0Mm :.M@ :7M0 :HPMH :dpM :rM :HPM :HPM :bM0 :dpMH :@M8 :rMݘ :N :kxMP :yN :XN0 :N :Mψ :N x :ҘM :M :MH :M ;MH :M :`Mp :(M ;MH :M ;N ;(NB` :@N@ ;N8 :XM :HN :N :٠N&@ :(N! :8N :XN8 :_Np :ND :fNg :NN :`N^ :N= :HNIh :NIh :Nn :w0Nq@ :NP :N` :Np :N` :ĈNu :N\( :8Nc0 :NG ;NG ;(NR ;N\( ;CNIh ;NY ;<NY ;Nz :Nz :Nc0 :8NxH :@Np :N :N :hN0 ;Nڸ ;N` :N ;N ;9N( ;(N ;X0N ;Ng ;ϸNxH ;@Np ;vN ;oN ;SN` ;qN̨ ;hN ;@NH ;@NH ;CN ;8NŠ ;CNx ;HO ;xN0 ;xN ;8Ne <NK L'P >PKP >Kɐ >K >iXK >Kp >Kw >PKO >:xKFP =hK =J >JK >T@JD > J# >׀J* >I0 ? Iʠ >XIj ?7I/ ?PI ?+H ?0H@ ?y8H ?H@ ?H ?HX ?H8 ?ۨH8 ?HP ? HX ?Hp ?y8H ?d Hp ?vH ?)H ? G ?5@G ?Q`Gh ?Fb CLF8 CEP C`EcH CEcH CZE2 CwD֨ BD\ BDEX BXD7H B@Cو BPC B(C B CCB CC B CC B8C BаC BPD CDc C(Dc CDh DGDP D(D ED E 8Dm0 ED} EIDZp ECXEC EC EC FDHC FDHC F,C H F=@B F,B( FDHBP FPBа FTB FXBX FBFh F B[ F B1P FB FB x FAX FB' GB GB*H G B G BY( FBi FB` F0BX FxB@ FeB FDHB FFC FBp GhA HA HA HXA H)p@ H+@hH H>@\ H+@U H0x@& H. ?p H? H? H"h?ۨ H. ? H2? H? H7?h HN?} H ?r0 H?] H>?o HE?O HU?_p Ho?Q` Ha?m Hr?] H?9 H}?.8 Ie> Ie> Iq> IX> I(>~p I> I>iX J6p>A Jn>< JY>< JR># Jzh> @ J8> J(> @ J@> J> K*0> @ K =x K5= K<>H Kɐ> K= KИ=հ K=8 L_= LQ=B L_=0 L{2)h H<02> HS2> H>2E HG2Z H. 2> G@2k G@2k G2{p G2 G2 G2 GH2k G2v G2 G~X2{p G2 GpH2r G.28 Gx2k Fh2 F2 F1( F32\ F*2E E82Q@ F/02. FY`2+ F[2P F1@ Fx1 F1{ Fp1Vx Gy00 Gm0 G'0p G 0D@ Fp0O G (060 FH/ F/K F/n F/4` F/ F/G F/ F|/9F|/9 F|/9 Fl .` FY`.` FKP/ FW/( FM.ݨ F1. F! . F((. E.q EG(.B EP.EP. EP. E4h.>H D.$ D`.- D.9 D.>H Dt8.)0 D2.+ D+.S` D(.>H C.$ Cm.m(Cm.m( Cm.m( Ct.h CH8- C-X B׸- B(- BH-dP Bg8- B(,Ш A,@AX,@ AX,@ Ap,0 A`,@ A`,@ AU, AY, A, A?, Aeh,g0 AR,p A|,Tp Asx,A A/,% A, A ,x @, p @@,*@ @,( @0, @P+ @h, @P, @H,% @H+ @8,0 @x+` @+0 @a@+X @B+ @{+ @c+ @E +̀ @E + @\+ @Z8+X @E + @P+ @+ @+ ?+@ ?+X ?`+ ?`+` ?+ ?t+0 ?Q`+ ? (+P >+ӈ >+( >+ >8+ >~p+ =+ =n+ =[+ =e0+u =Rp+q =`+q =M+I@ =x+& @C D hDx y`DX DP xD tD` ]@Dp Dq "D\ O0Dt8 %D C XC C C C |@Ci hC_ CC bxCL ]C" AC %C C `B0 xC@ B Bа ͈B` `C.p C0 C C@ D( sD  xD( hD PD hD D @D4 8DU bDm0 0Dc 0D D D( D 8D8 wD8 ]D ڠD D D` gDax DSh XC `C BHC nC ^hCb gCQ nCp uCZ sB0 B3 Az @x @oP 8?͘ ? P?͘ "? $X? 0?͘ 7? P@ j?x hP?X @x? +`? 7?r0 W? W? j? ?p ?@ ? {?} &>8 +`> +`> 0> ^>T@ e> N=X p=l8 =i = =H ø= =g PX=; =h < < :< R(<ш < ɰX >[H ɀ>r >g (> O>` v> ? ?CP h?V ?` x? ? ? x@q @X )@ BA? XA xBMp B C H CE yHCi XxCdX SCp vCp .Y5 >%`X0 =X =X =0X8` =MWh =W Wx =W =iW| =hW ><WW` =PW= >W6 =W =0V >M8V =xVh >.V >:xV > VH > V >bPV =V =ΨVE( >V0 >%`VE( >bPVm >dVG >XV8 > U >pU@ ?pU@ ?U( ?5@U ?vU( ?ZU ?U ?@U{ ?Uo ?XUk0 ?xUa ?U) @&U9 @@pU) @+XU @NU @U @{U @xTH @U @T AT A(xT AUT( A`T AT BTwp BHT BXTg BXTV CiT* CTX CTg C]PTM@ B8Ti` BXT BT@ B8XT B1PT@ BT( A8T@ AYU$ APUE @pU> @Ua @HUo @ðUt @xU @U A-(U A1U AUU A^`Up AU AlpUP AKU` A& U AUԨ @U @ʸU͠ @cUP @Up @{V @-U۰ ?U ?Uh ?ԠV ?V ?`VH ?ۨV0 ?EV4 ?ZVS8 ?LVj >8Vv` >(V ?V >(VX >V >V݀ ?0V ?LV( >VH ?0W ? hW!x ?W8 ?W48 ?XW ?HW ` @NW ` ?@W* @&W? ?XWW` @HW^h @(Wu @>Wx0 @0W @}`W @W @X @X' A*X3 @Xd A8Xb A#Xw AehX AehX0 A`X@ A0X @X @ X A@X AYY AY) A`Y0 AHY5 A!pY< AY[ AXY[ AHY B Y{ BY A`Y AY AHYp AzYX AlpYh @ Y AY @Y AY AYِ AgYP AgZx @8Z AYZ"8 AZ@ AZJ AKZa @@ZU @ZX @Z @HZm8 @;Z ?(Z @9hZ ?vZϨ @4ZX >[ >0[X ^G B^p B_ D^` G ^r H^_` K.^fh L^"p Ox] R(] Rh]f R ]" Rp\p OF\ O \P O[\H O?\T O\W O(\3 Q_@[@ Q[h Q[ R[h Si[p SsH[P Sո[` TH[K Sh[D S8[4p T[4p VøZp XAZְ XrZ@ X0Z YZf0 ZZSp [WZx ZY Z2Z YZ YZ Z YX YY Z(Yh Z{HY Z Y [PY@ Z Ym [Ym \XY \`X \X \^Xx \@XP \X` ]VX ]CXi ]Xi ] XuP ]HX ^GX ^@X ^X _pXp _xXFp _pX`8 _X _hX8 `I8Xx aX a0X b>Xx bkPX b_X¨ bPX` bX cBX duXY0 fX/ g8Wp g@X% gX gW` gWh h8XA ipXK i X jWp kxX( lpWP nOX o X/ sW̐ sW0 tW| u@hWPX u-W/ uW u(W vW w?XW wAW wWp w(W0 x8W xW xpW xXWR yt0Wh zVP zV {RPVh {V@ |OpV |i8Ve |hVq }V( }}V( }Ve }yVW }{pV7 }V& ~UhVP ~VS8 ~VE( ~ÐV" ~xV ~U( lPU( kUh EUx U WU \V `V (V0 VE( VG BXVZ@ YVx 3Vv` V XV V VH VH s@VX #V F0W-0 WR :xWN 0Wg 'W| |W8 (WP bW W IW ;Xx X X0 XR( Xp @Xh  Xx XO ]X ;W8 sxW( WW` W` W8 0Wp >V݀ PV V V Vp V\ G(Vv` VU VP V0 GV XPU0 U( VH V& gU V HU `V@ pU 3U U͠ V0U `V 0(Ux XV B`U 8U` lU` U( UX ӰUH UP UƘ ]UP U bU TUh U U` xUx aU ;V V2h V- @V @U xU +`U U͠ hU HU HU V& pV; ZxV& (U sV@ sV V 6@U VH XU :hU V0 .(V; VB BU HU@ g(U U רU A U U @U V& 8VP 0V> V) VL0 9V@x LVaH V@x PVZ@ HV &V V BV gV !HV 1W W ЈW( WBH WF {W6 ^VH ݈W `W8 PWW` Wlx BPW^h Wlx WU Ws =W\ gHWq( Wj W :8W Wň "@Wڠ W X(X ȨX X pX G8X XA ؈X= X% X3 XH |X: dXO XO JPX eX lX @X` @X` `X IY 0Y3( oHY3( oHYOH Y ͐Yˀ _hY8 7Y XYˀ xY 8Z <Z iZ+ ǘZo ?Zh Zq Z cXZo Z KZ@ ZH ,Z iZݸ bZ aZ z[( [= ^[D 4x[x s[ [X H[ \ F\#  \^ z@\M w\[ |\l( \^ \I X\[ \@ ĸ\ *\ \` K\Θ Eh\ܨ Ā\@ "@] T]T0 ]X OP] ] G] N] ] o]P ˈ]h C] ^ @^ 5^<8 ^L ^ X^h ^p F(^P ^ _( v_ x _7 Ix_ ś_à_Ѱ _Ѱ _p `#"hn0"hn0 PC8(2X/,Z )PP߸)(c0I0*0xH @`!![9^Z@`z yb@hz83H1i0PPPPXppppppP((x K(RBLÈxÈg8xxx"xtHÈPوh(P(P(Pe@e@P7ǰJ:(<`~ 800A0%0@8p%ޘ0 ( 8% >Q +dX >x d0 m ` c `ax `ax `q ( 8Ϡ 0 h!4p!{!Wh!ZH!@|!!! (!8" )" 5!?"pi@"p""p`"-8L"!L"!L"!!X"!P"Nh"nh"nh"n"P!8!P""p "; " 8"/; "/; "/X"!"p! `!p!]!PP!S@!jE!}p8!@P!^!^!vh!0!x!08!!(! ;!ZX!HZX!HZX!Hx!h!!!H"N";H0"IX#"Ӡ#8p##:#=#gH0#]Ȁ#~##ɸvx#t $P$P$)t $J8$.4P$30$E1$w(1$$($@q@$xH%0Y%CP%Sx%tHp%%,%(l%{Pp%pp%pp%px%X%`(%%x%%7X%0%"@%"@%"@,8$y%$%xH$X%0$5$hh$tX$$$$$$٘B$$h%8z%_0%c%tHH%%%Dh%s s s( ;spX +`sn ;r( \r pr pr pr~ 0r 8rH rp r s_ ?rX sn Vs3h bs# xsH 8s# s? sn psbHs<s[@mt9t `0sAxr,+mmn8op @o(o0͈o0͈o0͈p xoPoo@#o@!`o@!`oB0p$xpxp"@oVX5orxoCyoCyoCyo Xרo Xרo XרotHotHotHoPopcph:pqqUHxqq(q(qhqߐCxrM8re( rM" rYpvrps 8{0s,`y y yPyz4`zP@zqPPzPz Xz(z̸5zf{Aw@{~{|x{|x{Ր|<P|p@}"`}Q@}r}N`}m`0}@P}X@}Q8|0|0XpV(kL@hohx@ pNXwNXsxxx#pH\qv xHpKpH000?(0@8Hp`kUNpmX85@h@I@P$PۀhH0Pa@P0PPPPP-(PHN2E\qPUqp8H`.ehuM78FHXV$h̰EXH9h2hX(ݠ0;p`G({0Hhp}hHepPܠHpXr@ wwww n0"hn0"hn0N` UDDh8H,3+@ !P`Kx HPPZXݘHXPl`-֐-009ʨ9ʨ9ʨX@= Ph'X= 1,%XVi`n0p[pP?PH(H0DxPppp?P P_rpxQِ9X0H0sE`+HpXuGh7XLc%PsT0CàdT0(6xFeXx >::0ThKh8``hH0)7)m))Ҡ)8)tX)8))H)H)H)@))84)x)98)e)k H)P`))k )]%"@%"@<%cHX%[%ob %Xr%[%P%8&X%x2%\&7h&4xX8&9(&Y&sv&8Z&0&&&0h''*'`x'p'GH'jp(z(fP(d@((((ĸ ) `)0)])])]@)p)X*I***pUX*p\`+!*8++;04+^X6+0+zxH+cX+zx0+lh+0{`+@+h&B&Bp&R(&=&B!&^@&&x&w&&b'Puh'O's'~''nHX' {'X 'P('`x)X'fH'Pj([@(0ȸ(`(`0( )())"x)58 )r()HxxYPY8|*e@PTgc x(1(HJXppgHIHh ) S _}`  `2` !}ph!_p"pp"8@" |"H"`H"n"_#*X|#R0#Tވ#$$ pH$P0$X$)@$`($`x$El8$EW $bZX!HZX!H\""D;"8"g"""H@" )# #K(P#|`H#(`#HX$T`$A@:$E*0$5,$T,$  $ˈ `$$X%7X%>`%Z%C`%\c `c `!X!f!!{@!0!X"#0"#N0"6W"U"l"Wh"j("^p"U["l`h"X"0" "0 ("P""@X"P`"h@""E"S"07"L"!h"nh"n"H"h;"Ő"p0"0["x"plX"Pzh"sj"Wh; "Wh8"/%f8%f80%Eh% (`$Ґ$H$$0$rx$L$J@#>#(J@#Xh#`v##x##kG#?pQH#"pf`"`r""#̀#p"Ԉ##((#($8#0>#1`;##n#@#P#(#zh$ ^H$`[$,($30$t$($`4$P8$(eP$b$fn$rxp$f$i$t`%\`%\`%\%% % %`ppppp6W(06HDQ`q9h .8ј>@ވuPhF0g   J~0 pRp8 h  :8 Jh JhZ r@B D! !7 <!4!L8!;38!IO!@O!@O!@0!]h!]h"u"u"",0"P#(##8h¸#TX#} 0} 0}C0 }C0 h}P h}+`||_Y|3PTP|?* | {ǰ{P{Hp{p{[|(P|<%|'H|Vx|pÈ{{{xs{Xl{I{9@{|xxlP(:zXVx3xP@![(F@MpM "h 2( fO!@|r!t|r!t{H!{p!f|r!t|r!t{@!@{p!f~#~#~߰#8#n'`n'`^@'8x'(  X(M0{)${)${)L{)}|)_h|5)v|0)h{){ǀ){^)H{RP){:* {M*-{*Iz(*@hz`*x{|{|{~{^{b{*x{O_H{60Z{60P{{FH{``{|x{RP'`{RP'`{'pz'`z'Πz0'`z(#z(Hz`(pX}y!h}y!h}!h|! |r!t|r!t|r!t|P (}7x (v!Nv!Nv`!hXv0!Pwx!@wy w` Ơw@ 0w3 "xL@xwpxwpxwpxـz} `z z zh!-{p!fv(pAv(pAv`Ave`.ve`.vq,xvx ,xvx ,xvu|(v^X "v^X "v!4vu|(vu|(vP|(vw0wu@~x0x0x0xwpvPgvPgvivzXvXhwvθvpv`pv8v`vq,xx0x0yf hyTyߨyxy`^yPU`z# z#z#zyxhy9hxmLx'`GPwh(wrPw:Pw4vXewvHvpÈvH z#z#z`8z{h{8!{eX{z(u@ Jhu@ Jhu8 :u@ Jhu@ JhuѸ v P!>(v P!>(u@ JhoCyoCynxFXn][pn M`mn0mimM`m.mUM`m8.mllPXllxl)l0xl9xڈlHkxkƠkPk`@kSk5Pjkl`kp kp kp k"Fjj`j@jPjh8jЈ-jhߨhߨh8hh i=hNph8jhʨhph(hS8hRhxl`hNXheXhhÈhiӀiXi4ixixixiijHhjɀzpjpeXjאeXkp ixixiXi@iHjypjypjypj jj8k0pk"Hkl& lްlNlL8@lL8@lH5hm!3m;H,m;H 8mmppmHn hn#P@nO8nzHnn`o XרlNlNlE0:kij<ްjCjkɘjypfX/fX/ffXhf@f`fppf%8fJ*fCWHfeXf7xf.f.0f.0fd f?@f?@f?@fOh hftf_Df_Df_Df 8Hf_Df_Df`n0fu8fn0gfPPg.g g Lf?@f?@f0ffx8Hf4f4g24gpgXgghBg78g0h0h$(PhWhh  hlhh`Hh`Hh`Hhhqh$(h&h&hh wh y`h y`h/fh!Sh9@Sh!Sh&h&h y`h`h`hii0iǰjihi@Pxi@Pxi@Px^b^b^_`H^fhup^8e^͈up^X`X_Ghe_I_z__&C_X_t_ ^^_ x^ԐS^v_(r_p^xp^͈Xf4f4fhhfhfX@fAXhf' f<f? fi0@f@mfxmfXg Lg Lg LgJg}`u%2v$vF$vq$ p&p&k$k0$8k0$8k0$8j%jQ$piu$8^"s^"s`=#`=#`=#b%qc%c& c0&$c&Rd!&Rd4X&ld0&d8&xd&Hd@'e6(&Ha*a*ahYaXlHaa`axHaHa * bwxbQb0`b:0aOЈa:` p`p Qp`@ Z` m`u `- 0_`!_S ! _B!2p^!)^!^"=Y&Y&Y%@[`%@[P$[P$\I$\I#(^#(^"q0^"q0^"q0^"=["=["=^"=Yˀ(8Yˀ(8Y(]ZX (]Zx(CZ(M0[D([x([(([([x)h\A)Z\A)X`\A)X`\e )@\l((@\P(x\)$\x(]H(](p](_(_(w`_(__B#`=#Y)Y)Z_()Zo)Z)Z)hZ)[* [4p)[K*8[H*+PZH*8Z)Z{H*8ZC*Z2*Z0H*4Y*7Y*B\%)S\%)S\,)@\KX)\P)\=H)\b*!\@*\*Nx\X*h\h* \h* \h* \*[p*h[* [*[W*x[W*x[W*xZP*{ZC*Y*8Z+lhZ+lhZϨ+[W+[Y*h[4p*è[^*8[W*x\*\*\P*P\*\*H\*]*]3`*H]h*]*]X*p]8*^ *^P+^G+1^h+j^7+\^S+lh^V+^0+ ^}+^0+ڐ^0+ڐ^d+^h,8P^,D^8,b^,r^8,|H^,^,^,X^tx,^],X^XX,^},x^-^tx-^]-J^9-H0^9-H0^9-H0^-5p^-H0^-r`]x-{]-a]-dP]-H0],],][8,Ш]V,˜]<,H]?,H]?,H\,] 0,H] ,(],u@\ ,r],Tp\(+\ ,h[؀,Tp[h,V[,w[0,y]<,H]<,H]8,x] -] -,\-@^9-H0^9-H0^S-^L-^' -0^E-8^C@-H^-^.+^͈.;^Ԑ.^.0^x/ a,.ha,.ha` .`a[p._a8H.Nax-a[p-HaH, ap,Xa[p,wag(,:ag(,:ag(,:a],F`aO,:a +`+`@, p`zp,,`eX,(`M, `&,`+_+_ظ+_ظ+_ظ+_+h_+8_vH+_z+_q+_Z(+_Z(+_9X+@_9X+p_(+_ x+^+^(+`^0+ڐ_ظ+_ظ+_+zx_h+Y_0+R`@+*_*_ *0`D*`x*`l`*q`*c` *;`*`*8`*2Xa*$Ha )XaK)aO)ar)a@)`a)tbH()Lb{)'(b)2cP)2e6(&He6(&Hfx&f(%8iu$8cP)2cP)2cm )2c) d)d(d)d`(e(e/ (ne6(&HcP)2cP)2b)vc)Xc" )8c78)c*cj*cj*Ec(*d*vPd@*(d *d2*d2*(d2*(d;`*hd/*dn*d*d2*d2*c+*c+*c+B8c+?c}+`chp+e`chp+e`chp+e`b+WPb+Rb+Rb+Rb+qbp+caR+e`aD+Ha[p+ha]+̀aV,ag(,:c@.pc@.pcN-c+-Pc>@-mc)(-V@c9-5pc2, cG,޸ch,pc)(,c-,Db,?Xch,,c,#8c, c+b+b+b+qb+qb+jb+WPbh+Rcah+e`cah+e`cN+cX+c,1Hc,wcȈ-cx-cݠ-c0.k$k$k:%kv%(ko&k&BkX&} ka('j(j~).0jd)r(jF@)}j])Xd^-d^-dl-Qdg,wdp,rd ,Ad, d+dx+ڐdh+̀dx+d+d+Td+(pd*d+d+d*e!*L e(*(e8)fT)f*L g+*gU*!g@*S(h+0*h@hs*&h0*8i**8i*Ei*(j * j])Xj])Xj])Xj*Bj*@hj*@hj*j*jޘ+j+j+B8j@+=jr+`jF@+ڐj'+j%p,,i,Ki,pi,i,i(,ix-iT-r`ig-(i=h-i8-i@-h-h-`h - hh-Hh-Hhv0-hB-h6-g`.;gX.Xg.ob+lhob+lho)+lhnh+nh+(n(,Rn,kmN,Pm=,mc ,m-l0- lX-Jk0-k-Qkd0-Lkd0-Lkd0-Lko-.hk:,Hj8,%j+Xk}+Xk0+k 8+I@k.H*8k$*k x*èkp*jޘ*ljЈ*@hj*@hq.q.q.q.pqo.q;.px.{8pϰ.p.pv.pQ .pEh.o.o~0.ȐoJ. oA@/Ho% /+n/nd/n//(n8.m(.`m.`ml.m-8/m/8m/hm/hm/hm/qPl/hl{/ek/hk/xkƠ08kd0-Lkd0-Lk>-wk-j.xj.2j@.j.Xj`.k)/k7/6k$/9kA/jHk/pkƠ08orx+qorx+qo,oH,Vo(,|Ho,~oˈ,xp2,p)H,޸p,p-p@-QqcX-qW-qz.`qo.qр.LXq.q.kƠ08kƠ08k80?k0|k08kP0``k0WjH0:j.0?i@0?i@0?ha0?hD0%i@0?i@0?i0hB0j.0?j.0?j0ej'0j0j00j`0jp0xjא0j(10j1%@j1Qj1{j01XjX1j@1j01jɀ2SjЈ2{pj2(j2j2j2j2 j82jpp2jJ2pj2hi2xi2oiH2yiP2pip2`i=h2`iF28i83ib3iR3!ix3=ie@3a in3v8i6`3Pi 03v8i3m/hm/hmx/Hl08l 0l0l10l1l1@lf1l&2k(2vkƠ2HkP3Ekp3kk83k](3@k%`jЈ>%`j>3pjX=j@=t@0t@0t@@-t@@-t@@-t8?to?xto?to?t"x?sH?xs? s@)s@\t+@oPtr(@ltt@+Xt@@-to?xto?xtv>td>t58>Vt=t=t=s=sp=8s:p=s0=s= s= r=r=Hrl0=ܸr>3pr`>Hq >]qH>qcX>Pq?`p?p?p?oĀ?SoX?Q`o~0?Zof?HoA@?oh?`nH@np@n`@2`n8h@-n3?nV?͘nO?n?0m? m? m? mAmAmuA;8m`AYm(AFlqA6lhX@l@@pl&@lAkxA#rpA(xrpA(xrARqAXqApqAqHBrB?`rPBHrwBprAHrA s ArAjrpA(xs0= s0= r=r=irDX=Irx=r(0uNx7 u-6u46Ըu@6@u 6t6vX7vX7vx 7v7v7v7ݐvX7@w07wr7@w 7xw7x7x>7xr`7yp72xp&p&p&sp &sp %Zob+lhob+lhorx+lho~0+=oE+ PoOP*`o:8*Ѹo,(* o7*o*oHn8*}Xn*h@o p*o)oC)o,()ooX)_hoT)Eo)hoy(oH(p(pp&r2r2r`2ۈr2s02sH2sT82spX2ps(2s2s2s2sp2s28sp2Zs82@s2s2s2s3s3sp39Hs3cxs_3@s83`s 83s /hs /ht/Yt2/nt]/Ytmx/vt/t/`ux/N(uI/`u/Hu/Hu/Hu/N(u8/N(u0/\8u`/lu/v0v0bv0u08u1b0u1u/Hu/Huè.v.y/@y/@yc/yf 1 yx2Zv.v.vX. w8P/wP/qPx/px/PyG/y}/Dy/=y/@y/@z(/!zl/zx.z .{.0}<(- @|- @{X,~zP,Az,hzjH+ӈzP+zxX+e`zxX+e`zxX+e`z+!hzxX+e`zxX+e`zK+WPy+nyH+e`y+z2*zU0*0zn*z*sv.v.v0.@v.vD.}u0-hu-ue-?6p%77qP7qP7q7q7q7aX7PxP8xP869= 9= 9= 9x::P:P;;;;0;h;;;<X< Php5y:75:dp5:[58:{6:ː6_:6 ;60;>h6;6<$6<6>=>=b>׀=6P? =T?P:LX: L:@Lh:tL:{L@:M:pMP:M>8;)PMB;@M;0XMH;M;\MhH=Ψ>3p=>8 =>u=>~p=g>h=h?d =x?=?=@^=@x=@vX=@vX=@=@>AM>gA^`>xAP>B? hB`?+C'h?ECA0?{C%?B(?HBx@B@Z8B@qC,@qC@hC@(Dh@qD>P@hDX@lDo@BD`@>D@@D`?{@x=@x=@=h@@F06p>6>06>6?6h?7 >72x>X7oh>7?7@?"7?.88?t8(?@8I`?8U?8I`@@8j0@;8c(@c8@X8x@08A`8A`9A9A 9iA9AP9A09AӐ:_B`:bBH:B:C);@CQ;oC%;hC.p;(BD>Dݰ> E>HE>D`?{C7B C7B CB6C `Bg8BB@BBB BB0C0B CCC7B C7B CACpB DB[DBXDShBbD{@BXDBDB@E!BEYC HEsCA0EPCiEzCEx`CExCXD`?{D`?{D?E(?r0EI?Eg?ۨER@WE@hHE@D@ D@D>P@DGA XD(AC7B(C0^C0^D(0npD)80^D 01D"00 DEX0D(0 D`0( D0( D0( E&X0FEY0#pEx`03E0%E0:E0?E0( F/HF|/9D`0( D`0( E/E/HE6/E6/sE0/9D.HDx.EP.A.A.A.A.A.B/B/HB./G B/vAX/A0#pB0/(B(0iB0wBTx0Bh0B0 B0XB׸0@C@0C0CC00CVH0bC0TCX0iC0^>%`0(>%`0(>r1>0>81? 0?Q`0x?0?0?0^@ 0A@0h?0`?/8?/?/v?H/?fx/-X?/-X?(/N(@/Bp@U/z@j/jH@hH/9@h/9@/#@//A/@A/A`.A.ȐA.xA.;*;*;U+;.+PH; 0+T:+:ː, p:,d:,Tp:,p:,n8:,0;,װ;$,0;-H;-S;9-a;S-<\X-8%`0(AX,@AX,@Bp,pAX-%A8-LAH-{A(-A-AK-AM. A(x.+A.0~>00>%`0(C0^C0^Ch0RPCt/xCf/xC3 /xB8/=C.XC.ȐC0.Ci.Cf.Cw.Cb.Cm.m(=/HN\(=/HN\(=,O80M0M 0e`000O0y@0Έ0Xx0x00N0(v`0Xp00M03-00Xh/!x/pY/\/Ix@/ 0///Fp/ 0z/&Px.x.x/;h@/-X/.֠...p/?/!x.0T2T2T4?5V5:T6t"+"+!- HSX SahXUhpy_n@CH8^8^ ^"+"+"X""^"^"-P""|"c"p)( ^ ^"^#6`#6`  ^%p%p%H%h$hp$P0$$ ֘$$]`c$CU$t(#hp#$#pƸ#Oa#Ox6806v06Ch6.P@605H5 77(77(77(7787p808-@77(77(6607P87P87P^9~^9up99h9h9h:HP:0:V:V:(:bܐ:kxH:::V:V:V:X^:^:^;o^;h;o[;o[;8[;`:::}:`:;8;8:;;;;;h;h;x <Ũ;;;;N;@;77(77(9?x9z(9z(9O09?x9?x9s9Q89Q89HQ89?x8-@8-@8U8 @9h9h99%89x_9t8"X8"X8p8 8 8 8h h ixBjvHj3qjMHsj[Xxjppjyju jihjTPj5àjHi6`-ha@i1Z(i1Z(i`hhhi8i#hsWHj j jy( jJ j'v j?8fh jpp j< jh` h`ag(h ag(h a a a(H a: a'` ag(h`| `| `u `? `|_}P[ _}P[ _cu _^w _a0 _P` _2PP _  ^p _ ^`X _ps0 _lM _}P[b:9 b:9 b)! a(9 b.`I aR be b.`Y b P( b:9 k k k27 j`.( ki 0@ i 0@ i?V ib] i*r hXX i 0@i`@ i`@ iQP ipv iKxC@ i`@i2 i2 i@ ipJH i2i i i` i 8 iH izX"p i9 iDp0 i^850 iM i ix h h hؠ i i4 i iW0 i?˸ iY ilH ilHx i ib ih' h' h0_` h QP h' h( h( h0 hh .( h28 hH( h8 h h(o o oH@ ph oOP ob nY8 n8 nV okptX oĀh on@tX n@tX oEx mhU n:} n@tXqx' qx'rh rh s. r( r,"P rhpM pM p}[ qp0 q0P q ( qҠ p okp otH nR0H mx mx nz0 n  o"` m` l(P mGw8 lHk mk mNO` m8_ mO` m 7 nR0_ nX o o_Q ob5 opAP om p)HJ pZ[ pMu0_ u0_h h i 0 ih iKx iP i in>p j L iS j{` j`a jЈ9 k>9 kS kZX8 k2 k`X8 laP\ kh jhp jx0 jVx j8X l7  lGP j`` k0 j j kO$ k$ kd04 k۸a lS@NP lE0 l l lX( m^pp mKX8 m(@ n+ mŐ mDp l l0P l l^ k԰t kyH k jH` j` jH iH0 j jwx ih i  i iM hh0` h0` h ipy h0`kXx kXx k @ k @ k > ( @ [ H 8H (  ( xx ; 3H ( )( Ę P P ph y p8{ ,@0 p8r ˠ[p O d c0 `( M P X!` ~H `  h8 X@ p8 C 0 P %8 F 5 M H` ' AX x x! h 8 >ox ox 0@  X x x ֘  !H} 4 ox@c @c ]9   wx  @c{ { > {x&0 &0  X ` c  !( &01 1  nh 3h HDP HDP !( Tp F x` ` HDP  ` } ` } L _x _ H ɐ 0` 2 ` 2 ( d(  P P ` @ O ( X  ` 9p PCx Cx P Cxh h Ӹ8 8( [Ǩ Hih ih %h : * )p lhZX ZX x P([ M *   b  ZXY Y Ո=` ܐF 0W( PF 7/P @ pؘ rߠ ' _* 8 } ` p0 0  X H ^ ( H \  +ؘ _x h 0^0 Dn ^0 ? `W(H( H(  H kPÀ Z H(xX X  a`  X  x{` mPh Q0 $ S+ 5  ($ PX  h xP w YH X 8 M 8 s. .   X w8  Ip vx xw8 t f 5`{ p0 P X   g  [h˘ @ p  c$ "P  d@ d@  % (5 Y> HX Q T xVh 8f s`f V~@ cT ; x d@ `  ` X 0 ( H   A Q A Q O ` 8 P  X ވ 1  %h @ < A O}_P }h }_P }h }y W }x @x ~h( aH ~}@  } }_P }a }h    8 ׈  ׈  h    H    |  bX 3 g  A ip ,p  ` . 0 ?0 ` M@ Ը V m [P P g S u x k@ @ d8 'H h 5X P S 0 ` h`  \ (   ( h  x Qx  .P (  ?@ g v A a px ]  _x < L 8 .@ A H . 0 ` 5H  9  .@   @ .@ (   .@ W8 0  `-i -i an rHX X Jp ~ @  h ΰ Y @ H H # ( %h p  H 3x 0 %h SH P H _ H (0 h   j8 8 π@ @ &8 ֈzP Ph c(w Y` w Y [ /Dh ̠=` P, = ; x  g PNP P+( `+( P !e 8 5 l@ =  HX  hߠ 0 vp @ P x4 !@ =` Dh Y +pi<  <   UՀ X X( <  P-@~@ -@~@ m | -@~@0p0 0p0 +p:H q8O` f 0mm m (O` J @m `kb b @C w[ _~^ ~^ ~߰p0  ~a }r }r }7x]p |~PT }XHO` }F }N< | > }3@ ~+8x } p ~= ~ ~x K( }XHX }i( } p0{%0 {%0 |0 } }H' }Xp |0AP |). {%0s3@ s3@ H   %0 gPF u3@<  <   UՀ X X( <` ` @8  VX `  `  K     @X @  @  ( @ 0H 0H X8 PH  B 0HXx Xx x h' ]0xf( f( Z x   (0 d8(   `   X  `+0 +0 ^ `2 xu \0 +0poOP oOP ox oE3 nH oOPoX oX o  oo6@ o6@ oI o@A o6@o oo? o? oW oz8 nH o`~ n(l( n@b nM oYh o?BX BX X X * X  ͠ N    $X  $X @ =& =& BX&+ (&\P &B =&X"h X"h x" >"ڨ >"̘ " X"h X"h* * X*& *B *W * * x*` + * *H (* *` 0*@ ) * (,] (,] ,k (,]P&v P&v bX&j` &xp (&h &xp X&^ &xp ސ&P &` & H&H 8& H& 0'( @' Q'F TH'W *'T 'u 'F h& & & & &v' B ' B 9` h^8 ' DpH=h H=h ` vF 1 =hp p  %p 3`. CX pb b  Pu b0 0  ۘx 0j j ` }P jE E I@ eH P E8!p 8!p !X 8! 8!pXX" XX" Z"Ő " $" H#H " +"ڨ " XX"xZ0H" Z0H" ZQ"4@ Zo" Zj!P Z@!P Z0H" Y! Y! Y!݈ Yh" Z! Y!gh/` gh/` g/@ g/ g/p g/ g/^ gh/`z87 z87 z7` z7` z7 z87xf4 xf4 xp40 xx40 x4 x4 x04 xyh4 xf4U U TX TX Tސ U p U TXSո+ Sո+ T5 S"X Sո+S1E S1E S=`X@ SwS S1ES87p S87p Sx< SG S*C( S87p 0: 0: : : :P :P -X:{ l:t v:_ `:J `:JxX: xX: ŷ:{ ū: Ź:` e:` K:` 6: 0:ħ;y ħ;y J;c >H;N X;0X Q;ĐP:p ĐP:p @:p ; ;"H ;Ep 0;S ;f@ ħ;y9p$p 9p$p 9@$x 9$p 9$ 9p$p 9T# 9T# 9D(# 9u`$ 9d$,( 9$,( 9T#81$h 81$h 8-@$< 8=$" 8I`$< 8G$dh 8($dh 8D$VX 88$Q 8#$VX 8 $30 81$h7# 7# 8 # 8-@#x 8/# 8$ 7# 7# 78#x 7#8 7# 7ݐ#x 7#8#d 8#d 9# 98# 8 #h 98#ɸ 9 # 8# 8#z 8#d8"p 8"p 8I`"p 8X"X 8|#0 8x@#8h 8\ #% 8u# 8H"ڨ 8I`" 8"p7" 7" 7@" 7" 7ֈ" 8x"0 8x" 7P" 7":dp%p :dp%p :%P :Ĉ%@ :% :dp%p?>' ?>'A(n A(n A(] AF( A( A(n@(8 @(8 @(r A`(p A( @(8A( A( A8(8 A8) A(x) A(AB@)E AB@)E An)S Ax()} AR)} A^`)r( AB@)E5?@%q 5?@%q 5J%a 5r%q 5%p 5V%0 510%p 5R% 5?@%q7p% 7p% 7%8 7(% 7P%0 7p%78%"@ 78%"@ 7%"@ 8h%5 78%"@8h%- 8h%- 80%Eh 8%@ 8h%-8%Lp 8%Lp 8=%U 81%h 8%Lp> O > O =xO( =ǠO =Op =uOp =RpO = O@ > O=MO =MO =W O =1O <O =gO =O =nO =zHP h =6PO8 =O@ <O܈ =Oh <O <ؐO` ~pOe ? Ouh >O@ >_O =,O(HJ@1 HJ@1 H<01` H71x H+2@ H2 H2 H P27x G82' H P2<( G2G G2<( G2S G2C0 G2a G2d G2o Gb82XH GHp2d GC2@ G3X2r G82m` F29 F2 G2 G%H2 F1 G 1 G@1X G 1 G81` G81~P Gx1h G1 HJ@1AR+( AR+( Alp+( AY+@ A^`+@ @x+P A+( A+ A+8 AR+(A+4( A+4(AYN AYN AN AM AMH A8M AM AM֐ AMX A@Mp AM B=M BY(M` AM AŀN ApN0 AN! AYNBN( BN( BVM ByM B`0M( BuHM B`M B~MH BM BMp BpMψ BhM CM C%Mx B(Mx CPM8 C)M֐ BMݘ BxM BɨM BM B0N( BbMh BMpN Bn@N! BAN( BHN1 BN0P1b0 0P1b0 0@1r 01t 01 01H 01p 02 010 11ٸ 01H 010 01] 0P1b001 01 0P1 01 01$x $x O(0 'P  0  $x(p (p  @  8  8 X (p4P( 4P( N8 /H =Ѱ  @h Ѱ  x8 4P(IhX IhX h h IhX  l @- c- fH(  0 0 aX  S S( GH / ( (   p @@ NPX  !͈ \`͈ \` 0X@( X@( HP `} @  `z ^ ;^ X@(    `x @  T H P d`  >rp t 8 7h  X   H&N@ H&N@ &v &` ]'  =& '&@ H&s H&N@ % % /& p&! % ڠ% `%0 % % % ň%ϰ 0%h x0%h % p% p% D%H % % @% p% \%@ \%@ I%m@ %U ;%9 \%@P P @h H@ PX| X|  Ũ8  H (  8  HP =0  `X` ?9 b<8 ^fh 6(a (7 `G  > `2  ' ` p  @ x  p x  8( X|H H  ΀    hx X  w   ˸ İ P HX" X" hV (8 Hm um s3` BhH X"9. 9. BhQ W< qHX PxX Yh K = *x 4X@ | @iH ] 9Q  (8 65 9.  F X b@ 8M( X  C M( 8 8 8*  Z`h vh H  Qp Qp t(~ I I @ P p  x ;X  ( ܨ G j X 00ܨ I  X & H Hu  u Qp`p `p | -P| `Θ # p YX 6 Wh 2h ` hh 8 ܨ H @ ݠz8 `pU`p U`p Lhs0 U~ >Xn 2  ~ X | | i p H[ 0HYh U`p` `  H  ` 2 (0 Lh 2  0 p` h x  0 @ i " H@F 3(C L%P m :0%P L8 8 :08 5 h ) :0ՠ ih ]XΘ X8 @ Q m  ǐ  X p 0  p ` P<8 P<8 Oh %h] @o o n Dhtx E x2 P<86#( 6#(;_8 ;_8 :  :t" ::@%8 :E  : : ;+0 :X ;_83xH 3xH 28ϐ 2 3xH20p 20p 2N8 2Q@ 2J8 20pp 2m`]@ 2_ 20p2G 2G! ! !@H !@H !9x !ǰ !@H P P 0ǰ p X P|x2P |x2P @Np ^L \ `Xc 8o@ ss  `   H  à RHx eq 1xa0 MS Gh |x2P  `X/ %> / & 8 %$@   P @ %p Fƀ ? @ ,` `p H D8 4 { 4 { 78 e } { @ aH f Z@  aH  E(  I  $X g ;  &H P ϐ x  ; 0 00  ox 4 {ۀ ۀ 8 Z8 x  @H  pX p  8`  0   h  ` ( 28 W#0 l' % Z3 WM` Th hY M` pg( 8R p ߨi (y X  Dp P(d KxH % H 'ר `( @ 8 d TD px (?Z ?Z ?> >@ ?Z9H 9H 9@ U 9Y@ x0 8 x0 8g ? 8̠ 9i 9H 5x8 5x8 5 5ޠ 588J 4J 4` 5 5x870 & 70 & 7UJ 7P 6ƨ} 6Sp 6(- 70 &7h`d 7h`d 7 7_X 7}xwX 7SH 7fp 77( 7 ˸ 74 6İ 6(P 70 h 79_ 7& 7UV 7h`d=+ =+ =G0 =MW =+!P !P !>( !q !hXX "( "̘ #  !o` 0 !P p X ) + 9 h 0 k d( 1( _x  x =h  =h (P i`  ` I J  T 0| X( !9x0 !P# # $8 $rx $0 TH %P ~x %h  %{P % %p h & &D P &= &8 P &P &( &K & ~x &N@ | & H ] &6 TH & bX '8 'i  '  'x P 'x Ѐ ' < 'H %h (@ ?0 (,` * (X O ) X )H 0 )d _x )  *> 0 *Gp +H P +  +j h +j +` +6 +` +& 8 + - * *x P *` > *( ) *I B *0 x *8 B * N *H j * oX * *Z0 @ ) 0 )>  (n oX (T8 B 'h 'B ( & P %P  $X $0 p $m $8 oX " P "^p # Ԩ %( ͠ $J #b "K !ր o #H

PM DC` D 8 Dh| Dp@ C0 C8H D  D D$P Dh D. D4% D K D4< DL`O D\A DZpR Dm0?P DxK D}Y DK D}: D`: Dt8 DHk DhTh Dpg( D8K D: D` E2A Eh] Eo EN0 Ep EKp E4h E@  EN0 Eo E@  EPX EN0Р EKX EjP@ El Ep E EŸ EjP E@ p EBx Ee EBx Eo 8 ER3 E@ 'X EWH( EeV8 E E E0 EJ EdH E.` EHV8 E E` El Eg EjP8 Es E ERa E6, E P D_ DkP D(J Dh DdH Dt8 D4 D"08 DPA DpA D0 DL Dm0A DXf DQS D>P_ D&a D@L DX DQA D)8Cx D>PH Dx

@ 5Q 6x;= = =@ P >H >' P > h >8  >r  >g ( >5 ( >iX 6 > P >@ IP >` p > p > N >H !x ?)  ?S  ?"  ? F ?7 48 ?] -0 ? 6 ?_p D ? K ?{ ` ?( ` ?Ɛ x0 ?H q( ? x0 ?JX ?0 | ?Xh ` ?Ԡ @ ?P ` @2` s @$P  ?H ( @  @ ( @ ̐ @Z8  @S0 @j h @8 @ @ @` p @  @ A A8 A @ ̐ @ @8 ڠ A X  @ h A @}` @ @t  @S0 @ , @;  @ H @^ Fp @Z8 O @vX i @N R( @I i @) b ? 8` @ ] ? ] @ b ?h p @H ~ ? z @ ( ?  ?Ԡ ? ?@ ? ~ ?k( ?9 ?7 ?} w ?  ?S `8 ? p ? b ?H T > ] > R( > : ?Q` 3 ?S  ?H ?5@ #H > 6 >  > >( ( >X  >bP h >:x >H Ә >  =( P = = h = ( = = x =0 8` = ?h =;  =x 8 =P #H =u 3 =W : =i K = H =P w = ] =ܸ p =ܸ p > ~ = > > @ >8 >< p >?( >( ` > ( > и >` >H  > h >pH ? (H ? h >  ?, >3( ? hC ?ZC ?.8b ?ow ?m ?d` ?.8 ? ?9 ? ?_p ?` ? ?5@p ? >@ >0 >h@ > > >H >0 >wh >@ >Vˀ >CP >Q8 >.` >' >H > > ` =Ψ =i =P =`t <`kh =Xˀ = = = = =` >n"8 >]2 >C >X > Q >t@ =/H< <ؐ"8 <ш h ;p ;P ; ;ab ;_8yx ;7`i ;&t ;EpVP ;f :VP :< :L : h :" : :@ :kx :]h @ :C ::@` :38 :p 8 :X 9( 9 ɰ 9  9 9 9 9 9= 9T 9F 8p 8 8@.x 8 7ݐ 7 P 8g 8Wp z 9?x ( 9s 9O 9w x 9|h X 9]  9 9|h 9(  9 ~ 9 :,0 p : |X 9 @ : 8 ; ; ; 6 < <=  8 " =n $X =x G >3p Z@ >5 v` < \ =n c <` j =? m < { < =Kh oX = p = =8 =X 8 =B = < =~ =p ` = h = ݀ =  = =H >?( x = =Ǡ =` >H 8 = 6( 6( 7P 8x@ P 90 H 8 ph 8/ d 7X u 6h 8( 6rH ' 6(.hǨ .hǨ / 0*x` 1T  0H y /8 wp /\8 | / /4` . .H ( . x .S` ph .LX .8 .h .hǨ.ȐP .ȐP /h8 /ep .p .08W( . ; -Kp -? .B . .G .ȐP!X !X " "H "h #uX "` #M+( "p- #6P "Xe "j( "`v( "*= ! P !ch ! ! !;}0 !X !>(p Ơ } >  y P J x !X)٨ )٨ *\ * * ( +g@ +K' +x' ,1HEx , ,d +@ +`{` *v *ja )v )LfH )GG *G )x>p *0` )`+ )` 8 )0' )_h (0 ( )٨-H$ -H$ -L .Ȑc .xv . -H -) - -y ,XU -H$+W +W ,,Z ,px ,y\` ,P -: l -@ -aH -p -0 , -A(, ,0 ,Mh? ,O, ,*@B +/P +!@ +X +8p ,  ,ؘ *j *ؘ *h *P( +q +`À +8h *h +/x *P *qx + ,?Xp +ӈ ,D +H , +jl +WT f T f TX  T Sl@ 8 S H T fV- ph V- ph V V^ P Vø V Ѐ U} U{ k V- phV bX V bX V r Vx ( V- i` U_x ] V" M@ V bXUv  Uv  VP 8( U'8 ,p VP A U{ TH T < U ` Uv E E E ` Fgp 0 Es hP E@ N Ex L0 E( 7 EU8 I E= 4 DP 7 D & E ) D  D 0 E 8 D E T2 T2 3 3S 3 C(3 J03 t`3 3P 3 4 4sX U`4 p4P X4 4 @5 5%x 5J (5@ h5 5 ?5H M6$ lH63 `6m `6_ (6m p60 H6 MH6ƨ h6 1(6 P7X x7P y7 X7>0 d7P 1(7; Q70 #7 7X 6 n7 Dp68 @6 (6 ʐ6 P6 6f e6a h 6H !5 H5Ɉ v5 r5 mX5 U5P L5 C(5 C(5` 25H >x5 '5X 5 5 x5 p5Ɉ Ę5h k6x 06  5 5 5 ~H6 6A 6f :P6 6yP 6v T6t@7 @7 W7 7 @76 6 6 6 06 68 606_ 06_ x6t ԰6 6t 06_yH3 yH3 yH3H 3Ѡ 4 P4- Z4/` o4i H4 4z` 4x א4 4 H4 40 4` 4p P4 b4 `4sX 4sX 4 `4sX ?84sX Q4/` b`48 J4Y ]4| 4| ɀ4sX `4- 24!P 3 Z3Ѡ yH320 20 f39H 03 3 3@ 4 4H Ơ4 3 X3e 2 2P 2 20?82 ?82 b`2 2 2@ ]2@ ?82 04lP 04lP 4| BP4h x84 H5, g588 4@5# 5 #4 84 04lPؠ2 ؠ2 P2 2H cp2P o(2 ؠ2 'T 'T 0'@ ' /( (p ( ( (( (x )  @)Z )d @) ݸ) ) ) 0) )X -h)H R) v)p )X )۠ @)0 ) @)p )͐ ) )X `) *+P *B *E *h *c X*P ؀*a8 *I x* /)0 X)ƈ =* D*+P 9 *4 * )ƈ h) ) \) X ) G) G)͐ $)۠ ) U)r( )@ ){ x) )] X)JP 8)O p(X X(H (y H( ( h(p (O ' `' 'B @'1 P'B `'g 0'DX 'T)x )x 8)` *x X)` ) )x* * * * * `*@ * x*x *H **x *x U*x h* x*; * h* )@*9` *0 h*x(0* (0* *p (* ՠ* @+ +4( +I@ p+` P+PH p+Y +? += +* s0+ *gx* gx* :*P (0*/8+` /8+` R`+;0 H+/x + x+( `+8 +p H+( P+ i+ڐ n+( l(+ T+e` F+x 6@+q /8+`, , ,: 0,F` ,] 5,Tp 1,r Hx, %P, O, F , M(- iH-3 m-r` Ap- F -X .- :h- 3`- (-f `-t -h ܨ-0 h.p ._ h.B .p .9 =H. `-@ P- -_ x-% -'` -7 P-dP -L -.h s-V@ W-X W-.h @(-) -V@ - X- - h,( v,H ,@ ,x 0, ,P , x- , :, W,P gx, p,|H ,h ,r H,~ , x- x- - -8 `-8 Ƞ- x-:+ :+ P+ P, #,*@ ,' ,( p+@ =H+`+F `+F X+ +H ,D H+X + `+F`+u `+u x, ,1H @,R ,p jX,p \H,O (,. , p &`+ ^+ W+X o+u 0+e` `+up* p* ;x+ K+ h+ cP+(p + +# +K U@+g K+ `+ + Ϩ* p*p*8 p*8 H*X `* ِ*p h*P *8+* +* 0+x + kh+ X+P + h, , ,Tp , k, ?h,` ,w ,] >+ d`+ p+ ]X+lh + kh+g m+WP +- `:` `:` Px: Y:@ :r : X: ^:`? ? ?E ?+ ? h ? X?+ ?-GM -GM W0Gm W0G /XG G[0 -GM I& I& H H H H H X@H \GX 0Gp G` G 4H P jxH zH H0x @G@ ߨG8 G /XGҸ ^8G0 bHH MH ;HH H̀ -H` *I( pI xIh I H `H ߨIx ʐH I- I- I\x xIc eINh IZ I> 4I6 I6 I$8 PI6 I$8(G:` (G:` @Gi@ pG GHp (G:`XD XD vD qE@ E E! pE E( E( ahEBx 9E6 E@ E XD7` 7` 7ֈ 7@ @7 7 P7X 7X P7P &7h 70 7` 7 7 Np7 j7ݐ ^7p x7 `7ݐ 7 9K0 9K0 9A 9 8x H9@ h9 H9 H9= 9: 9K0wHU wHU HJ@ |HH0x ¤ HX kH` “H ¡G G0 n8G8 |HH g0H ˆH VH n8G@ VG8 yG KG H"h G Gh Gh hGĨ G HG@ G lhGx nH  FHS H_X 0Hp 1HX H `HH ѸI HH 8I I `I xI jI0 }XI4 h@I! PI4 UIB 2XIG` &IS -Ia( pIs I HI I _hIp I I0 `I I0 J ހJ 0J(` xJ J!X J- J(` `J6p JB( JD JT JW@ XJlX xJP8 JeP w`Jj w`Jzh Jn |J| ~hJ J( QJ8 T8JX w`J@ J fJ J w`Jx PJx J@ ]J ]K K KX sJP J J J J0 xJ( J# J8 (J J I hI@ ѸI( IØ I I I0 1I =I FI x I I@X XI9P I6 PI9P I I( I9P IX Is hI}H I I Iz Iq Ij 0Ic IL lhII WPI9P INh IG` xI9P 0I2H xI4 xI kH bH –Hk HN wHU)K )K EK3 $K< JPK< LKMX Kg K5 Kp +K G< G< +G:` `G| ×H "HL H2 H0x H ޸H' ɠH` H 3G` Y G8 ]F HF0 װF`h F^ hFY` hF: F3 FP pE8 E8 ˜E `E E E »E Ex` ²0E ´Ex` šEg ½EY ŸpE\@ ´EK EK šE\@ |HEN0 iE$ ‘`Eg iEK D DD֨ #8D D (DP D hD pDX DX Dj Dx PDj  Dx %D *@D OD RD0 g0Dx ŠXD u@DȘ ŠXDݰ ¨D@ ¶E ɠE! ¦xE ¦xEP @E! »E6 xEg ޸Eg hEz EqX E Ex E E E XEP xE E "E 5pE V@E H0E 5pEz LEh XE yhE dPEH {EP ÉF åF ÐF  ÎFp êF(( -FRX \FKP ĥhF F% FRX F Ğ`Fp ėXFX ĜF ĒFX UF F G<5` 5` %5: 8h5bh gH5~ 5px H5# 5`gH5А gH5А w5 6 6'H uX68 i5h ?p6 gH5А5 5 C50 rx5@ h6 X6 p6$ 05H 5P6 P6 6 h6 26 26p 6` @6 P6)H6 )H6 Sx6.P G6H h6]0 6 7X6k@ 06x )H6}7 }7 (7- 7aX 7c 7f 7G 7" x7` }7 <0 <0 (< ;+ t;7` t;$|9 |9 d9w X9 |:  9H 9@ 09 (9 |9x:y x:y :T :E :,0 :. :i :w0 0: x:yv) v) a*( Q8*0 v)X9 X9 8ڰ F8 F9 X99( 9( `P9 X9 9(;0 ;0 ;p ; ;0Ȁ=8 Ȁ=8 ;ϸ ;ϸ: : :` : :8;@ 8;@ X;. P; ; H;. 8;@0.q 0.q . . .o .qw/&P w/&P /( /H / . . x.p . H@. f. X.q 5.{8 P.X .hx H.Q .>H .Q .@ ¨.7@ . g@.7@ .& z. -8 p-p g@-ـ O-p :- -x - - P- .ap \.ap BH.x `. Y. !x.0. . .x. x. {. v`/ x/ 7/x (/ "0 00% 0% P0A p0A 0F 0w `0 0 0h 0 0X `0 0| | 0s u0 C0 0M!x.0 !x.0 .. . p. .ݨ x.0.ap 0.ap {.ap . . E@. q. . . ݘ/( ψ// `/6 / ̨/ 0 Ӱ/ h0X p/ 00P 0, R@0np D00/( e0/( 0M 00 08 0 0H %01 k1 10 :H1Vx %01M :H1[( dx1M 1%@ 1Hh 1p@ 1r `1 1h 1 @10 p1 1Ұ 2 x1 7h2 Ex2 S2 }2@ U2 h2 fH20 L2P {`2X 2 2 P3 p3 &x36 3v8 3 3 4& H4 4 4n 4 N4u _@4 ٨4* x4  3 3q 34 M2 H2 2)h 2"` 1p 81 p1d U 1J 00 (0 !0z( 01 01 }/ _/ /jH x/^ Jx. ,.H 0.ap0.ap 0.ap {.ap . . E@. q. . . ݘ/( ψ// `/6 / ̨/ 0 Ӱ/ h0X p/ 00P 0, R@0np D00/( e0/( 0M 00 08 0 0H %01 k1 10 :H1Vx %01M :H1[( dx1M 1%@ 1Hh 1p@ 1r `1 1h 1 @10 p1 1Ұ 2 x1 7h2 Ex2 S2 }2@ U2 h2 fH20 L2P {`2X 2 2 P3 p3 &x36 3v8 3 3 4& H4 4 4n 4 N4u _@4 ٨4* x4  3 3q 34 M2 H2 2)h 2"` 1p 81 p1d U 1J 00 (0 !0z( 01 01 }/ _/ /jH x/^ Jx. ,.H 0.ap 0#p 0#p ~/ rP/( / p0 0%^2h ^2h /2\ 2X 10 11( j82S j82d ^2h0 0 1" 20` ZX0 t 0` 0 X2@ X2@ 42y GH2p 2ۈ o 3 83! ch3$0 2X H2 2 `2m` `2Q@ 2Q@ 2k 2k 2G 2C0 (2 (2 B28 ^03 P 3( 139H !@3( 34 3 (2_@0H _@0H S0h @0ܘ "P0 0`00 S0 _@0H0 0 80 p0 0P0` P0` >0H Q00 {0H P0{0 {0 w81 0 .0 {1,80( ,80( (0X `0 0` ,80ǀ.0X .0X .0 @0@ .0p0^ p0^ 0~ 0b 80O 0F p0``0M 0M 0`` x00 0 H0( 0` 00 H0 0h 1C 1p@ ո1p@ 1 Ǩ1 1 H1` 1` x1x `1 ,p1x TH2+ ?02r X2x d2 u2Ԁ bX2 n3 @3` 3! 03 h3 3$0 3 h 23 CX2 J`3 S3e 3B 3P x3- 3 $X3; 3- &3; I3- P3Z p3I (32@ 3GX 83L P34 @3N` 3\p 3GX 3 3cx 3( 3 2X (3x ̐2 02( 2( `2 2 H2 H2k x2k 2@ x20p x18 2$ '2 Mx1 V1 |X1 i1Ұ ~1 b1 g@1_ 1 0 008 (0 "0 A80 0RP 00O 0H P0*x |X/( /p p/ / uP/̸ |X/ K / d/p A/s *P/v k/v g@/\8 |X/qP /g nH/G ]// w/&P?05 ?05 5` 5k 5[` 05ip H5] Ƙ5MP 5:ø5P ø5P 5` 85P q(6 66.P *6L p6Jp #67 6 p6 ø55 5 6 6H `6Qx X6V( 6> 6> `6 85D6 ( D6 ( uP6 6: 6> 6) 6 5 5 ¨5 6 85h 5p 6" h5p >6 ( [6.P X6: 6> 56L 6L 6'H X6O ,6rH x6d8 63 06 D6 (C6 C6 x6 H6 6H x6H >X6( 0H7 7 7P 6( 6Ͱ H@6P 56 C65 5 Sp6 6) 6 p60 60 9 6 cP5 cP5 K5 \H5ޠ q`5h U@60 \H6) -h6: 6S 6E 6V( Zx6Z 06E p6O `6: 6 X55 5 h6 ( 5 5h 6) 6 @ X6x 5?5 ?5 X5X `6 86 ,6 KX5 6@5 ?56 6 X6Z 6 f68 6.P 6Z 6 6 h60 068 7" h7H :7 65` 5` m5P 5` p5p m5 X5А 5ט 515Y 15Y ?5d /p5k /p5 5ט 5ט 5 5 05 15Y4h 4h 4(4 4 yx4h p4^@ H3h ~(3z 3Z 53h( .x3Z 3$0 .x3 3` h2 Q2 ]X2 p2 kh2 1P 1 `1 1p@ 1~P 1p@ 1Q 01' 01 x 0 01p J0h h0 0ܘ $0H \H0h o0P 0 100 P0 KX0 s00 0| 0P ?10 !(1< p1J 1< z1' Ƞ15 1" f018 1%@ 1? 1{ 1 1( (1 )@25 h25 1 10 81 K1 l1ٸ K1˨ z1 1 @2 p1p W1( 2@ 2Z 2} P2m` 2 2H p2H H3 @3 (3+8 3S 3h( B3 23h D3 Y3 \H3x cP3 K3 9 3 3 4 4H x4 8 3 3 {H3 G3a a32@ c3` U2X c2P 7P28 3p p3; 3ب 3( 4Dx 4 `4x 4hx. x. p/6 wX/;h / y/ ~`. x. 2' 2' 2C0 29 2U 2N 2' cP2Q@ U@2<( e2 2 025 2 2)h82XH 82XH `2\ (2y 82 ,2o 82XH82k 82k Hx2o ǐ2x 2th 82kI3x I3x R4(X 9 4F @(4` -h4W8 &`4g !4[ 4eH 48 4 I3x}3 }3 4 40 s4 jX4I( 4Y `4q W4x @(4x 4p4u W4M cP3 z3*3& *3& (3& 34 3I 3I X3q y3P 13j 3GX 3- *3&JH3` JH3` ƀ3` 3p 2 $@3` 3( à3e 3 9X3E p3E 3W 3GX 34 H3E tx3W G3 $3e 3- >3 JH3`4p 4p 5 5< H5' P4 5P 4p4lP 4lP 4 `4 Р4 4Ǹ 4 Р4 4 4h (4 `4( 4( 4lP29 29 H2+ $29 E2S 82fX 2U 291 1 1 H1 "p1h X1x 1ٸ 1 1˨ 1 h1x 1XX0T XX0T L01 mp0P 80P 0h 00F XX0T1T 1T )x1,H $1T 710 mp1( 501 P1 1F 15 0 0 0( H0gh 70: h0e 200 20p 0X `0 $0X G0 >0 JH0 0 0H 0@ N1p @1" 1A` 1T 1r 1r 1X 1p 1( P1p 1{ 1 X1 x1p 10 h1h h81` 1` s1 1rz2\ z2\ 2 e2 !2y z2\5~ 5~ @5~ D5 -P5 6 }60 p5X p5~T6t T6t Ũ5` 5 P5P qH5` Y58 \05 /5p #5 Ip5P 5d \05] &H5] p5< U(5C 5 #5p `4@ @4 4 04 P4x 4x 4g 4b G4& 004!P X4& 3 "3 ר3( ް3` 03` 3p 3 3 3` 3 w3 d3h( d3}@ H3Z O36 p3& i3 M`3( K3P 8H3L A3cx '3 .3 p3x 3x 3s @3cx 3@P h3@P 3 `3 j2 [2  2 2 p2 %2 .2 .2 32( K2 O2H R2( bx2@ Y2p |@2 i2` u82 ]2 r2 K2P 2 2H 02 l`2 sh2 Y2v eX2\ R2XH `2G F2C0 P2C0 822 @2> 2G X29 2 01 P@1Ұ 1x H1 ,1` |@1` 1 10 29 2\ 2 3` 82Ԁ P2( ް3p 3p x39H H3I S3E 3 2ۈ 2 ;2 42m` 2> 02 2 / 2 T2O02Q@ O02Q@ 2k 2} x2k L2\ O02Q@H(1 H(1 h1Ұ h2 H @2 ~2 H rX1p J1 ;5Y" <hY ; Y <X ;vX ;X ;&X( :XX :@X :~8Y 9X 9OX 9gPX 9Xɰ 9X 9hX :{X :HX :38X :OXX :ҘX ;X :X|X :Xi ;yXi ;ȰXT <`Xi ;X ;ȰX( SX B Sp BаS BHS ByS DxS DxS Dt8R DXSp DxSCTH CTH CҀT: D(T` D T3x CTHC HT׈ C HT׈ BpT BT BPT C"Ty C `T CLT C0T CfT( C HT׈:٠[ :٠[ :\!( 9\R` 7\(0 7N\X 6o[ 6v[8 6[ 8R[ :٠[>M8\ >M8\ <] M8\B]V B]V A] @]( @E ] ?]` >] @P] A] B]VI6\A I6\A Jp\u Js`\p Ia(\ J\ JF] J@] K ][8 J]f J]y J&] F]( EP]( D0] FX\@ H\R` I6\Aݠ ݠ  h ( h  wLP Y@_ u`9 Tp ph Ƹ P w s Hx T ( H : /x `  h @  P ` XEH nEH H& !9 ֈϐ  xP Kl 1^ #N \ qH c(` 0s x @xP dxP i` ?xU( = Bh R8;` ] p6 gP u`* px sX ݠ  x  =Ƹ p #@ h ?`(  8 x  ) <p 'hX J i <  0 ŀ ` eh K U P@ p - Z` q   7f IN 4G c00 Z8  P @8 @8 p H P (! A 6H ŀ1x ` 8X X sH xe8 T hI * `I 2T ysH 0sH %^0 % XB M u p U  ?x Op Pp PX lh ! (  ܈X Xu u v vuZx vHְ v@8 vPH v P v u` v!hְ v1 vg v|ݸ v^X uH{H upP uxo u u_( uʰ u4 u` v!hZx v>X vKQ vlh@ vI@ v P v& u uwШh wШh x%F xV@M xXe x7 xHp x" w  w0 w wp w0n w?X3 wD wPF wX8 wKX w=H w/8 w@ wp w w~ wX wШ w w wp ws( s( t<@( t(` tX t;x tƈ2 t` t>cP t58 sPx s s? Ϩ s s|x sP s  3x H Ho Ph h H P@  x  H ! ^0E  8 I @ mP* ٨ H x e Ux P@` P 8 ΰ2  h   .y :Hp { w8 `p )x Z  ` th (    pE  [ P p0h {  {V h m 3@ (0 5   8 (h   %0 50 " h   ( `  ( uh@ x 0 h  Հ  r(h r(h r,P qs0 r:| rT rP r  qX q r(hq9(^ q9(^ q4x qgx q9(^  3x H Ho Ph h H P@  x  H ! ^0E  8 I @ mP* ٨ H x e Ux P@` P 8 ΰ2  h9 9 rx >pظ 9   .y :Hp { w8 `p )x Z  ` th (    pE  [ P p0h {  {V h m 3@ (0 5   8 (h   %0 50 " h   ( `  ( uh@ x 0 h  Հ  Ѩ_` Ѩ_` h50 n @ ` `E ذk  D HH *0 R͈ &8 & (` Ѩ_`8 8 WXX 8d Wk Ș %: %: x`p X H ` p ,  ?P Hk h x p P  RX %3 #x7wШh wШh x%F xV@M xXe x7 xHp x" w  w0 w wp w0n w?X3 wD wPF wX8 wKX w=H w/8 w@ wp w w~ wX wШ w w wp wz̸?P z̸?P zk {n0 z z z z`8 zP zx z zhH z> z`'X z 0S z&P z8@ zBp.` zjH@ z^ z zpX zs zx zP@ z z { k zxi z̸?P}  }  }e }Q@0 }kH } }pfh }pfh }8mp }mp }@ }  } }  ~(` ~=h }͈ ~` }8 } }(p ~P0 }@- }X- } }- } } }`͈ }r` }yr }Xk }9 }$ } } ~`0 ~P ~E ~h(@ @ & * q F ~( ~( ~x ~ ~I X ~<8 }<8 }XX }Z }pfh{[ɘ {[ɘ {O0 {n0 {@H |Ӏ |]ڈ |b0p |MӀ |(( {h |. |(WH |"* |Q | |( |`@ |m8 |t |Hh | = |)| {8 |h {8H {5 {k {H {[ɘzg zg zD ze` zR zph zqP 0 z* z? zM( zhX zPO z  z z zǐ z  ze zg< < ' 8 'H h : _ h 8 8 P' P<ƨ ƨ  x @@ H߈  Ͱp   ? Yh Ը| gx z8 >0| 8~ `   p| Ͱ gx ^ I I 8 JpDP 6@ (0 %  h  ƨwN8 wN8 wq` wio wkP w0N8| t | t | yH | | { } | |y |h | P | t{o {o {8 |X { | {@ {x {  { { {{h {k {ot$C t$C tX$~0 t$ t`$ th$ tH$ t$ t% t$ t_h% ( tCH$ tZ%tS%0 tS%0 t)%9t.0%@ t.0%@ t]%)H t$ t% t`% tƈ$ t$Ā u $٘ t$ tp$ ux$ t$8 u$8 t${ u $i t$Ct+%9 t+%9 s% t0%@w`(+ P w`(+ P w[x* w1H* wF`* w|H* w*X w`(+ Puh1J uh1J u1wH u1y ux1X u1 u1` u1{ vH1 u1x uX1@ u1 u 1 up1` u1 ux1vp.X vp.X vx/ v/̸ w/ w p0 vX0 v0 v/x v/̸ v/ v/ v/qP v. v. vp.Xs51{ s51{ sM01X s*18tV1 tV1 tJP1 ty01 th1` tv1wH t1t t1_ t01i8 t1Hh t۠1Vx t@1d t1T t1d u13P u(1,H u9`1,H u-1? uB1? uI1Hh uE1Vx uZ01C uc1T us1[( uh1Jr2\ r2\ s020 rP2 r82xr3E r3E r3L r3 s*3l݈2 l݈2 l2 l2k lx2Z l2Q@ m h2N m2Z l2x m2 lX2H m 28 l݈2s*1 s*1 s01Ұ r1H s1 s81{r82 r82 r2 r2 r2 r2@ r82 rP2S rp2_Ps5 s5 s5( sk5ip s5*( rh4Ǹ s4p rܰ4; r 3( r3 rը3H r3ErX6x rX6x rH6 rn6 rn6 rp6m r6s,`3߰ s,`3߰ s 4!P s<41 s54n sT84 s54 s3h4 sT85P spX4 s5C sH5H sP6)u`6P u`6P u6 uh6( u7W ux70 v7u1 u1 u{2  uh20p uq2+ u2E uW2L uc2\ uL 2\ u\2k u-2th u+P2 uNx20 u2 u42 ul28 uvP2 u>2 th2 t`2 u3 t3 t3x tH3` t2( t@2( t2h t(2( t2p t2 t}2 t2 tk 2 tv2P tV2 ta28 tL2 tQX2` t@2 tJP2 t>2 ta2  tV1sP6'H sP6'H t6> s6E sX68 s@6'H s060 s5hr68 r68 r60 rܰ6E r6( r6q;N q;N q: r(:@ r/@: r%:p rK`:p ri:@ r:@v8X v8X v8( v#8 vB89R8 v9! u09H uh9 u8 uH8 u8P u08@ u8* uH78 u07>0 u@7) u7@ u6Pv7 v7 v 8 p u08! u88X v8ڰrp:@ rp:@ rΠ: r: r:X r: r: ru: rRh: rP:ː rx: r; q;Ne%+1 e%+1 e|x+sp ei+ e`X+@ enh,h eRH+ eYP+̀ eA+ eRH+ eT+@ enh+H ew+u e%+1cP,P cP,P b,P c ,` b, cX, b8- b-'` c- b-L c`-J b- c- c - b- b. b8- b- b{- b- b- bH-h bx-p b(- b-H b- b@- b-yh b-r` b-S b-Q b-J b-H0 b-: b-H0 b-.h b,0 b8-H bH-8 b-8 b(, bt, bx,x bh,޸ bw,` bZ,0 b>,0 b>,@ b, a, b, b0,( bQ,( b:, b>,n8 bf, bp,p b{, bkP,H b,x bƸ, b, b(-) b-) b-, b0- bH, b8, cP, b8,X b, cP,P_h,0 _h,0 _P-% _-% _Ѱ-Q _-]H _Ѱ-{ _-H0 _p-dP _0-]H _h-w _x-@ _- _0-i _@- _h,0`( `( `8( ` (x `(H `)  `)h `|( `8(P `(,PL ,PL ,e ,x -8p -, -)p -7ʨ -S -Ex -]H -m -t/p -( - -8R - = -eX -8 -h -h -ـ -PH -` .XM - -iP -"h - 0 -0 ,8 ,pƀ -'` - ,0P ,޸ -P ,Ԑ ,~P ,[x9X ,|HNp ,Np# # $f $p  $x( %>`h %(Zx %+ &UH+ &2 + & &X$ &G8 & & & &6h &( &-p %H %`- %8p &P &` &x ' 'p ' & &4x % %X $Xc $& #p& #1`X #H #x #@ #v #gH #O0 # #= #,ְ "Ӡ@ " ";H "z #/ #H%H1 %H1 & '( '  'e(h ( 'x8 &؈ &UHp &@0=H &=H %R` %: %M %H17t 7t 7  7m\0 81@ 8Y 8xK 8XK 8x4X 8* 8G4X 8&H 8X2 8* 8X;` 8p4X 9:p5|0P 5|0P 5 5P/ 5A1x 588T 5|0YP 5i 5O 5X8 63 6 6 7X 7m 7 7tŨ1 1 1 H 28 2PH 2@ 2"`ް 2E 2\p 29P 2Z 2m` 2{p 2d 2H 2Hp 3e 3 4Dx 4*H( 4it 4M8 4H 4n 4sX 4H 4 55 5p 5)( 6 ( 5p)( 6& 6 2 6~2 6H8 6 6p 7  7`H 60 6H 6 6 6ݠ 6h` 6o֘ 6O H 6h 6> 6: 5p 60 6<` 5h9 5h( 5+ + ,d -)ո - -:  -p %h ,˜ V ,P k - Q -m [P -~ -ـ y -P - -ـ p - ސ - ސ -x  -S ( , x , P ,P ` - $ ,x J` ,] > ,x  + x *8  *q ~x * J +^X ( + wp + O + g + 8( , : +p ` +u 1 +  +I@ @ +  +T + +P , +%P %P %x %9ʈ %ʈ % '  'H &l( &X &;z '!098 '8v( 'H 'F ' '8 'x (* (O (Q (ހ (P (6X (0I '/P 'F 'h8 &BRx %&h $t $Pi $HB %; % %$, $h $, $kp6X $T8 $X $7 $8 $P4 #B #x# #VB #!@ ";H8 "z #(h #H "x8 "x #h( "8 " #P #: #nPqx $,(qx $C %P0WUX 0WUX 0UX 1.o 0`qx 1@ 15 1dX 0@ 1Vx` 00h 00 0 1' 1mh 18 1H0 1ٸP 1X 2@p 2"`H 2h 2X 20 2 3N` 3 3 4uP 4ʈ 5:@ 6ʈ 6Sѐ 6<` 6X 6` 6 7) 7; 68 6Dh 7L@Kp 6Kp 6Ͱw 5 5RzP 4Kp 5w 4( 4=p 41g 4 3`i 3 3X 3sH 3h( 32@sH 3L` 2C0 2<(Kp 1(T 1| 18sH 0Hg 1pM 0Րp 0Hn 0OY 0 0Wߠ / /jH .H .} . .{8 .pjp ._\` -I -PGH -&x .G /n20 /P /}z /Z 0TUX8#` 8#` 9u`H 8uӰ : :p :kx : ;}X ; ; < <` >u =* >x ?p0 ? =p <0 =3 >J P ?y8 p0 2+HX 2C 2 m 3H 2( 3(P 2 3Sx 3 38( 38 4; 3@P 3x 2h< 2X( 2r 8 2J( 2m`X8 2 J( 2h 1r@ 1h 1Mh 1j 13P 0KHy /̸S 08G /Ex /W+ /Ű+ /@ /p 1)h / 0 / / /Bp /RҠ .` .EPH / .v .Xh -k /( .@p0 /2dx .Qf .[ -hM .t0O` .&,8 /\83@ ." //x .f  h .0 /G H /8 0  0 b` Y w ɀ Mx n 3 7 3 H #H |( H A *P *   8 n  T : 4 *P 8   x :  ! X !( @ 8  !ր p "D " h "Y "  "-8 *P ! , !@ A "-8 D "* V !f K !- Y0 p b !@  !  O h " ( @ i   @ א  0@= @= l RH @=W0Hx W0Hx p      5  ?8"p X h P zX0 @ W0Hx";H ";H !>(  !GP !p@ !p ";H+@X +@X ,  + +P͈ + ,,ƀ , +̀h + ,4 ,K!,HL ,HL ,%7 +Gh +> +n + +( +`H +ڐ +X +͈ +` +@X9:p 9:p 8p4X 9= 9D 8W 98X 88 7x 7t7qP 7qP 7X 7 7P87P8 7P8 6b6`X 6`X 5P 5 5A 5rH 5(5 5 5bh 5y5 5 5dBh 5`Px 4} 4Ǹn 4hK 5 5p 5 5# p 5 4RG 41LP 4!Pc 4; 3x 3` 3 38 3 3` 3}@P 3}@0 3UhxP 3 3P 3+8(3-~ 3-~ 2 2x2x 2x 22 2 28 2@@ 2Ȉ 2`@ 2x 22 2 3x78 3X 3Uh; 3Lc 3z4 3Ѡ00 3`p 4R@ 4`$x 400 4` 4x0 4*0 46hX 3h 3GX 2 2H 2v 2_P 2E 2.~ 1XH 15x15x 15x 1 0 0` 0w 0H0H 0H 1H( 1$ $ %( %Z %9 %< %C %)H( %  $hP $P $6" 6" 6"h 6`" 6S" 6"'wJ 'wJ ']@ '> (%XH}`}zOzO{^| |wH||((|0}})h}2}a}8`}{p(}ph}(wp wp xXxa0xdPPx>zx,0xf`xO8-xtWHxanx`qxxx(Hy&HyLXXy\xyP5z`5z [pz̸?Pz(Jz(Jy\LxxxP{xP{xx{[ɘ{[ɘ{H| |:X|dH||}X}C0|8LP| | }'Ƹ}>H}ظ}ظ|~P0~P0~q+H~\p;}2P}B}eApApd?wu %xXXpqͰͰ`rHV(7ipz8ipz8[`Yhp`@K'H`k@N84p@@(xx`x`xx߈yzDzY{F9 |Q|{|8 {P{@{)@z@zyykhyݨ hy$ {`a{`a{np4{H)@zD҈ypyX0ykhyP"y$ @PE`PE`j0aHUpc}\}@JxH`h8]X{ Sq) p0 9 r R($h 3p x` x.P @p w. p ~Ǹ 1X R` BH 2x 2x @ T 3Ͱ x5X  |X8  ~X 1X PX ? H ? ?%x !x p rxrx"31@xΐXӀ)`Ӏk0pظp߀pUxE( DXzNzNe(H8Ph@0x`i+b0A ,!(H;(؀؀w:(hR.ϨϨ8He0Ϩn `(E`xA8-x3(p 8 H X D @l H XB P ڠǠ XhXhDH8 qXi&Xe @,/80#}P7Hxrh3 jXpW6yX`ְ׀H HXHCX*jXM8p8`(0hMRpgxYx|(whX(ܨh.u(H@p0-<8&QPx& h@LhvH%ظk0p F|,{``Xp ڈs *8((0(mx]@d"`@h@687Yx|Yx|Me KXX#h8H0#l<Xe0ְiʀLhxϸ@ f>$5h 0 H@  D @jh ӘD` zH u ň ҈҈HtCc uP  X8(}Px@~ x@gp0` x>eP8&XH 8bpX, p|uKXs`!(B(ʠxvWKlp/otpPXP9 Y0 8`' %X  p <  (:` NF m x ' {h aH%H I` P#x 9pX  ( ( DH -@ :` I wP F N~X eph M 8 P h 5( #H' K ` 3Nh ]S 8 s`XuXuX pL 8Nh d 69 Mx`PG(x- h hxQ* *(_w>,[H=H0gxK1[KXE`pˆHHH0`0`pE 0 0| " x @{ X H u wp wp   Hr $ P  " 00 g0 g r0 88 = E( k0( k0( k04p E0 ( ސ u i` 1X 1X R(h b O `h b1  xh 8 P( ( ΰ57A8P]X~(r@(`H҈8ˀCX9ِhP@")\݀҈6=pzxs-hLhhf0`U`8H.x@ yxGkh VP :0[LF )JΘ 3 # K ؀ l \  ݀ p 8   8 X 7uuv]("XΘ((*^F1(@/8x3G#d/8_`x{/88P2PPZ(8?  M[uxPH;xG0V8:0V8h%Xxp<V8H|@pxˀp|HsPXX0O P 8 , Hv Y &(@ 0 {w L0 * X( 80   7%ƀ%ƀMp&xۘ2`h Bm@@VCGHpx(H@^0pw3xDP(:1pZ@p&P@(?hoHyxYYx (*8HԐ(8}P& ˀ`@kbVJx]Xx:0xVPJkhyx @p0>@ɘ=ɘ=H=PQ30Sh PQ{Hh9Qr8r P `qh@S 7P xr 8ph+X+=2RjPjq`cRG0cPyx^]Xsx6oDepXX9 \H-۰hP !`!`%k[p g(FXP]?PH`mrp Qِ9X0H0sE`+H@(uGh7XLc%PsT0CàdT0(6xFeXx >::0ThKh8``h 8>>>>X:HXް 8 pp~DH 3 3#0Hp h-xX`26xn4 x0xUx2P*pB>>`~HpxPPh`y`8Hר'Xy`xK <h2x_cp4p+EH28s6xӸ#3 H#h@8̰phP(Z(7*pErPrPq&spLh@7Px4DpZxe@LhZx80_(XJxh5P$Xxxd0)@"80>(X.xx  d0 x T .H Jh Xh H HB N ^h0P  7  @  d `  6 IPj \o` \o` \x F ps X p( X8 VX C  `- H SH SH %  @ x P WP @ Z@ P ͠# p }H Qh(%(%X-SPP(H(Ph*P(HpIhKǰg((/`V`Php ,8X|pF^8Kx8x`܈`PÈp(P0H}8fHWS60`-.  0t0 (l@h)3Hi`,@MސOhxw@x8ٰ׈8xGvhH ߨr=hphgp)I ] (PԨT&;DpxpGPFppи8`"{hppMj@H0]0HuHW0>o(pX#)  cy1 7! H (!U!P!*"K-H#Ih#(=$ \($$E($w($P$$$h$Xp%5!%U%m@&@%%00&W&q&j' U'ZX'Bop'e('e(''`}(H(V!H!H"H"8"6P"֐##bop#R0c#N#pU#-#h@$% $% $$'x0$~0p$0%hV0%h>%%&(&e'P&&.X'@'?E'nO('(o'ܰd@(.(!@x!'P!P$!Cp!PO(!@!@!!E"L"("Wh"n("@"ڨ(`#@Up##P-#T$8#s!#6#>$"4$ $8$A@!$A@!$A@(#8#-#?ps#8@# o o 0 0f ͨX ԰ H  X!8`!!2p !x"8"P`x"&#c# `#V#nP#p#^#8#(#i`#|`p#`@H#i#M:#K(՘#]<#xb8#|`y#x #h˰#x#|`#(C8#y $@$H$5 $50$L$L $,($'xa$"h#@ '@ '@ '@} {@Xޘv0@@L<'~ẍe@?XјxP@p81 MۨlHX8`r0(EhEMH (` ) f  !8P!-!}p3p!!@"p"6e0"Kl8"ex/H"h1#w#Y8i#pn#B#`6P$P $0=X$J(@$OP $J$<`$73$PB#`l8#u#Y8p#A/H#,"W "zRp"j(g"exe0"K"-8@"6"("`!@!{!0!    : h.8VP@28286 h }8HxhH0hH08@CPL ($($5@8pmX0NUk|iX    @?(P`8IXp<c٠~8Ҩ{.t%88 ?q8 Nhn}g`yv~Hyv~HxHPx0xpx,wˠx08x8'w(Gx]Haxp{hx: w(wɠDwp^wPhw(x`@y@y2Ry\yHzXyhz@z!z&PHz=z^zWzvz{`<{3k{*x{M p{ 0|,H V |m yH|( f})h 0}v `}x 0}fX Ơ}X y5y5yXy{8'y\x9xr`x.hxـ xـ x xyyPXyzHzHz#Pz928zqPGPz\8cpzqzz zh1z80{KH`{?'{]{Ր|5|H|ɀ|0|Ġ| 5P| f{{{H`{60 {[H{]| xP|5|H|ɀ|x@|||8|8 "|_ S|X me1xϐe1xϐee e%e8hpe00ed8d\0A c PcCxcjdHb{bdHahu15u15t0pt08t`0itX03td0#ptp0:t20t /̸tG/hty0/xXt.0/tV.Nt -s-0s-Qs-'`s,ɠsu,~s,]s,3t58,HtE,'tP+PtP+ht+t+`tX*Gpt0*t8)ht`)8t)dtx)t(t(_uW(:puh'uh'uP'#uP&u4&pu &t'ty0't{'3t2'Ht'Xs'us&sp&0s&zsH&Ks&Bsp&`sx&@s%8s%Xs%t$Ct$Ct`#t0# tx#gHtP#D tP#t#%tv#8t"Hs"\s`!8tX!aPt! t sp Ơsh r@s +s s s t  (t  ot_h 8s@-,s@-,s,˜s,s,ys,Dwi+ Pwi+ Pw+Fw0+Yx+spw+8w,w`(+wMh+wh+ v+vx+@vsp+vK+@v/x+v4(+Ru+8uè*u*0u*juh*^u*+Pue*uP)ua8)u) tx(wV+gwV+gw.+?w:+ PwO+wD*k$,Y k$,Y kH,ika,Y kr@,:kXx, k,jא, j0,'ju ,Mhj1(,`(i,Hi,]ix,5iKx,=i,]h,h,(h^,gP-Hg-0g-f-f-'`fh-f_,(fx,fx,f ,e,`(e(,ieb,3ei,ei,Kei,Ke(,ke`,n8f , f:P,fb(,fb(,f-8f-f.hfp8.}f5.f .e.`f3H/(f3H/(f7.fr.f.f-hf-)f-g>x-g-3g-h-h-hU`,޸he,hq,˜\ ,r\ ,r],D\+x]*+]F +]+]+\]x+K]p+*]+&^>*(^v*^P*{_*_W*_`)_)_)0` )`j)X`)2`X) ]8+*]8+*] +- ]+I@]+\^+^+^h*^v*`^*s^H*>^H*>_*_W*_`)X_)X_)ƈ`)`j)X`)d`)d`)0`h(`h(ap(a8H(JbA (@b(%Xb( b( c$x(pc$x(cG(Hc9)+cX)@c\)ac)c)d**&dG*pd`*pd*(e#h+*cx)y0cx)y0c\)Vc;)+c;)+cI)c (c (b(xbx(b(kb(kb(Pb((Pb((PbCx(@b5h(b5h(a*8(Va (iPa (iP`(`x(c+c+c+(pc+(pc+B8c8+?c}+`cf+`cX+lhcLP+@c++c-+pc+c, c,#8ch,,b,.b,Y bH,wc,a)a)a8*!a(*Bb:*Z0bO0*bt*brX+b(+!hb+PHb+b+Xbp+HbJ+b]@,(b,1Hb>,n8_+^X_+^X`P@+&`+`*@`*(a`*oHa*a.*aR*0aY*ʰaFX*ѸaFX*8a[p+aR+`aD+Ha[p+ha]+̀aV,ai,[xa[p,wap,a,(ah,a,Шa,a,0\x+(p\x+(p\?+\l(* \%*\:*}X\#*e[*vP[H*e[*@[`*+P[Y*@[K* [H*Z`)ZX*0Z)Z()Zt@)Zx*(\,+`\,+`\6@+\i+\n+\+R\+\h+]*X]3`*]F *j],X*0\*+P\x*0\)۠\Θ)Ԙ\x)\`)8\%)S[)[h([([xh(([B(([(JZ`(M0Yˀ(`Y(Y(Y(]ZP(XZ(F(Z(M0[D([z(0[x([8(([([)s0060s0060s/ sH/Ps/0r/0rX/sre(/srF/`q/qPq؈/Pq(/qPqh/q@/vq/;hqG8/nqX/gq /p/p / p</vp+/eo/go@/Ro_/U0o0/+o]`.o]`.o,(/+n/n//(n8.m.m^p.m-8/m/ m/@lx03l 0Hl0Hl`18l1l1lq1xlX2k(2m`k2kH3Pkp3`kk83kp4j4&j|(4[jO4`j[X4xjJ4jh4qh7Xqh7XqcX7@qX70p7p7q@7tq7Up7-pָ70 p`6p6p6p(6~p6q`6~q4x6V(q+6>qP6'HqW5pq5q5Ɉq@5q5TXq4q4Yq4q(3q/3zqX3Lq!2q2q22p`1p1p1Jpx1 p<1pp&0Po00o0boP08mx0Wm@0|m0ܘl1lր1yl1 lH1l1 l@1`l1JlX0Hl80pa1(pa1(p7X1o0Րo80npo`0?n0KHnz0bm@0npm^p0Pm0@l1(l1_m1rl81rl1pl02Xk(2kP2@kH3rh4Hrh4Hri4Hr?4 qߐ4Xq4Hq4 p57p57p7X7p (7o 7po_7`o>86oX8o8Řo90o9Toy9hoH9o:]hp0:p2; p;p;<q;>hq;SqG8;Cq0;_8q;Nr:@r:@r:>sP: `s:t9Pu :ux:{vH:v/x;@v;v;Xu:u:v:v&;8ve`;Q(v;09Y@v;09Y@vD9Hu:hv:mvB8:vF;)PrAUrAUrArArpArpAr6HArBqBqBFhqBKq=B.qBApPB8XpjApAoAgomA`op A o]`AoA@oAIHnADnAnAn?pA=m̘AmAmuA;8m`AYm(AFlqA6lhX@l@@pl&@lAkxA#80``80``9H0``9M0=89T09/9x/09h/-X9/9/9.:X-:X-:J-:M-8:V`,h:J,9,?X9+9+9 +P9x+sp9`+T@0!@0!?0D@?H0!?0X?/>/H>/H>n/Ű>/`>/Ix=/D=x/&P=.=.B=.&=X.=0->->H-i>g->>-5p> -? - X?CP-7?o-)?fx-?t-?-?H,(@-,`@P,@,@,@`,w@,k@x,3@,=.`=.`>8-> @->Q-i>r->>-: >-?$-'`?@->?m-.h?t- ?-8?0-?͘-8@0,޸@S0,@,8A,8@X,x@,@,D@8,0;c9;c9;`9;9~;9= ;j98;<9:8̠:8P:w08p:i 8j0:.8 :AH7:7:p7:f7:]h7SH:570 :AH68:06 :AH6h:%(6Ը96:6yP96H:6):6096095H959595(9595~95`95O9@5,9@5 94949(494(:4:%(4:.4`:54-:f4!P:y40:P3(:3:03(:3z:3Uh;53P;j3/;y3Uh;3;Ȱ3;3X2>M82Ԁ>u28>2 >2?2?S3@P?JX3h(?Xh3I?03@-3?h3x?3?3Ð@ 3?x3@3x@3P@3x@3hA(x3lAn3o0A@3GXA3GXB 3!B3$0B x3/B`3N`B03IBH3-B 32@B03C%2CE2Cyp2C02ԀC2C2Dp2DSh2}D2DQ28DJ2HDv2HDQ2D82HD2D2D2hD2D2D2D2D2Dq3lDx2xE(2hEW2 E2Q@<=0O<=0O<0,=00:=;0=Yx0/(=s@0=(/=0>80O>*0=(0`=15=x1i8>H1`>n1>X1?@10? 1h?1@2 H@p2A 29A*2yA3A3+8B x3(BFh3+8B3BBH3(B 3+8B3`C `2CA02C2ۈC82D2 Dm02xD2D2(D2D`2pE2hE=2E2L:Ĉ3W:Ĉ3W:3=:H3/:p39H;$3N`;tP3/;3a ;3;@3X<;3<3Ѡ< 3xX2>?(2 >~p2ۈ>(2>28>2>2H? h2?3cx?Ɛ3@;3@3s@x3`A& 3jAc3jA3BAlp3BA83;Au3-A3BA3=A3-A3!A`2AM2A2vA2>@j2@@p1ٸ?1?r01?5@1>1>1>n1807)807)86868=58h5'747ֈ4I(748;P3߰8\ 38j04 89V4;9w4@9`4 983:4:,03`:V`3:3D9D9E9xE69Ev9[Ex8HEl7E7E7tEP7\E`6FP6F/06HFM6`F60E߀6E 5E5`F5FHFF5<FRX5pF,5 XF4E4qE 4bE4/`E@3E3ѠE3E3E3F`3F6834FRX3UhFgp3N`Fs(3+8F`h3xF*2\F*2\F#x2FKP2F`h3FP2F,2_PGx2kGx2kFh2{pF2oF2kF2XHF@2m`F2rF2F`2F2F2hF20F@2F2(Fܠ2F2Fp2Fp2G 2(G (2oEX;UEX;UE; 0E: E8:F,:)F`h: F9hFΐ98F9,F`8(G%H8G 8^xG 7πF7G7IGb86G˰6 (G5 GP5G5kGh5?@H. 4HL4HE4HS4Hd4HHXP4Hmh4HN4gG4`G˰4MG3XG03;G2G2PGp3Gx::@Gx::@G9G90G9G9AH9/H. 98pHS9PHQH98Ho8Hv8Hmh8H_X8=H>8#H$7xH@7H27HJ@7aXHS60HN6Hr6ChHh5H05ޠH5xH(5|0H5dH5FHHې4H4sXHQH4FH'4YH'4YH4bJ;oJ;oJF:JP:J!X:7J|:J9KX8KX8hK'8`K 7K.70Kg 7\K7"K6Kp6K86L.X6LO(6 L6L6pLư6k@L06hL6JpM60M;6 @M@6ChM6_M6JpM 6aM6d8M6xN6(N74I^<I^<IS8E^><E;p>QE+>8E>E>D?hDݰ?ԠD@@@D`@>Do@BDC@D @qCX@C@CҀ@C@C@C@@lB@@oPB@Bh@Br@B`0A^`B'AB'BFhAژBABACO@ACACxBD$BDACACAC{ABA@B׸AB׸AB@BBVB#@ABY(A`Bi@0B@B@B@eC~ @D@hHD;@B>hB>hB? hC?7CC?hCX?B(?HBx@B@Z8B@oPEcH:EcH:EcH:pE2:D:~8D:{Dh:D:`Cx:@C(;2CO@;LxC]P; C.p;hC]P;CdX<CL<@8B<C<0C<C@=C"=hC H=CL>:xCQ>dCk`>yC_>C(>Ct?)C3 ?VJb=Jb=J=e0J=;J=;J^H=%J^H=%J =Io8<ʀIo8<ʀIG`:7x9¸_98p9q8px8hp8(>@8I8u>@84H8q848;8Hhp98p89\:5t(:N:(h;f@h;:0/:0/: \0:En:Q:t@:AHRH:AHp7q7q7qP555y7+pU7+pU7x7HH7p808-@8U84xT4xT444-4@TP4=p4(Xɀ4 C`4B 4H 44!...X/4`a/Yh//X/g(/6/( /(q/@00K0@1(1[(YP1?0ܘ`00Έ0'0Pt0p1p`101]1<o11811xx1 =1@jx10\h1 1wHј1_1b0#1 [18h1pp0P00X00@[X0000h0 A0 m0 yH0 0 0ǀ 0Έ `0h 1y!81wH!&1`!f1H!65Xp65Xp5h@48ʐ4^@4!H3x%3H133Sp3$0sP2W02W02yB2\#2ox202 2a2a27xh8up8up7ݐup7V7F7}xs7Uw797p79X7&6:P6P6"6 J6rH(6`5 @585Q85Q85Y'5p< 5P.407p44|4T 4?4K"X3p)`3E303o0t`3I3-3202H282th`2}(2E82E21p1 x(pXP(pXP(8>x(\)J0)<@\* *p+4(+sp0,`,H8,a,˜c-_-x -=-I-HW-h -Z.X.$.-.Zh8...//Rh/p/P0P(P080A^80YX000@x&&h&&h%X%(8%(%X%h%Z0%dH&\P 8&07','s8J(k(k)E()P+- X+- X+6w+g{+Ƹ+x+x,4X,*@(,KG,X,X- @-t -.7@p.7@x.vr....`x//2 /xh/@ˠ/ /0  0KHC(0h.0C(1?H1]"x8"x8"h"p#Fxx##(Np$ $kp!$x%9x%X&(&&+H'P'[x'((9X)QX;) ()8*Gp*Wx*@++6ۘ+`+q+x,O>,O>,[x9X-0-0-E}-G-`-(.S`~`/r/./,X'XH'XH('H(`(Xx(pH(x(8X(F(#(1p' A' u (%X(Q)2 h)r(!$`)x!S@*7!x*\!U*{!*!+- !P+|!ZH+(!,8P"K,?X"X,r", # -x&t`&@0%&%&%qa%h`%8% (q$$Pʐ$t0# # #F$0(##@# %p$b`##א##:(#:("P-!Ѱ!"" " "(Y"?[p"BP"!(!݈'X!!o`!&@!  0.` ۸5h ͨ]@ h h!I!^!" !}p00 HSX SahXUhpy_n7880`&X0&X0&P=&-pY%&%0X%he%Ng%X(%>`$0$0##`#@̰"n"(""|"ah"p"8"YƸ!  !  0 0  Xxh O 7ޘЈ (x:Pޘ $<  "mX {hHxHx+0.qǐߨMC H 0!hX!HH"!H"iH"l3`"h"""Őn#8hR`#``p$,(8$/8$%aP%Q h%pp%@%p%Jxh$hG0%8G0%/$P$$$p$kp"G"G"?    yHx..`9 Jh} yHx#>X...; @  x g@ [p %2 b( (? zH ^h @ 8 F 6 ݀# PG  ( j@ `x  \F uw@ (7p  #H"X [ p # `T ppppi0Pvx0zph (߈M ehN8P# 8   O}ܐܐpupRH8;x8;x`(m8Sp4pXXXAxw FX<1@%X @c 4 P h` |Xp Y0JH ` HR` ߈ ?h ?hh Mx b` r   X 8 0 h # ` ø5 Z@m U @ h PSp pj J`t@ 5H  _( XqSpΰ((Sp Jm8 f0  5H Eq Sp >X `h Wkh HC  !x и-E-EDpEE4h`ED@E2E{hE/{hEBx_HEI5E-` DDXMDq.DP DN@D-HD>PiD+K@D8D-DZpD2xD+hD`c8DxPDHYDplEPxDpBhD(7A?7A?AsxЈA8kAA#A=A8A@AAHpApB B,X@BdxBBPfC C<C.C(CD(D-nDXnDXWD֨9D`;`D#D*Dp9D`Xastir-Release-2.2.2/xastir-lsb.spec.in000066400000000000000000000062761501463444000177320ustar00rootroot00000000000000# NOTE: # “Free Standards Group, FSG, Linux Standard Base, LSB, Free # Standards Certified, LSB Certified and the Free Standards # Certified logo are trademarks, service marks and certification # marks, as appropriate, of Free Standards Group in the United # States and in other countries.” # # We are in no way representing that Xastir has been certified by # the FSG. To do so costs real money. We do intend some Xastir # binaries to install and run properly on LSB-3.0 compliant x86 # Linux systems though... # Summary : Amateur Station Tracking and Reporting system for Amateur Radio APRS Name : xastir Version : @VERSION@ Release : 1 Copyright : GPL Group : Applications/Networking Packager : Curt Mills, WE7U # Icon : src/xastir.xpm Source : http://prdownloads.sourceforge.net/xastir/xastir-@VERSION@.tar.gz URL : http://xastir.org #BuildRoot : %{_tmppath}/%{name}-buildroot BuildRoot : RPM #Requires : #AutoReqProv : no PreReq : lsb >= 3.0 # # # Stuff gleaned from the LSB appbat RPM build files: # # Force a 486 target #buildarchtranslate: i686 i486 #buildarchtranslate: i586 i486 #buildarchtranslate: pentium3 i486 #buildarchtranslate: pentium4 i486 #buildarchtranslate: athlon i486 #buildarchtranslate: k6 i486a # # Overrides for LSB packaging # We want a non-root build. Just put everything in the same directory. # Only _rpmdir and _builddir are actually used in these builds but we # define all five of the directories for completeness. #%_topdir /home/archer/xastir #%_rpmdir %{_topdir}/rpm #%_specdir %{_topdir}/rpm #%_builddir %{_topdir}/rpm #%_sourcedir %{_topdir}/rpm #%_srcrpmdir %{_topdir}/rpm #%pkgroot %{_topdir}/rpm # #%_messagelevel 0 # # Replace the "buildpolicy" defined in the distro's brp-(distro) file. # Forces uncompressed manpages so the specfiles don't vary. #%__os_install_post \ # /usr/lib/rpm/brp-strip \ # /usr/lib/rpm/brp-strip-comment-note # # Unpackaged files in a build root don't terminate a build #%_unpackaged_files_terminate_build 0 # # Missing %doc files in the build directory don't terminate a build #%_missing_doc_files_terminate_build 0 # # Force gzip payload #%_binary_payload w9.gzdio %description Xastir is a graphical application that interfaces HAM radio and internet access to real-time mapping software. Install XASTIR if you are interested in APRS(tm) and HAM radio software. %prep %setup -q #%patch %build %install %clean %files %defattr(-,root,root) # Documents: Go into special doc area at /opt/Xastir/share/doc/xastir/ %doc AUTHORS ChangeLog COPYING DEBUG_LEVELS FAQ INSTALL LICENSE %doc README CONTRIBUTING.md README.GIT README.Getting-Started %doc README.MAPS README.sudo UPGRADE COPYING.LIB.LESSTIF /opt/Xastir/bin /opt/Xastir/share/xastir/help /opt/Xastir/share/xastir/config /opt/Xastir/share/xastir/symbols /opt/Xastir/share/man /opt/Xastir/lib/xastir # protect user-installed map and other files from being clobbered %config /opt/Xastir/share/xastir/maps %dir %attr(666,root,root) /opt/Xastir/share/xastir/maps/GPS %config /opt/Xastir/share/xastir/Counties %config /opt/Xastir/share/xastir/fcc %config /opt/Xastir/share/xastir/GNIS %config /opt/Xastir/share/xastir/sounds %changelog Xastir-Release-2.2.2/xastir-min.spec.in000066400000000000000000000044271501463444000177310ustar00rootroot00000000000000Summary : Amateur Station Tracking and Reporting system for amateur radio Name : @PACKAGE@ Version : @VERSION@ Release : 1 #Epoch : 1 License : GPL Group : Applications/Networking Packager : n2ygk@weca.org # Icon : src/@PACKAGE@.xpm Source : http://prdownloads.sourceforge.net/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz URL : http://xastir.org BuildRoot : %{_tmppath}/%{name}-buildroot #Requires : %description Xastir is a graphical application that interfaces HAM radio and internet access to realtime mapping software. Install XASTIR if you are interested in APRS(tm) and HAM radio software. %prep %setup -q #%patch %build ./bootstrap.sh %configure --without-ax25 --without-festival --without-gpsman --without-graphicsmagick --with-imagemagick --with-internal-shapelib --without-libproj --without-geotiff --without-pcre --without-dbfawk --without-map-cache make %install rm -rf ${RPM_BUILD_ROOT} %makeinstall # Docs go into package docs area instead of the Makefile install # locations listed here: rm -rf ${RPM_BUILD_ROOT}/usr/share/doc %clean rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root) # Documents: Go into special doc area at /usr/share/doc/xastir/ or # /usr/share/doc/packages/xastir/ %doc AUTHORS ChangeLog COPYING DEBUG_LEVELS FAQ INSTALL LICENSE %doc README CONTRIBUTING.md README.GIT README.Getting-Started %doc README.MAPS README.sudo UPGRADE %{_prefix}/bin %{_prefix}/share/xastir/help %{_prefix}/share/xastir/config %{_prefix}/share/xastir/symbols %{_prefix}/share/man #%{_prefix}/lib/xastir # protect user-installed map and other files from being clobbered %config %{_prefix}/share/xastir/maps %dir %attr(666,root,root) %{_prefix}/share/xastir/maps/GPS %config %{_prefix}/share/xastir/Counties %config %{_prefix}/share/xastir/fcc %config %{_prefix}/share/xastir/GNIS %config %{_prefix}/share/xastir/sounds %config %{_prefix}/share/xastir/scripts %changelog * Thu Jul 03 2003 Alan Crosswell - 1.2.1 my patches now integrated into the main trunk. * Sat Jun 21 2003 Alan Crosswell - added xastir-maps.patch * Mon Jun 16 2003 Alan Crosswell - 1.2.0 * Fri Jun 06 2003 Alan Crosswell - June 5 snapshot * Thu May 15 2003 Alan Crosswell - start with chuck's spec file for 1.1.4 Xastir-Release-2.2.2/xastir.1000066400000000000000000000043561501463444000157520ustar00rootroot00000000000000.TH XASTIR 1 "HI8GN on Apr 09 2002" "By Jose R. Marte A." "Xastir APRS(tm) Client APPLICATION" .SH NAME Xastir \- graphical application that interfaces HAM radio and APRS(tm) internet access to real-time mapping software. .SH "DESCRIPTION" This manual page briefly documents the .BR Xastir commands. .SH SYNOPSIS .B xastir .I "[options] Language ..." .SH OPTIONS The program follows the usual GNU command line syntax, with long options starting with one dash (`-'). A summary of options is included below. .TP .br .B \-c /path/dir Specify an optional config directory. Defaults to ~/.xastir .TP .br .B \-f callsign Track callsign .TP .br .B \-i Use a private colormap .TP .br .B \-geometry WxH+x+y Set Window Geometry/Position .TP .br .B \-l Language Xastir remembers the language once you set it the first time. .TP .br .B \-m Deselect Maps .TP .br .B \-p Disable popups .TP .br .B \-t Internal SIGSEGV handler enabled .TP .br .B \-v Level Set the debug level .TP .br .B \-? Show summary of options available. .br .SH AVAILABLE LANGUAGES Current choices are: .br .B Dutch English French German Italian Portuguese Spanish. .SH Usage is: .br .B xastir -i -v 2047 -l Dutch & .br .SH SIGNALS .B SIGINT, SIQQUIT, SIGTERM Cause Xastir to exit. .br .B SIGHUP Causes a restart. .br .B SIGUSR1 Causes a snapshot to occur. .br .SH NETWORK PORTS Enable these ports on this menu: "Interface->Enable Server Ports" .br .PP .B TCP:2023 Bidirectional TCP port for clients to connect to. Requires login if client will be transmitting. .br .B UDP:2023 Unidirectional UDP input port for clients to inject packets. See the documentation for the format. .br .SH "SEE ALSO" The program is documented fully by .IR "help-English.dat" , available via the HELP menu option in Xastir, plus the various README and INSTALL text files that come with the program. Also see and the Documentation Wiki there. .br .PP .B Xastir is a program for APRS(tm)... .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2023 The Xastir Group .SH AUTHOR This manual page was written by Jose , for the Debian GNU/Linux system (but may be used by others). Xastir-Release-2.2.2/xastir.spec.in000066400000000000000000000053671501463444000171540ustar00rootroot00000000000000Summary : Amateur Station Tracking and Reporting system for amateur radio Name : @PACKAGE@ Version : @VERSION@ Release : 1 #Epoch : 1 License : GPL Group : Applications/Networking Packager : dranch@trinnet.net # Icon : src/@PACKAGE@.xpm Source : https://github.com/Xastir/Xastir/archive/Release-@VERSION@/Xastir-Release-@VERSION@.tar.gz URL : http://xastir.org BuildRoot : %{_tmppath}/%{name}-buildroot #BuildRequires reflect Centos/RHEL naming conventions - edit package names to suit other RPM-based distros BuildRequires : tk, tkimg, lesstif, libXp, libXp-devel BuildRequires : geos, giflib, unixODBC, netcdf BuildRequires : GraphicsMagick, pcre-devel, proj-devel, shapelib-devel BuildRequires : db4-devel, perl-HTTP-Lite, perl-Device-SerialPort, perl-Test-Simple BuildRequires : perl-Module-Build, perl-Image-Size, perl-perl-GPS, perl-Tree-R, BuildRequires : perl-Geo-Shapelib, perl-Test-Simple, perl-Module-Build %description Xastir is a graphical application that interfaces HAM radio and internet access to realtime mapping software. Install XASTIR if you are interested in APRS(tm) and HAM radio software. %prep %setup -q #%patch %build ./bootstrap.sh %configure CPPFLAGS="-I/usr/include/libgeotiff" make %{?_smp_mflags} %install rm -rf ${RPM_BUILD_ROOT} %makeinstall %{__chmod} 4755 $RPM_BUILD_ROOT/usr/bin/xastir # Docs go into package docs area instead of the Makefile install # locations listed here: rm -rf ${RPM_BUILD_ROOT}/usr/share/doc %clean rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root) # Documents: Go into special doc area at /usr/share/doc/xastir/ or # /usr/share/doc/packages/xastir/ %doc AUTHORS ChangeLog COPYING DEBUG_LEVELS FAQ INSTALL LICENSE %doc README CONTRIBUTING.md README.GIT README.Getting-Started %doc README.MAPS README.sudo UPGRADE %{_prefix}/bin %{_prefix}/share/xastir/help %{_prefix}/share/xastir/config %{_prefix}/share/xastir/symbols %{_prefix}/share/man # protect user-installed map and other files from being clobbered %config %{_prefix}/share/xastir/maps %dir %attr(666,root,root) %{_prefix}/share/xastir/maps/GPS %config %{_prefix}/share/xastir/Counties %config %{_prefix}/share/xastir/fcc %config %{_prefix}/share/xastir/GNIS %config %{_prefix}/share/xastir/sounds %config %{_prefix}/share/xastir/scripts %changelog * Fri Jul 8 2017 David Ranch - Updated to 2.0.9 with Git support * Thu Jul 03 2003 Alan Crosswell - 1.2.1 my patches now integrated into the main trunk. * Sat Jun 21 2003 Alan Crosswell - added xastir-maps.patch * Mon Jun 16 2003 Alan Crosswell - 1.2.0 * Fri Jun 06 2003 Alan Crosswell - June 5 snapshot * Thu May 15 2003 Alan Crosswell - start with chuck's spec file for 1.1.4 Xastir-Release-2.2.2/xastir_udp_client.1000066400000000000000000000057711501463444000201620ustar00rootroot00000000000000.TH xastir_udp_client 1 2019-05-01 "The Xastir Group" .SH NAME xastir_udp_client \- send simple messages to xastir for APRS(tm) network. .SH SYNOPSIS .B xastir_udp_client .I {-identify | [-to_rf] } .SH DESCRIPTION xastir_udp_client sends packets into the UDP listening port of an enabled xastir instance. .SH EXAMPLES xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "\-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 \-to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the \-identify flag: xastir_udp_client localhost 2023 \-identify .SH NOTES This is a very simple utility that provides no validation of message content. The text passed as the last argument is directly injected into Xastir's incoming data stream and processed exactly as if it had come out of a TNC. As such, the text passed to it as "APRS Packet" must be a complete APRS packet, including FROM and TO call signs, not simply the payload. Thus to have it work properly, you should pass "MYCALL-0>APX219:payload goes here" as the string, not "payload goes here" (where obviously you should replace "MYCALL-0" with your own callsign and SSID). If the APRS payload provided is an object or item, and the call sign and SSID provided in the packet header match Xastir's exactly, then Xastir will "adopt" the object or item and treat it in the same manner as one that had been created in its own GUI --- that is, the object will be retransmitted with decaying intervals until deleted. This can be useful if one wishes to create objects external to Xastir and have it take control over them, but can be a bit surprising if you weren't expecting it. If you want the objects treated as Xastir's own, use the same callsign and ssid for the object as the callsign/SSID that Xastir is using, and if you DON'T want that, use a different SSID. If Xastir's callsign is "MYCALL-0" then this invocation will create an object that will be adopted and retransmitted: xastir_udp_client localhost 2023 MYCALL-0 "MYCALL-0>APX219,WIDE2-1:;foobar *202111z3501.53N/10619.04W/" while this invocation will create an object that will only be transmitted once and not adopted: xastir_udp_client localhost 2023 MYCALL-0 "MYCALL-1>APX219,WIDE2-1:;foobar *202111z3501.53N/10619.04W/" .SH SEE ALSO xastir help file .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2023 The Xastir Group