]> git.street.me.uk Git - andy/viking.git/blob - tools/geo-nearest
Merge tag 'viking-1.2.2'
[andy/viking.git] / tools / geo-nearest
1 #!/bin/bash
2 #
3 #
4 #       DO NOT EDIT! This file is generated from geo-nearest.sh
5 #
6
7 #
8 #       geo-nearest: Fetch list of nearest geocaches.
9 #
10 #       Requires: curl; gpsbabel; bash or ksh;
11 #                 mysql (if using the gpsdrive.sql output option)
12 #
13 #       Donated to the public domain by Rick Richardson <rickr@mn.rr.com>
14 #
15 #       Use at your own risk.  Not suitable for any purpose.  Not legal tender.
16 #
17 #       $Id: geo-nearest.sh,v 1.42 2011/04/06 19:10:38 rick Exp $
18 #
19
20 PROGNAME="$0"
21
22 usage() {
23         cat <<EOF
24 NAME
25     `basename $PROGNAME` - Fetch a list of nearest geocaches
26
27 SYNOPSIS
28     `basename $PROGNAME` [options]
29
30     `basename $PROGNAME` [options] latitude longitude
31
32     `basename $PROGNAME` [options] zipcode
33
34     `basename $PROGNAME` [options] u=<username>
35
36     `basename $PROGNAME` [options] pq=<pocket-query>
37
38     `basename $PROGNAME` [options] tx=<bookmark-id>
39
40     `basename $PROGNAME` [options] -b bookmark
41     `basename $PROGNAME` [options] guid=<bookmark-id>
42
43 DESCRIPTION
44     Fetch a list of nearest geocaches.
45
46     Requires:
47         A premium member (\$30/yr) OR a basic member (free) login at:
48              http://www.geocaching.com
49         Visit a cache page and click the "Download to EasyGPS" link at least
50         once so you can read and agree to the license terms.  Otherwise, you
51         will not get any waypoint data.
52
53         curl            http://curl.haxx.se/
54         gpsbabel        http://gpsbabel.sourceforge.net/
55
56 EOF
57         gc_usage
58         cat << EOF
59
60 NOTE
61     A basic member will get caches very slow (20 cache pages per minute)
62     because we have to get the actual cache pages.  They will be stored in:
63         ~/.geo/caches/GCXXXX.html.
64     Of course, after running this command, geo-html2gpx could be run.
65
66 EXAMPLES
67     Nearest 20 caches, display shortnames:
68
69         geo-nearest -s
70
71     Search nearest 500 caches for virtual caches not yet found:
72
73         geo-nearest -n500 -Ivirtual -Xifound
74
75     Add nearest 50 caches to a GpsDrive SQL database
76
77         geo-nearest -n50 -f -s -S
78
79     Purge the existing SQL database of all geocaches, and fetch
80     200 fresh ones...
81
82         geo-nearest -S -P -s -n200
83
84     640x480 map of nearest caches using map source 2:
85
86         geo-nearest -omap,"-a2 -W640 -H480"
87
88     Copy two cachers:
89
90         geo-nearest -n200 -Xifound -udyl1231 -pPW | awk '{print \$1}' >1.foo
91         geo-nearest -n200 -Xifound -urickrich -pPW |awk '{print \$1}' >2.foo
92         geo-gid -otabsep \$(comm -12 1.foo 2.foo) >both
93
94     Fetch by owner:
95
96         geo-nearest u=team-deadhead
97
98     Fetch by tx method:
99
100         # nearby caches of this (puzzle) type, that I haven't found
101         geo-nearest -n500 -f -otabsep tx=40861821-1835-4e11-b666-8d41064d03fe |
102             geo-mystery >> Caches/rick.ts
103
104     Fetch a bookmark list:
105
106         geo-nearest -b acro
107         or
108         geo-nearest guid=baae5bf9-4315-4874-b7fb-ac84c9585641
109
110     Fetch a PQ query:
111
112         geo-nearest pq=08be103b-ffd1-4e27-992f-616e144e24df
113
114 FILES
115     ~/.georc
116     ~/.geo/caches/
117
118 SEE ALSO
119     geo-newest, geo-found, geo-placed, geo-keyword, geo-code, geo-map,
120     geo-waypoint,
121     $WEBHOME
122 EOF
123
124         exit 1
125 }
126
127 ##############################################################################
128 # begin #include "geo-common"
129 ##############################################################################
130
131 # I doubt this stuff will work in other than english
132 LANG=en_US
133
134 #
135 #       Common global constants
136 #
137 UA="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
138 WEBHOME="http://geo.rkkda.com/"
139
140 #
141 #       Common global variables
142 #
143 DEBUG=0
144 CRUFT=
145 CURL_OPTS=
146
147 #
148 #       Report an error and exit
149 #
150 error() {
151         echo "`basename $PROGNAME`: $1" >&2
152         exit 1
153 }
154
155 debug() {
156         if [ $DEBUG -ge $1 ]; then
157             echo "`basename $PROGNAME`: $2" >&2
158         fi
159 }
160
161 verbose() {
162         if [ $VERBOSE -ge $1 ]; then
163             echo "$2" >&2
164         fi
165 }
166
167 dbgcmd() {
168         if [ $DEBUG -ge $DBGCMD_LVL ]; then
169             echo "$@" >&2
170         fi
171         "$@"
172 }
173 DBGCMD_LVL=2
174
175 #
176 #       procedure to remove cruft files
177 #
178 remove_cruft() {
179         if [ $DEBUG = 0 -a "$CRUFT" != "" ]; then
180             for i in $CRUFT
181             do
182                     [ -f $i ] && rm -f $i
183             done
184         fi
185 }
186
187 trap remove_cruft EXIT
188
189 #
190 # Convert DegDec, MinDec, or DMS lat/lon to DegDec
191 #
192 latlon() {
193     # Handle NSEW prefixes
194     arg1=`echo "$1" | sed -e 's/^[nNeE]//' -e 's/^[wW]/-/' -e 's/^[sS]/-/'`
195     # If negative, print the sign then take the absolute value
196     case "$arg1" in
197     -*) echo -n "-"; arg1=`echo "$arg1" | sed 's/^-//'`;;
198     esac
199     # Now handle the 3 different formats
200     case $# in
201     1)  
202         case "$arg1" in
203         *.*.*)  echo "$arg1" \
204                 | sed -e 's/,//' -e 's#\([^.]*\)\.#\1 #' -e 's#$# 6k 60/+p#' \
205                 | dc
206                 ;;
207         lat=*)
208                 echo "$arg1" | sed 's/^lat=//'
209                 ;;
210         lon=*)
211                 echo "$arg1" | sed 's/^lon=//'
212                 ;;
213         *)      echo $arg1
214                 ;;
215         esac
216         ;;
217     2)  echo "6k $arg1 $2 60/+p" | dc;;
218     3)  echo "6k $arg1 $2 60/ $3 3600/++p" | dc;;
219     esac
220 }
221
222 #
223 #       Convert DegDec to MinDec
224 #
225 degdec2mindec() {
226     awk -v v=$1 \
227         'BEGIN{ i=int(v); f=(v-i)*60; if(f<0)f=-f; printf "%d.%06.3f\n", i, f}'
228 }
229
230 #
231 #       Read RC file, if there is one
232 #
233 read_rc_file() {
234     if [ -f $HOME/.georc ]; then
235         . $HOME/.georc
236         # Allow LAT/LON in rc file to be in any of the formats that we grok
237         if [ "" != "$LAT" ]; then
238             LAT=`latlon $LAT`
239         fi
240         if [ "" != "$LON" ]; then
241             LON=`latlon $LON`
242         fi
243     else
244         cat <<-EOF > $HOME/.georc
245                 #
246                 # These are the default values for the geo-* series of programs
247                 # Please edit this file as needed.  Setting values for
248                 # USERNAME, PASSWORD, LAT/LON, and STATE are required.
249                 #
250
251                 #################################
252                 # Login and paid membership status for www.geocaching.com...
253                 #USERNAME=name
254                 #PASSWORD=pasword
255                 #SOC=0
256
257                 #################################
258                 # Your HOME lat/lon and state...
259                 #LAT=N44.55.666
260                 #LON=W93.11.222
261                 #STATE=MN
262
263                 #################################
264                 # Default map scale, font, and source...
265                 #MAPSCALE=10K
266                 #MAPFONT=helvetica
267                 #MAPSRC=2
268
269                 #################################
270                 # Login for terraserver.com...
271                 #TSCOM_EMAIL=xxx@yyy.com
272                 #TSCOM_PW=password
273
274                 #################################
275                 # Miscellaneous...
276                 #OUTFMT=gpsdrive
277                 #GPSDRIVE_VER=2.09
278                 #CURL_OPTS="-4"
279         EOF
280         error "First time user: please review and edit $HOME/.georc"
281     fi
282 }
283
284 if [ `uname` = 'Darwin' ]; then
285     sed=gsed
286     date=gdate
287     touch=gtouch
288     PATH=$PATH:/usr/local/bin:/opt/local/bin
289     export PATH
290 else
291     sed=sed
292     date=date
293     touch=touch
294 fi
295
296 #
297 #       Get the value from a name= value= pair in a file
298 #
299 get_value() {
300     # <input type="hidden" name="__EVENTTARGET" value=""
301     what=$1
302     where=$2
303     eval $what=`$sed -n "s/^.*\"$what\" *value=\"\([^\"]*\)\".*/\1/p" < $where`
304 }
305
306 #
307 #       urlencode
308 #
309 #       incomplete, just does what we need it to do
310 #
311 urlencode() {
312     echo "$1" | sed -e 's/\+/%2B/g' -e 's/\&/%26/g' #-e 's/\//%2F/'
313 }
314
315 #
316 #       urlencode2
317 #
318 urlencode2() {
319     echo "$1" |
320     awk '
321         BEGIN {
322             split("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ")
323             hextab[0] = 0
324             for (i = 1; i <= 255; ++i) ord[ sprintf ("%c", i) "" ] = i + 0
325         }
326         {
327             encoded = ""
328             for (i = 1; i <= length($0); ++i ) {
329                 c = substr ($0, i, 1)
330                 val = ord[c]
331                 if (val >= 97 && val <= 122)            #0x61-0x7A
332                     encoded = encoded c
333                 else if (val >= 65 && val <= 90)        #0x41-0x5A
334                     encoded = encoded c
335                 else if (val >= 48 && val <= 57)        #0x30-0x39
336                     encoded = encoded c
337                 else if (val >= 45 && val <= 46)        #0x2D-0x2E
338                     encoded = encoded c
339                 else if (c == " ")
340                     encoded = encoded "+"
341                 else if (val < 128) {
342                     lo = val % 16
343                     hi = int(val / 16);
344                     encoded = encoded "%" hextab[hi] hextab[lo]
345                 }
346                 else {
347                     byte = 192 + val/64
348                     lo = byte % 16
349                     hi = int(byte / 16);
350                     encoded = encoded "%" hextab[hi] hextab[lo]
351                     byte = 128 + val%64
352                     lo = byte % 16
353                     hi = int(byte / 16);
354                     encoded = encoded "%" hextab[hi] hextab[lo]
355                 }
356             }
357             print encoded
358         }
359     '
360 }
361
362 #
363 #       return true if current arguments appear to be a lat/lon
364 #
365 is_latlon() {
366     if [ "$#" -lt 2 ]; then
367         return 1
368     fi
369     case "$1" in
370     lat=*)              ;;              # cut/paste from GPX file
371     [NS])               return 0;;      # cut/paste from gc.com
372     [NSns][0-9]*)       ;;
373     [-][0-9]*)          ;;
374     [0-9]*)             ;;
375     *)                  return 1;;
376     esac
377     case "$2" in
378     lon=*)              return 0;;
379     [EWew][0-9]*)       return 0;;
380     [-][0-9]*)          return 0;;
381     [0-9]*)             return 0;;
382     *)                  return 1;;
383     esac
384 }
385
386 #
387 #       split lines between two strings
388 #
389 #       $1 - string 1
390 #       $2 - string 2
391 #       $3 - null or 'g'
392 #
393 split_lines_between() {
394     sed "s@$1$2@$1\\
395 $2@$3"
396 }
397
398 ##############################################################################
399 # end #include "geo-common"
400 ##############################################################################
401 ##############################################################################
402 # begin #include "geo-common-gc"
403
404 # $Id: geo-common-gc,v 1.242 2011/05/21 17:38:57 rick Exp $
405 ##############################################################################
406
407 #
408 #       Common global constants
409 #
410 UA="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
411 UA="Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/XX (KHTML, like Gecko) Version/ZZ Safari/YY"
412 GEO="http://www.geocaching.com"
413 GEOS="https://www.geocaching.com"
414
415 #
416 #       Global variables that can be overridden on command line or rc file
417 #
418 PASSWORD=dummy
419 USERNAME=dummy
420 LAT=44.9472
421 LON=-93.4914
422 SOC=${SOC:0}
423 GEOMYSTERY=/dev/null
424 GEODIR=$HOME/.geo
425 case `uname` in
426 CYGWIN*)        CURL_OPTS=-k;;
427 *)              CURL_OPTS=
428 esac
429
430 #
431 #       Global variables
432 #
433 COOKIE_FILE=$HOME/.geocookies
434 NOCOOKIES=0
435 FOUND=1
436 USERFOUND=1
437 BABELFLAGS=
438 RADIUS=
439 OUTFILE=
440 OUTFMT=gpsdrive
441 NUM=20
442 INCLUDE=*
443 EXCLUDE='-unavail'
444 VARTIME=found
445 GEOSLEEP=${GEOSLEEP:-8}
446
447 #
448 #       Common options handling
449 #
450 gc_usage() {
451         cat <<EOF
452 OPTIONS
453         -b bookmark     Use list "bookmark" [none]
454         -c              Remove cookie file when done
455         -f              Do not report any found or unavailable caches
456         -m              Do not report any members-only caches
457         -F              Report caches found by the login 'username' as unfound
458         -n num          Return "num" caches [$NUM]
459         -s              Output short names for the caches (gpsbabel option)
460         -I term         Include only caches with 'term' [$INCLUDE]
461         -X term         Exclude caches with 'term' [$EXCLUDE]
462                         terms: "" (exclude none), unfound, ifound, soc, unavail,
463                         regular, multi, virtual, webcam, event, hybrid, cito
464         -r radius       Display only caches with radius (e.g. -r 25M)
465         -M mystery      Use file 'mystery' for unknown/mystery/puzzle
466                         caches [$GEOMYSTERY]. Awk Format:
467                             gcid lat lon comment
468                         i.e:
469                             GC2CBVB n44.45.123 w93.00.321       Final
470                             GC2CC1Z 44.123456 -93.564123        Cache
471
472         -u username     Username for http://www.geocaching.com
473         -p password     Password for http://www.geocaching.com
474         -o format       Output format, -o? for possibilities [$OUTFMT]
475                         plus "gpsdrive.sql" for direct insertion into MySQL DB
476                         plus "map[,geo-map-opts]" to display a geo-map.
477         -O filename     Output file, if not stdout
478         -S              Alias for -o gpsdrive.sql
479         -d              For -S, just delete selected records
480         -P              For -S, purge all records of type -t $SQLTAG*
481         -t type         For -ogpsdrive.sql, the waypoint type [$SQLTAG]
482         -H htmldir      Also fetch the printable HTML pages (slowly)
483         -L logdir       Also fetch the plain text log entries (slowly)
484                         For -H or -L, the limit is 1500 updated caches/day.
485         -! "lpr -Plp"   Print HTML pages
486         -D lvl          Debug level [$DEBUG]
487         -U              Retrieve latest version of this script
488
489 DEFAULTS
490         Defaults can also be set with variables in file \$HOME/.georc:
491
492             PASSWORD=password;  USERNAME=username;   SOC=0|1;
493             LAT=latitude;       LON=logitude;        GEOMYSTERY=/dev/null;
494             NUM=num;            OUTFMT=format;       BABELFLAGS=-s;
495             SQLUSER=gast;       SQLPASS=gast;        SQLDB=geoinfo;
496 EOF
497 }
498
499 gc_getopts() {
500     #
501     # Defaults for options that cannot be overriden in the RC file
502     #
503     PURGE=0
504     DELETE=0
505     SQL=0
506     MAP=0
507     HTMLDIR=
508     LOGDIR=
509     CMDPIPE=
510     BOOKMARK=
511
512     while getopts "!:H:L:I:X:b:cdfFmM:n:o:O:p:Pr:sSt:u:D:Uh?-" opt
513     do
514         case $opt in
515         "!")    CMDPIPE="$OPTARG";;
516         b)      BOOKMARK="$OPTARG";;
517         c)      NOCOOKIES=1;;
518         d)      DELETE=1;;
519         f)      FOUND=0; EXCLUDE="$EXCLUDE|-ifound";;
520         m)      SOC=0;;
521         M)      GEOMYSTERY="$OPTARG";;
522         I)
523                 if [ "$INCLUDE" = "*" ]; then
524                     INCLUDE=
525                 else
526                     INCLUDE="$INCLUDE|"
527                 fi
528                 INCLUDE="$INCLUDE-$OPTARG"
529                 ;;
530         X)
531                 if [ "" = "$OPTARG" ]; then
532                     EXCLUDE=-ExClUdEnOtHiNg
533                 else
534                     EXCLUDE="$EXCLUDE|-$OPTARG"
535                 fi
536                 ;;
537         F)      USERFOUND=0;;
538         P)      PURGE=1;;
539         n)      NUM="$OPTARG"
540                 case "$NUM" in
541                 [0-9]*) ;;
542                 *)      error "Not a number: '$NUM'";;
543                 esac
544                 if [ "$NUM" -lt 1 -o "$NUM" -gt 999999 ]; then
545                     error "NUM is not between 1 and 999999 ($NUM)"
546                 fi
547                 ;;
548         r)      RADIUS="$OPTARG"
549                 RADIUS_NUM=`awk -v "N=$RADIUS" 'BEGIN{printf "%d\n", N}'`
550                 case "$RADIUS" in
551                 *km*|*KM*)      RADIUS_UNITS=km;;
552                 *)              RADIUS_UNITS=mi;;
553                 esac
554                 ;;
555         s)      BABELFLAGS="$BABELFLAGS -s"; GEONUKE=",nuke_placer";;
556         S)      OUTFMT="gpsdrive.sql";;
557         t)      SQLTAG="$OPTARG";;
558         u)      USERNAME="$OPTARG";;
559         p)      PASSWORD="$OPTARG";;
560         o)      OUTFMT="$OPTARG";;
561         O)      OUTFILE="$OPTARG";;
562         H)      HTMLDIR="$OPTARG";;
563         L)      LOGDIR="$OPTARG";;
564         D)      DEBUG="$OPTARG";;
565         U)      echo "Getting latest version of this script..."
566                 curl $CURL_OPTS -o$UPDATE_FILE "$UPDATE_URL"
567                 chmod +x "$UPDATE_FILE"
568                 echo "Latest version is in $UPDATE_FILE"
569                 exit
570                 ;;
571         h|\?|-) usage;;
572         esac
573     done
574     
575     shiftamt=`expr $OPTIND - 1`
576     shift $shiftamt
577
578     case "$SOC" in
579     0)  EXCLUDE="$EXCLUDE|-soc";;
580     esac
581
582     case "$OUTFMT" in
583     map)
584         OUTFMT=tiger,newmarker=grnpin,iconismarker
585         MAP=1
586         ;;
587     map,*)
588         MAPOPTS=`echo "$OUTFMT" | sed -n 's/map,\(.*\)$/\1/p'`
589         OUTFMT=tiger,newmarker=grnpin,iconismarker
590         MAP=1
591         ;;
592
593     gpsdrive.sql)
594         OUTFMT=gpsdrive
595         SQL=1
596         # DEBUG=1
597         ;;
598     \?)
599         gpsbabel_formats
600         exit
601         ;;
602     esac
603
604     LOGUSERNAME="$USERNAME"
605     return $shiftamt
606 }
607
608 #
609 #       Get viewstate
610 #
611 gc_getviewstate() {
612     file=$1
613     get_value __EVENTTARGET $file
614     get_value __EVENTARGUMENT $file
615     get_value __VIEWSTATEFIELDCOUNT $file
616     get_value __VIEWSTATE $file; __VIEWSTATE=`urlencode "$__VIEWSTATE"`
617     get_value __EVENTVALIDATION $file;
618         __EVENTVALIDATION=`urlencode "$__EVENTVALIDATION"`
619     viewstate=
620     viewstate="$viewstate -d __VIEWSTATE=$__VIEWSTATE"
621     if [ "$__VIEWSTATEFIELDCOUNT" != "" ]; then
622         get_value __VIEWSTATE1 $file; __VIEWSTATE1=`urlencode "$__VIEWSTATE1"`
623         get_value __VIEWSTATE2 $file; __VIEWSTATE2=`urlencode "$__VIEWSTATE2"`
624         get_value __VIEWSTATE3 $file; __VIEWSTATE3=`urlencode "$__VIEWSTATE3"`
625         get_value __VIEWSTATE4 $file; __VIEWSTATE4=`urlencode "$__VIEWSTATE4"`
626         get_value __VIEWSTATE5 $file; __VIEWSTATE5=`urlencode "$__VIEWSTATE5"`
627         get_value __VIEWSTATE6 $file; __VIEWSTATE6=`urlencode "$__VIEWSTATE6"`
628         get_value __VIEWSTATE7 $file; __VIEWSTATE7=`urlencode "$__VIEWSTATE7"`
629         get_value __VIEWSTATE8 $file; __VIEWSTATE8=`urlencode "$__VIEWSTATE8"`
630         get_value __VIEWSTATE9 $file; __VIEWSTATE9=`urlencode "$__VIEWSTATE9"`
631         get_value __VIEWSTATE10 $file; __VIEWSTATE10=`urlencode "$__VIEWSTATE10"`
632
633         viewstate="$viewstate -d __VIEWSTATEFIELDCOUNT=$__VIEWSTATEFIELDCOUNT"
634         viewstate="$viewstate -d __VIEWSTATE1=$__VIEWSTATE1"
635         viewstate="$viewstate -d __VIEWSTATE2=$__VIEWSTATE2"
636         viewstate="$viewstate -d __VIEWSTATE3=$__VIEWSTATE3"
637         viewstate="$viewstate -d __VIEWSTATE4=$__VIEWSTATE4"
638         viewstate="$viewstate -d __VIEWSTATE5=$__VIEWSTATE5"
639         viewstate="$viewstate -d __VIEWSTATE6=$__VIEWSTATE6"
640         viewstate="$viewstate -d __VIEWSTATE7=$__VIEWSTATE7"
641         viewstate="$viewstate -d __VIEWSTATE8=$__VIEWSTATE8"
642         if [ "$__VIEWSTATE9" != "" ]; then
643             # __VIEWSTATEFIELDCOUNT == 9, but VIEWSTATE9 is null on geo-myfinds!
644             viewstate="$viewstate -d __VIEWSTATE9=$__VIEWSTATE9"
645             viewstate="$viewstate -d __VIEWSTATE10=$__VIEWSTATE10"
646         fi
647     fi
648 }
649
650 #
651 #       login to geocaching.com
652 #
653 #       Outputs: $__VIEWSTATE
654 #
655 gc_login() {
656     _username=`urlencode "$1"`
657     _password=`urlencode "$2"`
658
659     [ "$_username" != dummy ] || error "You need a www.geocaching.com username"
660     [ "$_password" != dummy ] || error "You need a www.geocaching.com password"
661
662     #
663     #   Get the login page so we can get a valid viewstate
664     #
665     LOGINPAGE=${TMP}-login.html
666     CRUFT="$CRUFT $LOGINPAGE"
667
668     URL="$GEOS/login/default.aspx"
669     debug 1 "curl $CURL_OPTS $URL"
670     curl $CURL_OPTS -s -A "$UA" -c$COOKIE_FILE \
671         -e "$URL;auto" \
672         -o $LOGINPAGE "$URL"
673     [ -s $LOGINPAGE ] || error "Unable to connect to gc.com"
674     get_value __VIEWSTATE $LOGINPAGE
675     __VIEWSTATE=`urlencode "$__VIEWSTATE"`
676     get_value __EVENTVALIDATION $LOGINPAGE
677     __EVENTVALIDATION=`urlencode "$__EVENTVALIDATION"`
678
679     sleep 2
680
681     #
682     #   Now post the login
683     #
684     URL="$GEOS/login/default.aspx"
685     #URL="$URL?RESET=Y"
686     debug 1 "curl $URL"
687     dbgcmd curl $CURL_OPTS -s -A "$UA" -b$COOKIE_FILE -c$COOKIE_FILE \
688         -d __VIEWSTATE="$__VIEWSTATE" \
689         -d __EVENTVALIDATION="$__EVENTVALIDATION" \
690         -e "$URL;auto" \
691         -dctl00%24SiteContent%24tbUsername="$_username" \
692         -dctl00%24SiteContent%24tbPassword="$_password" \
693         -dctl00%24SiteContent%24btnSignIn=Login \
694         -L "$URL" > $LOGINPAGE
695     if grep -q "ErrorText" $LOGINPAGE; then
696         error "Login username/password does not match."
697     fi 
698 }
699
700 #
701 #       procedure to nag about agreeing to EasyGps download license
702 #
703 easy_warning() {
704         cat <<-EOF
705         You have not agreed to the waypoint download license at $GEO
706
707         Click one of the waypoint license agreement links at $GEO,
708         read and agree to the license terms, then try this program again.
709         EOF
710 }
711
712 #
713 #       getcids infile cidfile xtrafile archfile number
714 #
715 #       Wade thru the HTML and produce lists of found, notfound and new CIDs
716 #
717 getcids() {
718     awk \
719         -v "CIDFILE=$2" \
720         -v "XTRAFILE=$3" \
721         -v "ARCHFILE=$4" \
722         -v "NUM=$5" \
723         -v "USERFOUND=$USERFOUND" \
724         -v "VARTIME=$VARTIME" \
725         -v "SOC=$SOC" \
726         -v "DATE=$date" \
727         -v "DEBUG=$DEBUG" \
728         < $1 \
729     '
730     function debug(lvl, text) {
731         if (lvl <= DEBUG)
732             print text > "/dev/stderr"
733     }
734     function hex2dec(x,   val) {
735         for (val = 0; length(x); x = substr(x, 2))
736             val = 16*val + index("0123456789ABCDEF", substr(x, 1, 1)) - 1
737         return val
738     }
739     # Convert GC0000 to 58913
740     function wp2id(wp,    val) {
741         sub("^GC", "", wp)
742         if (DEBUG > 5)
743             print "wp2id: " wp " ..." > "/dev/stderr"
744         if (length(wp) <= 4 && wp < "G000")
745         {
746             val = hex2dec(wp)
747             if (DEBUG > 5)
748                 print "wp2id hex: " val " ..." > "/dev/stderr"
749             return val
750         }
751         set = "0123456789ABCDEFGHJKMNPQRTVWXYZ"
752         val = 0
753         for (pos = 1; pos <= length(wp); ++pos)
754         {
755             val *= 31;
756             val += index(set, substr(wp, pos, 1)) - 1;
757         }
758         val = val - 411120
759         if (DEBUG > 5)
760             print "wp2id id: " val " ..." > "/dev/stderr"
761         return val
762     }
763     function id2wp(id,    val) {
764         gid = "";
765         if (id < 0)
766             ;
767         else if (id < 65536)
768             gid = sprintf("GC%04X", id)
769         else
770         {
771             GcOffset = 16 * 31 * 31 * 31 - 65536
772             GcSet = "0123456789ABCDEFGHJKMNPQRTVWXYZ"
773             id += GcOffset;
774             for (i = 1; i <= 4; ++i)
775             {
776                 gid = substr(GcSet, id%31 + 1, 1) gid
777                 id = int(id / 31)
778             }
779             tmp = substr(GcSet, id%31 + 1, 1)
780             if (tmp != 0)
781             {
782                 gid = tmp gid
783                 id = int(id / 31)
784             }
785             if (id)
786                 gid = ""
787             else
788                 gid = "GC" gid
789         }
790         if (DEBUG >= 5)
791             print "id = ", id, "wp = ", gid > "/dev/stderr"
792         return gid
793     }
794     function hash2sdt(text,
795                 value, mod, sizePre, diff, terrainPre, difficultyPre) {
796         if (ratingKey == "")
797             ratingKey = "hbM9fjmrxy7z42LFD58BkKgPGdHscvCqNnw3ptO6lJ"
798
799         # cut leading zero
800         if (length(text) > 6)
801             text = substr(text, length(text) - 6 + 1)
802         # add missing leading zero
803         while (length(text) < 6)
804             text = "h" text
805
806         for (i = 0; i < 6; i ++) {
807             value += (index(ratingKey, substr(text, i+1, 1)) - 1) \
808                          * (42 ^ (5 - i) );
809         }
810         # debug(5, "sdk value: " value)
811
812         mod = (value - 131586) % 16777216
813
814         sizePre = int(mod / (42 ^ 3));
815         if (sizePre == 0) diff = 0
816         else if (sizePre == 1) diff = 131072
817         else if (sizePre == 3) diff = 262144
818         else if (sizePre == 5) diff = 393217
819         else if (sizePre == 7) diff = 524288
820         else if (sizePre == 8) diff = 655360
821         else if (sizePre == 12) diff = 917504
822         else diff = -1
823
824         terrainPre = int((mod - diff) / 252)
825         difficultyPre = int(((mod - diff) % 42) - (terrainPre * 4))
826
827         # cache size
828         if (sizePre == 0) size = "not chosen"
829         else if (sizePre == 1) size = "Micro"
830         else if (sizePre == 3) size = "Regular"
831         else if (sizePre == 5) size = "Large"
832         else if (sizePre == 7) size = "Virtual"
833         else if (sizePre == 8) size = "Unknown"
834         else if (sizePre == 12) size = "Small"
835         else size = "BUG"
836
837         # terrain rating
838         if (terrainPre == 0) terrain = 1.0
839         else if (terrainPre == 1) terrain = 1.5
840         else if (terrainPre == 2) terrain = 2.0
841         else if (terrainPre == 3) terrain = 2.5
842         else if (terrainPre == 4) terrain = 3.0
843         else if (terrainPre == 5) terrain = 3.5
844         else if (terrainPre == 6) terrain = 4.0
845         else if (terrainPre == 7) terrain = 4.5
846         else terrain = 5.0
847
848         # difficulty rating
849         if (difficultyPre == 0) difficulty = 1.0
850         else if (difficultyPre == 1) difficulty = 1.5
851         else if (difficultyPre == 2) difficulty = 2.0
852         else if (difficultyPre == 3) difficulty = 2.5
853         else if (difficultyPre == 4) difficulty = 3.0
854         else if (difficultyPre == 5) difficulty = 3.5
855         else if (difficultyPre == 6) difficulty = 4.0
856         else if (difficultyPre == 7) difficulty = 4.5
857         else difficulty = 5.0
858     }
859     function begin_new_entry() {
860         # Beginning of a new entry, reset variables to defaults
861         inrecord = 1
862         avail = 1
863         archived = 0
864         bugs = 0
865         ifound = 0
866         iplaced = 0
867         soc = 0
868         unfound = 1
869         tdcnt = 0
870         gcid = "GC0000"
871         foundt = 0
872         ifoundrec = 0
873         ifoundt = 0
874         container = "unknown"
875         sendgps = 0     # Non-subscription members
876         # Bug Fix: FIXME
877         #gctype = "Traditional cache"
878         #type = "regular"
879         #difficulty = 0
880         #terrain = 0
881         # End Bug Fix: FIXME
882         if (DEBUG >= 5)
883             print "Begin " NUM " ..." > "/dev/stderr"
884     }
885     function parse_dates(text,    cmd, val) {
886         sub("[*]$", "", text)
887         debug(5, "parse_dates: text=" text)
888         if (text ~ /Today/)
889         {
890             cmd = sprintf("%s -d \"%s\" +%%s", DATE, "12am today")
891             cmd | getline val; close(cmd)
892         }
893         else if (text ~ /Yesterday/)
894         {
895             cmd = sprintf("%s -d \"%s\" +%%s", DATE, "12am yesterday")
896             cmd | getline val; close(cmd)
897         }
898         else if (text ~ /ago/)
899         {
900             cmd = sprintf("%s -d \"12am %s\" +%%s", DATE, text)
901             cmd | getline val; close(cmd)
902         }
903         else if (text ~ /[0-9][^<]*[0-9]/ )
904         {
905             cmd = sprintf("%s -d \"12am %s\" +%%s", DATE, text)
906             cmd | getline val; close(cmd)
907         }
908         else
909             val = 0
910         debug(5, "parse_dates: val=" val)
911         return val
912     }
913     BEGIN {
914         q = sprintf("%c", 39)
915         ++NUM
916         gctype = "Traditional cache"
917         type = "regular"
918     }
919     # Test: geo-nearest -s (18)
920     # Test: geo-newest -s (20)
921     # Test: geo-nearest -b multi (8)
922     #   
923     # For geo-nearest AND geo-nearest -b
924     /class=".* Data BorderTop"/ {
925         begin_new_entry()
926         debug(3, "Data BorderTop")
927         next
928     }
929     /<td/ {
930         ++tdcnt;
931     }
932     inrecord && tdcnt >= 1 && tdcnt <= 10 {
933         if (DEBUG >= 5)
934             print "tdcnt " tdcnt ", text: " $0 > "/dev/stderr"
935     }
936     /<a href="\/seek\/cache_details.aspx?[^>]*>/ {
937         name = $0
938
939         # remove strikeout class
940         sub("<span class[^>]*>", "", name)
941         sub("</span>", "", name)
942         sub(".*<span>", "", name)
943         sub("</span>.*", "", name)
944
945         sub(".*<a href=.../seek/cache_details.aspx?[^>]*>", "", name)
946         sub("</a>*.", "", name)
947         sub("</[^>]*>", "", name)
948         sub("</[^>]*>", "", name)
949         sub("<[^>]*>", "", name)
950         sub("<[^>]*>", "", name)
951     }
952     /"Found It!"/ {
953         if (USERFOUND)
954             ifound = 1
955         next
956     }
957     /Premium Member Only Cache/ {
958         soc = 1
959     }
960     tdcnt == (8-0) && /[0-9][0-9]*.[0-9][0-9]*/ {
961         # RER: May 4, 2011
962         date = $0
963         sub(/^ */, "", date)
964         sub(/ *<.*/, "", date)
965         sub(/\015/, "", date)
966         debug(5, "date: " date)
967         cmd = sprintf("%s -d \"12am %s\" +%%s", DATE, date)
968         cmd | getline placedt; close(cmd)
969         debug(5, "placedt: " placedt)
970     }
971     # <td>
972     #   Yesterday<strong>*</strong><br />
973     #   <span class="Success">
974     #       3 days ago*</span>
975     # </td>
976     #OR
977     # <td>
978     #   Yesterday<strong>*</strong><br />
979     #   <span class="Success">
980     #   </span>
981     # </td>
982     tdcnt == (9-0) && /[a-zA-Z0-9*>]<br .>/ {
983         # catch dates DD MMM YY, N days ago, Today, Yesterday
984         unfound = 0
985         date = $0
986         sub(".*<td>", "", date)
987         sub("<.*", "", date)
988         lastfoundt = parse_dates(date)
989         foundt = lastfoundt
990         debug(5, "lastfoundt: " lastfoundt)
991     }
992     tdcnt == (9-0) && /[a-zA-Z0-9*>]<.span>/ {
993         unfound = 0
994         date = $0
995         sub(".*Success.>", "", date)
996         sub("<.*", "", date)
997         ifoundt = parse_dates(date)
998         debug(5, "ifoundt: " ifoundt)
999     }
1000     /<strike><font/ {
1001         # i.e. <font color="red">
1002         avail = 0; archived = 1
1003     }
1004     /<\/strike><\/font/ {
1005         # i.e. <font color="red">
1006         avail = 0; archived = 1
1007     }
1008     /<strike>[^<]/ {
1009         avail = 0;
1010     }
1011     /class=".*Strike">/ {
1012         avail = 0
1013     }
1014     /class=".*Warning Strike.*">/ {
1015         avail = 0; archived = 1
1016     }
1017     tdcnt == 5 && /^ *GC/ {
1018         gcid = $0
1019         sub("^ *", "", gcid)
1020         sub("\015", "", gcid)
1021         debug(5, "GCID: <" gcid ">")
1022         cid = wp2id(gcid)
1023     }
1024     /left" nowrap>[0-9].*[0-9][0-9]<.td>/ {
1025         i = match($0, ">")
1026         j = match($0, "<.td>")
1027         date = substr($0, i+1, j-i-1)
1028         sub(q, "20", date)
1029         cmd = sprintf("%s -d \"%s\" +%%s", DATE, date)
1030         cmd | getline placedt; close(cmd)
1031     }
1032     /left" nowrap>[0-9].*[0-9][0-9].<IMG/ {
1033         # gc.com calls this "new"
1034         i = match($0, ">")
1035         j = match($0, " <IMG ")
1036         date = substr($0, i+1, j-i-1)
1037         sub(q, "20", date)
1038         cmd = sprintf("%s -d \"%s\" +%%s", DATE, date)
1039         cmd | getline placedt; close(cmd)
1040     }
1041     /alt=.Your Geocache/ {
1042         # altmy cache
1043         # A mistake in the HTML! should be alt="my cache"
1044         if (USERFOUND) {
1045             iplaced = 1
1046             ifound = 1
1047         }
1048     }
1049     /alt="Earthcache"/ {
1050         type = "earth"
1051         gctype = "Earthcache"
1052     }
1053     /alt="Event Cache"/ {
1054         type = "event"
1055         gctype = "Event cache"
1056     }
1057     /alt="Cache In Trash Out Event"/ {
1058         type = "cito"
1059         gctype = "Cache In Trash Out Event"
1060     }
1061     /alt="Traditional Cache"/ {
1062         type = "regular"
1063         gctype = "Traditional cache"
1064     }
1065     /alt="Letterbox Hybrid"/ {
1066         type = "hybrid"
1067         gctype = "Letterbox Hybrid"
1068     }
1069     /alt="Multi-cache"/ {
1070         type = "multi"
1071         gctype = "Multi-Cache"
1072     }
1073     /alt="Unknown Cache"/ {
1074         type = "unknown"
1075         gctype = "Unknown Cache"
1076     }
1077     /alt="Virtual Cache"/ {
1078         type = "virtual"
1079         gctype = "Virtual cache"
1080     }
1081     /alt="Webcam Cache"/ {
1082         type = "webcam"
1083         gctype = "Webcam Cache"
1084     }
1085     /alt="Wherigo Cache"/ {
1086         type = "wherigo"
1087         gctype = "Wherigo Cache"
1088     }
1089     /alt="Mega-Event Cache"/ {
1090         type = "mega"
1091         gctype = "Mega-Event Cache"
1092     }
1093     /name=.CID. / {
1094         i = match($0, "value=.")
1095         cid = substr($0, i+7, 99) + 0
1096     }
1097     /name=.BID. / {
1098         i = match($0, "value=.")
1099         bid = substr($0, i+7, 99) + 0
1100     }
1101     #/ImgGen.seek.CacheInfo.ashx?v=/ {
1102     0 && /[?]v=/ {
1103         text = $0
1104         debug(5, "sdt text: " text)
1105         sub(".*?v=", "", text)
1106         sub(". .*", "", text)
1107         debug(5, "sdt text: " text)
1108         hash2sdt(text)
1109         debug(5, "size: " size " difficulty: " difficulty " terrain: " terrain)
1110         container = size
1111     }
1112     /Unapproved cache/ && inrecord {
1113         avail = 0; archived = 1
1114     }
1115     /class=.Checkbox NoBolding./ {
1116         sendgps = 1     # Subscription members
1117     }
1118     /<\/[tT][rR]>/ && inrecord {
1119         # RER mod 11/22/10: if (0 && ..
1120         if (0 && sendgps == 0)
1121             next
1122         inrecord = 0
1123         debug(5, "End")
1124
1125         strtype = "Geocache"
1126
1127         if (soc) strtype = strtype "-soc"
1128         if (unfound) strtype = strtype "-unfound"
1129         else if (ifound) strtype = strtype "-ifound"
1130         if (!avail) strtype = strtype "-unavail"
1131         if (archived) strtype = strtype "-archived"
1132
1133         strtype = strtype "-" type
1134
1135         # gpsbabel only allows one time in the DB, figure out what
1136         # time to use for this, but always carry all three times
1137         # in the .xtra file
1138         if (iplaced) ifoundt = placedt
1139         vartime=1234
1140         if (VARTIME == "placed") vartime = placedt
1141         else if (VARTIME == "ifound") vartime = ifoundt
1142         else if (foundt > 0) vartime = foundt
1143         else vartime = placedt
1144
1145         # date -d 1970-01-01 1237093200 sec +%Y%m%d
1146         # 20090315
1147         cmd = sprintf("%s -d \"1970-01-01 %d sec\" +%%Y%%m%%d",
1148             DATE, lastfoundt)
1149         cmd | getline lastfound; close(cmd)
1150
1151         # avail=1 is the choice right now (8/19/05)
1152         # archived=0 is the choice right now (11/14/06)
1153         if (!archived && (SOC || !soc))
1154         {
1155             if (bid != 0) {
1156                 printf("-dBID=%d\n", bid) > CIDFILE
1157                 gcid = id2wp(bid)
1158             } else if (cid != 0) {
1159                 printf("-dCID=%d\n", cid) > CIDFILE
1160             }
1161             # GCID type vartime ifound soc iplaced tPLACED tFOUND tIFOUND
1162                 #"%.1f\t%.1f\t%s\t"
1163                 #difficulty, terrain, container,
1164             printf "%s\t%s\t%d\t%s\t%s\t%s\t%d\t%d\t%d\t" \
1165                 "%s\t%s\t%s\n",
1166                 gcid, strtype, vartime,
1167                 ifound, soc, iplaced, placedt, foundt, ifoundt,
1168                 gctype, "hint", lastfound >> XTRAFILE
1169             if (--NUM == 0)
1170                 exit
1171         }
1172         else if (archived)
1173         {
1174             if (DEBUG > 5)
1175                 print "Archived ", gcid, " " name > "/dev/stderr"
1176             if (name == "")
1177                 name = "error-no-name!"
1178             # Use "merge" file output, NOT XTRAFILE!
1179             printf "%s\t%s\t0.0\t0.0\t%s%s%s\t%s\t%d\t" \
1180                 "%s\t%s\t%s\t%d\t%d\t%d\t%.1f\t%.1f\t%s\t%s\t%s\t%s\n",
1181                 gcid, name,
1182                 "http://www.geocaching.com/seek/cache_details.aspx",
1183                 "?log=y&wp=", gcid,
1184                 difficulty, terrain, container,
1185                 strtype, vartime,
1186                 ifound, soc, iplaced, placedt, foundt, ifoundt,
1187                 gctype, "hint", lastfound >> ARCHFILE
1188             if (--NUM == 0)
1189                 exit
1190         }
1191     }
1192     '
1193 }
1194
1195 #
1196 #       A temporary style we can use for merging the loc data with
1197 #       the scraped html data.  This is a dual purpose hack.  We
1198 #       use it as an output format to convert the .loc data to a
1199 #       record-per-line format.  We use it as an input format to
1200 #       read up the merged data.
1201 #
1202 make_scrape_style() {
1203     cat <<-EOF
1204         ENCODING                UTF-8
1205         FIELD_DELIMITER         TAB
1206         RECORD_DELIMITER        NEWLINE
1207         BADCHARS                TAB
1208         IFIELD  SHORTNAME,      "",     "%s"
1209         IFIELD  DESCRIPTION,    "",     "%s"    
1210         IFIELD  LAT_DECIMAL,    "",     "%08.5f"
1211         IFIELD  LON_DECIMAL,    "",     "%08.5f"
1212         IFIELD  URL,    "",     "%s"
1213         IFIELD  GEOCACHE_DIFF,  "",     "%3.1f"         #difficulty
1214         IFIELD  GEOCACHE_TERR,  "",     "%3.1f"         #terrain
1215         IFIELD  GEOCACHE_CONTAINER,"",  "%s"            #container (not set)
1216         IFIELD  ICON_DESCR,     "",     "%s"            #strtype (Geocache-*)
1217         IFIELD  TIMET_TIME,     "",     "%ld"           #variable time
1218         IFIELD  IGNORE,         "",     "%s"            #ifound
1219         IFIELD  IGNORE,         "",     "%s"            #soc
1220         IFIELD  IGNORE,         "",     "%s"            #iplaced
1221         IFIELD  IGNORE,         "",     "%s"            #placed time
1222         IFIELD  IGNORE,         "",     "%s"            #found time
1223         IFIELD  IGNORE,         "",     "%s"            #ifound time
1224         IFIELD  GEOCACHE_TYPE,  "",     "%s"            #gc.com type
1225         IFIELD  GEOCACHE_HINT,  "",     "%s"            #gc.com hint
1226         IFIELD  GEOCACHE_LAST_FOUND, "","%s"            #gc.com last found
1227         OFIELD  SHORTNAME,      "",     "%s"
1228         OFIELD  DESCRIPTION,    "",     "%s"
1229         OFIELD  LAT_DECIMAL,    "",     "%08.5f"
1230         OFIELD  LON_DECIMAL,    "",     "%08.5f"
1231         OFIELD  URL,    "",     "%s"
1232         OFIELD  GEOCACHE_DIFF,  "",     "%3.1f"         #difficulty
1233         OFIELD  GEOCACHE_TERR,  "",     "%3.1f"         #terrain
1234         OFIELD  GEOCACHE_CONTAINER,"",  "%s"            #container (not set)
1235         EOF
1236         # OFIELD        ICON_DESCR,     "",     "%s"
1237 }
1238
1239 #
1240 #       csv2csv puzzle-file 
1241 #
1242 csv2csv() {
1243     if [ ! -e "$1" ]; then
1244         error "Don't have a -M '$1' file"
1245     fi
1246
1247     awk -v GEOMYSTERY=$1 '
1248     function latlon ( val ) {
1249         if (val ~ ".[.]..*[.].*")
1250         {
1251             if (val ~ "[-wWsS]")
1252             {
1253                 val = substr(val, 2)
1254                 neg = 1
1255             }
1256             else if (val ~ "[nNeE]")
1257             {
1258                 val = substr(val, 2)
1259                 neg = 0
1260             }
1261             else
1262                 neg = 0
1263             dd = int(val)
1264             sub("[^.]*[.]", "", val)
1265             dd += (val+0.0) / 60.0
1266             return neg ? -dd : dd
1267         }
1268         return val
1269     }
1270     BEGIN {
1271         while (getline <GEOMYSTERY > 0)
1272         {
1273             if ($0 ~ "^#")
1274                 continue
1275             if ($0 ~ "^[        ]*$")
1276                 continue
1277             if ($2 ~ "unk")
1278             {
1279                 lat[$1] = 48
1280                 lon[$1] = -88
1281             }
1282             else
1283             {
1284                 lat[$1] = $2
1285                 lon[$1] = $3
1286             }
1287         }
1288         FS="    "
1289     }
1290     {
1291         if (lat[$1] != 0)
1292         {
1293             deglat = latlon( lat[$1] )
1294             deglon = latlon( lon[$1] )
1295             # GC# Desc lat lon URL diff terr size
1296             for (i = 1; i <= 2; ++i)
1297                 printf "%s\t", $i
1298             printf "%.6f\t%.6f\t", deglat, deglon
1299             for (i = 5; i < NF; ++i)
1300                 printf "%s\t", $i
1301             printf "%s\n", $NF
1302         }
1303         else
1304             print
1305     }
1306     '
1307 }
1308
1309 #
1310 #       Query the gc website
1311 #
1312 gc_query() {
1313     if [ $USERFOUND = 0 ]; then
1314         FOUND=1
1315     fi
1316     if [ $FOUND = 0 ]; then
1317             SEARCH="$SEARCH&f=1"
1318     fi
1319
1320     if [ $DEBUG -gt 0 ]; then
1321         TMP=/tmp/geo
1322     else
1323         TMP=/tmp/geo$$
1324     fi
1325
1326     HTMLPAGE=$TMP.page
1327     CIDFILE=$TMP.cids
1328     LOCFILE=$TMP.loc
1329     LOCTMPFILE=$TMP.tmp
1330     XTRAFILE=$TMP.xtra
1331     CSVFILE=$TMP.csv
1332     CSVFILE2=$TMP.csv2
1333     JOINFILE=$TMP.join
1334     MERGEFILE=$TMP.merge
1335     ARCHFILE=$TMP.arch
1336     OUTWAY=$TMP.way
1337     STYLE=$TMP.newstyle
1338
1339     CRUFT="$CRUFT $HTMLPAGE"
1340     CRUFT="$CRUFT $CIDFILE"
1341     CRUFT="$CRUFT $LOCFILE"
1342     CRUFT="$CRUFT $LOCTMPFILE"
1343     CRUFT="$CRUFT $XTRAFILE"
1344     CRUFT="$CRUFT $CSVFILE"
1345     CRUFT="$CRUFT $CSVFILE2"
1346     CRUFT="$CRUFT $JOINFILE"
1347     CRUFT="$CRUFT $MERGEFILE"
1348     CRUFT="$CRUFT $ARCHFILE"
1349     CRUFT="$CRUFT $OUTWAY"
1350     CRUFT="$CRUFT $STYLE"
1351     if [ $NOCOOKIES = 1 ]; then
1352         CRUFT="$CRUFT $COOKIE_FILE"
1353     fi
1354
1355     #
1356     #   Login to gc.com
1357     #
1358     gc_login "$USERNAME" "$PASSWORD"
1359
1360     #
1361     #   Find the bookmark
1362     #
1363     if [ "$BOOKMARK" != "" ]; then
1364         URL="$GEO/bookmarks"
1365         debug 1 "$start: curl $URL #bookmark"
1366         SEARCH=`
1367             curl $CURL_OPTS -L -s -b $COOKIE_FILE -A "$UA" "$URL" \
1368             | grep -y ">$BOOKMARK<" \
1369             | sed -e 's@^.*href=.http://www.geocaching.com/@@' -e 's/.>.*$//'
1370             `
1371         case "$SEARCH" in
1372         *bookmarks*)    ;;
1373         *)              error "No bookmark with the name '$BOOKMARK'.";;
1374         esac
1375     fi
1376
1377     #
1378     #   We might combine one or more pages into a single XML, so cobble
1379     #   up a header with the ?xml and loc tags.
1380     #   
1381     cat <<-EOF > $LOCFILE
1382         <?xml version="1.0" encoding="UTF-8"?>
1383         <loc version="1.0" src="EasyGPS">
1384         EOF
1385
1386     #
1387     # Loop, getting at least "NUM" locations
1388     #
1389     ((NUM=NUM-1))
1390     if [ $DEBUG -gt 0 ]; then
1391         filter2="tee $TMP.bulk"
1392     else
1393         filter2=cat
1394     fi
1395
1396     subscriber=1
1397     > $XTRAFILE
1398     > $ARCHFILE
1399     ((start=0))
1400     while ((start <= NUM)); do
1401         sleep $GEOSLEEP
1402
1403         #
1404         # Fetch the page of closest caches and scrape the cache ID's
1405         #
1406         case "$SEARCH" in
1407         *bookmark*)
1408             URL="$GEO/$SEARCH"
1409             ;;
1410         *)
1411             URL="$GEO/seek/nearest.aspx"
1412             URL="$URL$SEARCH"
1413             ;;
1414         esac
1415         debug 1 "$start: curl $URL #list"
1416         if ((start > 0)); then
1417             # "postback"... grab the "next" button
1418             case "$SEARCH" in
1419             *bookmark*)
1420                 __EVENTTARGET="ListInfo\$pgrBMItems\$_ctl8"
1421                 ;;
1422             *)
1423                 TGT=$(sed -n "s/^.*__doPostBack('.*pgrTop\$\(.*\)','.*/\1/p" \
1424                     < $HTMLPAGE)
1425                 if [ "$TGT" = "" ]; then
1426                     error "TGT is blank!"
1427                 fi
1428                 __EVENTTARGET="ctl00%24ContentBody%24pgrTop%24$TGT"
1429                 ;;
1430             esac
1431             curl $CURL_OPTS -L -s -b $COOKIE_FILE -A "$UA" \
1432                 -d __EVENTTARGET="$__EVENTTARGET" \
1433                 $viewstate \
1434                 "$URL" \
1435                 | sed -e "s/&#39;/'/g" -e "s/\r//" > $HTMLPAGE
1436         else
1437             curl $CURL_OPTS -L -s -b $COOKIE_FILE -A "$UA" \
1438                 "$URL" \
1439                 | sed -e "s/&#39;/'/g" -e "s/\r//" > $HTMLPAGE
1440             if [ "$DEBUG" -ge 1 ]; then
1441                 grep "Total Records:.*Top.*" $HTMLPAGE |
1442                     sed -e "s/<.b>.*//" -e "s/^.*span>//" -e "s/<b>//" 1>&2
1443             fi
1444         fi
1445         rc=$?; if [ $rc != 0 ]; then
1446             error "curl: fetch $URL"
1447         fi
1448         if grep -s -q "We encountered an error when requesting that page!" \
1449             $HTMLPAGE; then
1450             error "searching error (1) on $start"
1451         fi
1452         if grep -s -q "has resulted in an error" \
1453             $HTMLPAGE; then
1454             error "searching error (2) on $start"
1455         fi
1456         if grep -s -q "By State" $HTMLPAGE; then
1457             error "searching gave up on $start"
1458         fi
1459         if grep -s -q ">Advanced Search<" $HTMLPAGE; then
1460             error "need a country AND a state!"
1461         fi
1462
1463         #
1464         # Grab a few important values from the page
1465         #
1466         gc_getviewstate $HTMLPAGE
1467
1468         #
1469         # Grab the CIDs into two categories: found and notfound
1470         #
1471         > $CIDFILE
1472         getcids $HTMLPAGE $CIDFILE $XTRAFILE $ARCHFILE $((NUM-start))
1473
1474         #
1475         # Fetch the waypoints, rip out the ?xml and loc tags, and
1476         # append to the $LOCFILE file.
1477         #
1478         if [ -s "$CIDFILE" ]; then
1479             sleep $GEOSLEEP
1480             case "$SEARCH" in
1481             *bookmark*)
1482                 URL="$GEO/$SEARCH"
1483                 ;;
1484             *)
1485                 URL="$GEO/seek/nearest.aspx"
1486                 URL="$URL$SEARCH"
1487                 ;;
1488             esac
1489             debug 2 "$start: curl $URL #loc"
1490             curl $CURL_OPTS -s -b $COOKIE_FILE -A "$UA" \
1491                     $viewstate \
1492                     `cat $CIDFILE` \
1493                     -d "Download=Download+Waypoints" \
1494                     -d "ListInfo:btnDownload=Download+to+.Loc" \
1495                     "$URL" \
1496             | $filter2 \
1497             | sed -e 's/^<?xml [^>]*>//' \
1498                     -e 's/>[gG]eocache</>Geocache</g' \
1499                     -e 's/<loc [^>]*>//' \
1500                     -e 's#</loc>##' \
1501             > $LOCTMPFILE
1502             rc=$?; if [ $rc != 0 ]; then
1503                 error "curl: fetch the waypoints"
1504             fi
1505             if grep -s -q "you are not logged in" $LOCTMPFILE; then
1506                 error "you are not logged in on $start"
1507             fi
1508             if grep -s -q "has resulted in an error" $LOCTMPFILE; then
1509                 error "searching error (3) on $start"
1510             fi
1511             if grep -s -q "Geocaching > Search for Geocaches" $LOCTMPFILE; then
1512                 error "searching error (4) on $start"
1513             fi
1514             if grep -s -q "recaptcha_challenge_field" $LOCTMPFILE; then
1515                 #
1516                 # Basic members: do it the SLOW way
1517                 #
1518                 if [ "$GEODIR" != "" -a ! -d "$GEODIR" ]; then
1519                     mkdir "$GEODIR" || error "Couldn't mkdir $GEODIR"
1520                 fi
1521                 if [ "$GEODIR/caches" != "" -a ! -d "$GEODIR/caches" ]; then
1522                     mkdir "$GEODIR/caches" \
1523                         || error "Couldn't mkdir $GEODIR/caches"
1524                 fi
1525
1526                 if [ $subscriber = 1 ]; then
1527                     debug 0 "Basic Member: pay the \$30/yr fee for Premium Member!"
1528                     debug 0 "Basic Member: doing it the REAL SLOW way!!!"
1529                     timestamp="$GEODIR/caches/.timestamp"
1530                     $touch -d "1 day ago" $timestamp
1531                 fi
1532                 subscriber=0
1533
1534                 #
1535                 # Pull 20 GCIDs...
1536                 #
1537                 bstart=$start
1538                 grep "^ *GC.*" $HTMLPAGE \
1539                 | sed -e "s/ //g" \
1540                 | while read gcid; do
1541                     #
1542                     #   Get the cache page
1543                     #
1544                     cachepage="$GEODIR/caches/$gcid.html"
1545                     if [ ! -s $cachepage -o $timestamp -nt $cachepage ]; then
1546                         # cache page doesn't exist or out of date
1547                         sleep 3 #$GEOSLEEP
1548                         urlpage="http://www.geocaching.com"
1549                         urlpage="$urlpage/seek/cache_details.aspx"
1550                         urlpage="$urlpage?log=y&wp=$gcid"
1551                         debug 0 "$bstart: curl $urlpage #cache fetch $gcid.html"
1552                         curl $CURL_OPTS -L -s -b $COOKIE_FILE -A "$UA" \
1553                             $urlpage > $cachepage
1554                     fi
1555
1556                     #
1557                     #   Cobble up the .loc file entry
1558                     #
1559                     name=` grep -A1 "<head><title>" $cachepage \
1560                         | tail -1 | tr -d "\r"  \
1561                         | sed -e 's/[   ]*GC[^ ]* //' -e 's/ (.*by/ by/' `
1562                     diff=` grep ctl00_ContentBody_uxLegendScale $cachepage \
1563                         | sed -e 's/.*alt="//' -e 's/ .*//' `
1564                     terr=` grep ctl00_ContentBody_Localize6 $cachepage \
1565                         | sed -e 's/.*alt="//' -e 's/ .*//' `
1566                     size=` grep "alt=.Size:" $cachepage \
1567                         | sed -e 's/.*alt="Size: //' -e 's/" .*//' `
1568                     case $size in
1569                     Unknown)    cont=1;;
1570                     Micro)      cont=2;;
1571                     Regular)    cont=3;;
1572                     Large)      cont=4;;
1573                     Virtual)    cont=5;;
1574                     Other)      cont=6;;
1575                     Small)      cont=8;;
1576                     *)          cont=1;;
1577                     esac
1578
1579                     echo "<waypoint>"
1580                     echo "<name id=\"$gcid\"><![CDATA[$name]]></name>"
1581                     grep "lnkConversions" $cachepage \
1582                         | sed -e 's/.*lat=/<coord lat="/' \
1583                             -e 's/&amp;lon=/" lon="/' -e 's@&.*@"/>@'
1584                     echo "<type>Geocache</type>"
1585                     echo -n "<link text=\"Cache Details\">"
1586                     urlpage="http://www.geocaching.com"
1587                     urlpage="$urlpage/seek/cache_details.aspx"
1588                     urlpage="$urlpage?wp=$gcid"
1589                     echo -n "$urlpage"
1590                     echo "</link>"
1591                     echo "<difficulty>$diff</difficulty>"
1592                     echo "<terrain>$terr</terrain>"
1593                     echo "<container>$cont</container>"
1594                     echo "</waypoint>"
1595
1596                     debug 3 "bstart: $bstart"
1597                     if [ $bstart == $NUM ]; then
1598                         break
1599                     fi
1600                     ((++bstart))
1601                     #break
1602                 done >> $LOCFILE
1603             else
1604                 cat $LOCTMPFILE >> $LOCFILE
1605             fi
1606         fi
1607
1608         #
1609         # Check to see if the user hasn't agreed to license terms
1610         #
1611         if grep -s -q "lblAgreementText" $LOCFILE; then
1612                 easy_warning >&2
1613                 remove_cruft
1614                 exit
1615         fi
1616
1617         ((start=start+20))
1618
1619         # If the Next button is disabled, break this loop
1620         # grep "Records: <b>[1-9].*disabled.><b>Next<" $HTMLPAGE
1621         if grep -s -q "Records: <b>[1-9].*disabled.><b>Next " $HTMLPAGE; then
1622             # echo "$start: dis"
1623             break;
1624         fi
1625     done
1626
1627     #
1628     # Finish off the .loc file
1629     #
1630     echo "</loc>" >> $LOCFILE
1631
1632     #
1633     #   Convert the .loc data to .csv format and join it with
1634     #   the extra data scraped from the HTML page.  Filter out
1635     #   the data according to the -I and -X options.
1636     #
1637     # http://www.geocaching.com/seek/cache_details.aspx?wp=GCG2H4
1638     # http://www.geocaching.com/seek/cache_details.aspx?log=y&wp=GCG2H4
1639     # http://www.geocaching.com/seek/cache_details.aspx?ID=92117&log=y
1640     #
1641     # The joined .csv format looks like this:
1642     #   GCH636  Jidana 3 by rickrich    44.94520        -93.47540 \
1643     #   http://www.geocaching.com/seek/cache_details.aspx?log=y&wp=GCH636 \
1644     #   Geocache-ifound-regular 1070285077      1       0       1 \
1645     #   1067925600      1070285077      0
1646     #
1647     make_scrape_style > $STYLE
1648
1649     dbgcmd gpsbabel -i geo$GEONUKE -f $LOCFILE \
1650         -o xcsv,style=$STYLE -F $CSVFILE2
1651     if [ $? != 0 ]; then
1652         cp $LOCFILE /tmp/geo.err
1653         error "gpsbabel returned error code [1]"
1654     fi
1655
1656     # Convert CSV into CSV with puzzles...
1657     csv2csv $GEOMYSTERY < $CSVFILE2 > $CSVFILE
1658
1659     join -t '   ' $CSVFILE $XTRAFILE > $JOINFILE
1660     if [ $? != 0 ]; then
1661         cp $CSVFILE /tmp/geo.err.csv
1662         cp $XTRAFILE /tmp/geo.err.xtra
1663         error "joined file error: see join /tmp/geo.err.{csv,xtra}"
1664     fi
1665     egrep -- "$INCLUDE" < $JOINFILE \
1666     | egrep -v -- "$EXCLUDE" \
1667     | sed -e 's/wp=/log=y\&&/' > $MERGEFILE
1668
1669     if [ $FOUND = 1 ]; then
1670         cat $ARCHFILE \
1671         | egrep -- "$INCLUDE" | egrep -v -- "$EXCLUDE" \
1672         | sed -e 's/wp=/log=y\&&/' >> $MERGEFILE
1673     fi
1674
1675     if [ $DEBUG -ge 2 ]; then
1676         # First two of these should be the same number of lines!
1677         wc -l $CSVFILE >&2
1678         wc -l $XTRAFILE >&2
1679         wc -l $MERGEFILE >&2
1680     fi
1681
1682     #
1683     # Convert to the desired format
1684     #
1685     BABELFILT=
1686     if [ "$RADIUS" != "" ]; then
1687         BABELFILT="-x radius,distance=$RADIUS,lat=$LAT,lon=$LON"
1688     fi
1689
1690     if [ $SQL = 1 ]; then
1691             #
1692             # add it via mysql
1693             #
1694             if [ "$OUTFILE" != "" ]; then
1695                 >"$OUTFILE"
1696             fi
1697
1698             if [ $PURGE = 1 ]; then
1699                 gpsdrive_purge | gpsdrive_mysql
1700                 PURGE=2
1701             fi
1702
1703             dbgcmd gpsbabel $BABELFLAGS \
1704                 -i xcsv,style=$STYLE -f $MERGEFILE \
1705                 $BABELFILT -o "$OUTFMT" -F $OUTWAY
1706             if [ $? != 0 ]; then
1707                 error "gpsbabel returned error code [2]"
1708             fi
1709             gpsdrive_add <$OUTWAY $SQLTAG | gpsdrive_mysql
1710     elif [ $MAP = 1 ]; then
1711             dbgcmd gpsbabel $BABELFLAGS \
1712                 -i xcsv,style=$STYLE -f $MERGEFILE \
1713                 $BABELFILT -o "$OUTFMT" -F $OUTWAY
1714             if [ $? != 0 ]; then
1715                 error "gpsbabel returned error code [3]"
1716             fi
1717             if [ "$OUTFILE" = "" ]; then
1718                 dbgcmd geo-map -s0 $MAPOPTS -t$OUTWAY
1719             else
1720                 dbgcmd geo-map -s0 $MAPOPTS -t$OUTWAY -o"$OUTFILE"
1721             fi
1722     else
1723             #
1724             # output to stdout or to a file
1725             #
1726             if [ "$OUTFILE" = "" ]; then
1727                 OUTTMP="$TMP.way";  CRUFT="$CRUFT $OUTTMP"
1728                 dbgcmd gpsbabel $BABELFLAGS \
1729                     -i xcsv,style=$STYLE -f $MERGEFILE \
1730                     $BABELFILT -o "$OUTFMT" -F $OUTTMP
1731                 if [ $? != 0 ]; then
1732                     error "gpsbabel returned error code [4]"
1733                 fi
1734                 cat $OUTTMP
1735             else
1736                 dbgcmd gpsbabel $BABELFLAGS \
1737                     -i xcsv,style=$STYLE -f $MERGEFILE \
1738                     $BABELFILT -o "$OUTFMT" -F $OUTFILE
1739                 if [ $? != 0 ]; then
1740                     error "gpsbabel returned error code [5]"
1741                 fi
1742             fi
1743     fi
1744
1745     #
1746     #   Optionally, print the HTML pages
1747     #
1748     if [ "$CMDPIPE" != "" ]; then
1749         OIFS="$IFS"
1750         IFS="   "
1751         while read id desc lat lon url diff terr container strtype \
1752             vartime ifound soc iplaced placedt foundt ifoundt extra; do
1753             url="$url&decrypt=y"
1754             echo "Print: $url"
1755             HTMLPAGE2=$TMP.html
1756             CRUFT="$CRUFT $HTMLPAGE2"
1757             debug 1 "curl $url" >&2
1758             dbgcmd curl $CURL_OPTS -s -A "$UA" -b $COOKIE_FILE "$url" > $HTMLPAGE2
1759             htmldoc --quiet -t ps --nup 2 --fontsize 14 --webpage $HTMLPAGE2 \
1760                 | psselect -q -p1-1 | eval $CMDPIPE
1761             # exit
1762         done < $MERGEFILE
1763         IFS="$OIFS"
1764     fi
1765
1766     #
1767     #   Optionally, fetch printable HTML pages
1768     #
1769     if [ "$HTMLDIR" != ""  -o "$LOGDIR" != "" ]; then
1770         if [ "$HTMLDIR" != "" -a ! -d "$HTMLDIR" ]; then
1771             mkdir "$HTMLDIR" || error "Couldn't mkdir $HTMLDIR"
1772         fi
1773         if [ "$LOGDIR" != "" -a ! -d "$LOGDIR" ]; then
1774             mkdir "$LOGDIR" || error "Couldn't mkdir $LOGDIR"
1775         fi
1776
1777         HTMLPAGE2=$TMP.html
1778         CRUFT="$CRUFT $HTMLPAGE2"
1779         TIMESTAMP=$TMP.time
1780         CRUFT="$CRUFT $TIMESTAMP"
1781
1782         fetchcnt=0
1783         fetchmax=1000
1784         if [ $DEBUG -ge 3 ]; then
1785             fetchmax=3
1786         fi
1787         OIFS="$IFS"
1788         IFS="   "
1789         while read id desc lat lon url diff terr container strtype \
1790             vartime ifound soc iplaced placedt foundt ifoundt extra; do
1791             #
1792             #   Don't fetch page if we already have a current version
1793             #
1794             if [ $placedt -gt $foundt ]; then
1795                 filetime="$placedt"
1796             else
1797                 filetime="$foundt"
1798             fi
1799             $touch -d "1/1/70 $filetime seconds last second" $TIMESTAMP
1800             if [ "$filetime" -gt 0 -a "$HTMLDIR/$id.html" -nt $TIMESTAMP ]; then
1801                 continue
1802             fi
1803
1804             # Basic member...
1805             if [ "$subscriber" == 0 -a "$HTMLDIR" != "" ]; then
1806                 debug 2 "cp $GEODIR/caches/$id.html $HTMLDIR/$id.html"
1807                 cp "$GEODIR/caches/$id.html" "$HTMLDIR/$id.html"
1808                 # debug 2 "f: $filetime"
1809                 if [ "$filetime" -gt 0 ]; then
1810                     $touch -d "1/1/70 $filetime seconds" "$HTMLDIR/$id.html"
1811                 fi
1812                 continue
1813             fi
1814
1815             # Limit to 1000 caches/day
1816             ((fetchcnt=fetchcnt+1))
1817             if [ $fetchcnt -gt $fetchmax ]; then
1818                 error "Fetch count exceeded $fetchmax.  Try tomorrow!"
1819             fi
1820
1821             # Be kind to the server.  Do not remove this sleep
1822             sleep $GEOSLEEP
1823
1824             echo "<BASE HREF=http://www.geocaching.com/seek/>" > $HTMLPAGE
1825             debug 1 "curl $url" >&2
1826             dbgcmd curl $CURL_OPTS -s -A "$UA" -b $COOKIE_FILE "$url" |
1827                 tr -d "\001\007\010\013\017\020\031" >> $HTMLPAGE
1828             if [ $? != 0 ]; then
1829                 error "Couldn't fetch $id cache page"
1830             fi
1831
1832             size=$(ls -l $HTMLPAGE | awk '{print $5}')
1833             if [ $size -lt 1000 ]; then
1834                 debug 0 "Could not retrieve web page for cache $id"
1835                 continue
1836             fi
1837
1838             if [ "$HTMLDIR" != "" ]; then
1839                 cp $HTMLPAGE "$HTMLDIR/$id.html" ||
1840                     error "Couldn't copy $id cache page"
1841                 if [ "$filetime" -gt 0 ]; then
1842                     $touch -d "1/1/70 $filetime seconds" "$HTMLDIR/$id.html"
1843                 fi
1844             fi
1845
1846             if [ "$LOGDIR" != "" ]; then
1847                 sed -e '1,/Cache find counts/d' -e 's/<STRONG><IMG SRC=/\
1848 &/g' < $HTMLPAGE |
1849                 egrep ">$LOGUSERNAME<|strong> \($LOGUSERNAME\) \(" > $HTMLPAGE2
1850                 lynx -dump $HTMLPAGE2 > $LOGDIR/$id.log
1851                 if [ "$filetime" -gt 0 ]; then
1852                     $touch -d "1/1/70 $filetime seconds" "$LOGDIR/$id.log"
1853                 fi
1854             fi
1855         done < $MERGEFILE
1856         IFS="$OIFS"
1857
1858         if [ "$LOGDIR" != "" ]; then
1859             # This is a hack, and might be innaccurate
1860             echo -n "Finds:" >&2
1861             MONTHS="  January |  February |  March |  April |  May |  June "
1862             MONTHS="$MONTHS|  July |  August | September |  October "
1863             MONTHS="$MONTHS|  November |  December "
1864             egrep "$MONTHS" $LOGDIR/*.log |
1865             egrep "icon_smile|icon_happy|icon_camera" | wc -l >&2
1866         fi
1867
1868     fi
1869 }
1870
1871 ##############################################################################
1872 # end #include "geo-common-gc"
1873 ##############################################################################
1874 ##############################################################################
1875 # begin #include "geo-common-gpsdrive"
1876 ##############################################################################
1877
1878 #
1879 # default MySQL global options...
1880 #
1881 SQLUSER=gast
1882 SQLPASS=gast
1883 SQLDB=geoinfo
1884 SQLITEDB=$HOME/.gpsdrive/waypoints.db
1885 SQLTAG=Geocache
1886
1887 #
1888 # procedures for updating gpsdrive database via MySQL
1889 #
1890 #       Global Vars:    $SQLDB, $SQLTAG $OUTFILE
1891 #
1892 gpsdrive_create_210() {
1893     echo "CREATE TABLE poi ("
1894     echo "poi_id        INTEGER      PRIMARY KEY,"
1895     echo "name          VARCHAR(80)  NOT NULL default 'not specified',"
1896     echo "poi_type      VARCHAR(160) NOT NULL default 'unknown',"
1897     echo "lat           DOUBLE       NOT NULL default '0',"
1898     echo "lon           DOUBLE       NOT NULL default '0',"
1899     echo "alt           DOUBLE                default '0',"
1900     echo "comment       VARCHAR(255)          default NULL,"
1901     echo "last_modified DATETIME     NOT NULL default '0000-00-00',"
1902     echo "source_id     INTEGER      NOT NULL default '1',"
1903     echo "private       CHAR(1)               default NULL);"
1904     echo "CREATE TABLE poi_extra ("
1905     echo "poi_id         INTEGER       NOT NULL default '0',"
1906     echo "field_name     VARCHAR(160)  NOT NULL default '0',"
1907     echo "entry          VARCHAR(8192) default NULL);"
1908 }
1909
1910 gpsdrive_purge() {
1911     case "$GPSDRIVE_VER" in
1912     ""|"2.09")
1913         delcmd="delete from waypoints"
1914         echo "use $SQLDB;"
1915         echo "$delcmd where type like '$SQLTAG%';"
1916         ;;
1917     "2.10")
1918         if [ ! -s $SQLITEDB ]; then
1919             gpsdrive_create_210
1920         fi
1921         delcmd="delete from poi"
1922         echo "$delcmd where poi_type like '$SQLTAG%';"
1923         ;;
1924     esac
1925 }
1926
1927 gpsdrive_add_209() {
1928         delcmd="delete from waypoints"
1929         addcmd="replace into waypoints (name,lat,lon,type)"
1930         sqltag="$1"
1931         echo "use $SQLDB;"
1932         while read name lat lon type extra
1933         do
1934                 name=`echo "$name" | tr -d "'"`
1935                 # Primary key is autoincrementing id number, so delete
1936                 # the old record (if any) by name and type
1937                 if [ $PURGE = 0 ]; then
1938                     echo "$delcmd where name='$name' and type like '$SQLTAG%';"
1939                 fi
1940
1941                 if [ $DELETE = 0 ]; then
1942                     # Add the new record
1943                     if [ "$sqltag" = "Geocache" ]; then
1944                         tag="$type"
1945                     else
1946                         tag="$sqltag"
1947                     fi
1948                     echo "$addcmd values ('$name','$lat','$lon','$tag');"
1949                 fi
1950         done
1951 }
1952
1953 gpsdrive_add_210(){
1954     if [ ! -s $SQLITEDB ]; then
1955         gpsdrive_create_210
1956     fi
1957     delcmd="delete from poi"
1958     addcmd="replace into poi (poi_id,name,poi_type,lat,lon,alt,comment,last_modified)"
1959     sqltag="$1"
1960     sqltag=`echo "$sqltag" | tr A-Z a-z`
1961     OIFS="$IFS"
1962     IFS="|"
1963     #while read name lat lon type extra
1964     poi_id=0
1965     egrep -v 'Geocache Found|-ifound' | tr '    ' '|' | tr -d "'" |
1966     while read index shortname description notes url urltext icon lat lon \
1967         lat32 lon32 latdecdir londecdir latdirdec londirdec latdir londir \
1968         altfeet altmeters excel timet diff terr container type \
1969         pathmiles pathkm placer yyyymmmdd hint lastfound extra
1970     do
1971         if [ "$placer" = "$USERNAME" ]; then
1972             continue
1973         fi
1974         if [ "$placer" = "dyl1231" ]; then
1975             continue
1976         fi
1977         name=`echo "$description" | tr -d "'"`
1978         # Primary key is autoincrementing id number, so delete
1979         # the old record (if any) by name and type
1980         if [ $PURGE = 0 ]; then
1981             echo "$delcmd where name='$name' and poi_type like '%$sqltag%';"
1982         fi
1983
1984         ((poi_id=poi_id+1))
1985         if [ $DELETE = 0 ]; then
1986             # Add the new record
1987             if [ "$sqltag" = "geocache" ]; then
1988                 tag="$type"
1989             else
1990                 tag="$sqltag"
1991             fi
1992             case "$type" in
1993             "Earthcache")       poi_type="geocache.geocache_earth";;
1994             "Event Cache")      poi_type="geocache.geocache_event";;
1995             "Mega-Event Cache") poi_type="geocache.geocache_event";;
1996             "Cache In Trash Out Event") poi_type="geocache.geocache_event";;
1997             "found")            poi_type="geocache.geocache_found";;
1998             "Multi-cache")      poi_type="geocache.geocache_multi";;
1999             "Unknown Cache")    poi_type="geocache.geocache_mystery";;
2000             "night")            poi_type="geocache.geocache_night";;
2001             "Traditional Cache") poi_type="geocache.geocache_traditional";;
2002             "Virtual Cache")    poi_type="geocache.geocache_virtual";;
2003             "Webcam Cache")     poi_type="geocache.geocache_webcam";;
2004             *)                      poi_type="geocache";;
2005             esac
2006             echo -n "$addcmd values ($poi_id,'$name','$poi_type',"
2007             echo -n "'$lat','$lon',"
2008             echo -n "'0.0'," #alt
2009             echo -n "'$type $container $diff/$terr. Last Found: $lastfound.  $hint',"
2010             echo "'0');"
2011         fi
2012     done
2013     IFS="$OIFS"
2014 }
2015
2016 gpsdrive_add() {
2017     case "$GPSDRIVE_VER" in
2018     ""|"2.09")  gpsdrive_add_209 "$1";;
2019     "2.10")     gpsdrive_add_210 "$1";;
2020     esac
2021 }
2022
2023 gpsdrive_mysql() {
2024     if [ "$OUTFILE" != "" ]; then
2025         cat >> $OUTFILE
2026     elif [ $DEBUG -gt 0 ]; then
2027         cat
2028     else
2029         mysql -u$SQLUSER -p$SQLPASS
2030     fi
2031 }
2032
2033 gpsdrive_sqlite3() {
2034     if [ "$OUTFILE" != "" ]; then
2035         cat >> $OUTFILE
2036     elif [ $DEBUG -gt 0 ]; then
2037         cat
2038     else
2039         sqlite3 $HOME/.gpsdrive/waypoints.db
2040     fi
2041 }
2042
2043 #
2044 # Extended list of gpsbabel output formats
2045 #
2046 gpsbabel_formats() {
2047     gpsbabel -? | sed -e '1,/File Types/d' -e '/Supported data filters/,$d'
2048     echo        "       gpsdrive.sql         " \
2049             "GpsDrive direct MySQL database insertion"
2050     echo        "       map[,geo-map-opts]   " \
2051             "Display map of waypoints using geo-map"
2052 }
2053
2054 ##############################################################################
2055 # end #include "geo-common-gpsdrive"
2056 ##############################################################################
2057
2058 #
2059 #       Set default options, can be overriden on command line or in rc file
2060 #
2061 UPDATE_URL=$WEBHOME/geo-nearest
2062 UPDATE_FILE=geo-nearest.new
2063
2064 read_rc_file
2065
2066 #
2067 #       Process the options
2068 #
2069
2070 gc_getopts "$@"
2071 shift $?
2072
2073 #
2074 #       Main Program
2075 #
2076 case "$#" in
2077 6)
2078         # Cut and paste from geocaching.com cache page
2079         # N 44° 58.630 W 093° 09.310
2080         LAT=`echo "$1$2.$3" | tr -d '\260\302' `
2081         LAT=`latlon $LAT`
2082         LON=`echo "$4$5.$6" | tr -d '\260\302' `
2083         LON=`latlon $LON`
2084         SEARCH="?origin_lat=$LAT&origin_long=$LON"
2085         ;;
2086 2)
2087         LAT=`latlon $1`
2088         LON=`latlon $2`
2089         SEARCH="?origin_lat=$LAT&origin_long=$LON"
2090         ;;
2091 1)
2092         case "$1" in
2093         iraq|Iraq) SEARCH="?country_id=97" ;;
2094         u=*)
2095             SEARCH="?$1"
2096             ;;
2097         pq=*)
2098             SEARCH="?$1"
2099             ;;
2100         tx=*)
2101             LAT=`latlon $LAT`
2102             LON=`latlon $LON`
2103             SEARCH="?$1&lat=$LAT&lng=$LON"
2104             ;;
2105         guid=*)
2106             SEARCH="bookmarks/view.aspx?$1"
2107             ;;
2108         *[0-9]*)
2109             ZIP=$1
2110             SEARCH="?zip=$ZIP"
2111             ;;
2112         *)
2113             error "'$1' isn't something I understand how to search for"
2114             ;;
2115         esac
2116         ;;
2117 0)
2118         SEARCH="?origin_lat=$LAT&origin_long=$LON"
2119         ;;
2120 *)
2121         usage
2122         ;;
2123 esac
2124
2125 gc_query