1 /*
2     Copyright (C) 2003-2013 Robert Lipe, robertlipe+source@gpsbabel.org
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 
18  */
19 #include "defs.h"
20 #include "cet_util.h"
21 #include "src/core/file.h"
22 #include <QtCore/QXmlStreamReader>
23 
24 static char* noretired = nullptr;
25 static QString read_fname;
26 
27 static
28 QVector<arglist_t> nav_args = {
29   {
30     "noretired", &noretired, "Suppress retired geocaches",
31     nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
32   },
33 };
34 
35 #define MYNAME "navicache"
36 #define NC_URL	"http://www.navicache.com/cgi-bin/db/displaycache2.pl?CacheID="
37 
38 static struct
39     nc_type_mapping {
40   geocache_type type;
41   const char* name;
42 } nc_type_map[] = {
43   { gt_unknown, "unknown" },
44   { gt_traditional, "normal" },
45   { gt_multi, "Multi-part" },
46   { gt_virtual, "Virtual" },
47   { gt_event, "event" }
48 };
49 
50 static struct
51     nc_container_mapping {
52   geocache_container type;
53   const char* name;
54 } nc_container_map[] = {
55   { gc_other, "Unknown" },
56   { gc_micro, "Micro" },
57   { gc_regular, "Normal" },
58   { gc_large, "Large" },
59   { gc_virtual, "Virtual" }
60 };
61 
62 static
63 geocache_type
nc_mktype(const QString & t)64 nc_mktype(const QString& t)
65 {
66   int sz = sizeof(nc_type_map) / sizeof(nc_type_map[0]);
67 
68   for (int i = 0; i < sz; i++) {
69     if (0 == t.compare(nc_type_map[i].name, Qt::CaseInsensitive)) {
70       return nc_type_map[i].type;
71     }
72   }
73   return gt_unknown;
74 }
75 
76 static
77 geocache_container
nc_mkcont(const QString & t)78 nc_mkcont(const QString& t)
79 {
80   int sz = sizeof(nc_container_map) / sizeof(nc_container_map[0]);
81 
82   for (int i = 0; i < sz; i++) {
83     if (0 == t.compare(nc_container_map[i].name, Qt::CaseInsensitive)) {
84       return nc_container_map[i].type;
85     }
86   }
87   return gc_unknown;
88 }
89 
90 static void
nav_rd_init(const QString & fname)91 nav_rd_init(const QString& fname)
92 {
93   read_fname = fname;
94 }
95 
96 static void
NaviReadCache(const QXmlStreamReader & reader)97 NaviReadCache(const QXmlStreamReader& reader)
98 {
99   const QXmlStreamAttributes a = reader.attributes();
100   auto* wpt_tmp = new Waypoint;
101   geocache_data* gc_data = wpt_tmp->AllocGCData();
102   if (a.hasAttribute("cache_id")) {
103     int n = a.value("cache_id").toString().toInt();
104     QString fn = QString("N%1").arg(n, 5, 16, QChar('0'));
105     wpt_tmp->shortname = fn;
106 
107     UrlLink l(QString(NC_URL) + QString::number(n));
108     wpt_tmp->AddUrlLink(l);
109   }
110   if (a.hasAttribute("name")) {
111     wpt_tmp->description = a.value("name").toString();
112   }
113   if (a.hasAttribute("user_name")) {
114     gc_data->placer = a.value("user_name").toString();
115   }
116 
117   if (a.hasAttribute("latitude")) {
118     wpt_tmp->latitude = a.value("latitude").toString().toDouble();
119   }
120   if (a.hasAttribute("longitude")) {
121     wpt_tmp->longitude = a.value("longitude").toString().toDouble();
122   }
123 
124   if (a.hasAttribute("difficulty")) {
125     gc_data->diff = a.value("difficulty").toString().toDouble() * 10;
126   }
127   if (a.hasAttribute("terrain")) {
128     gc_data->terr = a.value("terrain").toString().toDouble() * 10;
129   }
130 
131   if (a.hasAttribute("cache_type")) {
132     QString t = a.value("cache_type").toString();
133     gc_data->type = nc_mktype(t);
134     if (t == "normal") {
135       wpt_tmp->icon_descr = "Geocache-regular";
136     } else if (t == "multi-part") {
137       wpt_tmp->icon_descr = "Geocache-multi";
138     } else if (t == "moving_travelling") {
139       wpt_tmp->icon_descr = "Geocache-moving";
140     } else {
141       wpt_tmp->icon_descr = QString("Geocache-%-%1").arg(t);
142     }
143   }
144 
145   if (a.hasAttribute("hidden_date")) {
146     QString h = a.value("hidden_date").toString();
147     QDateTime hd = QDateTime::fromString(h, "yyyy-MM-dd");
148     wpt_tmp->SetCreationTime(hd);
149   }
150 
151   if (a.hasAttribute("retired")) {
152     if (a.value("terrain").toString() == "yes" && noretired) {
153       delete wpt_tmp;
154       return;
155     }
156   }
157 
158   if (a.hasAttribute("cache_size")) {
159     gc_data->container = nc_mkcont(a.value("cache_size").toString());
160   }
161 
162   if (a.hasAttribute("description")) {
163     gc_data->desc_long.is_html = true;
164     gc_data->desc_long.utfstring = a.value("description").toString();
165   }
166 
167   if (a.hasAttribute("comments")) {
168     gc_data->desc_short.is_html = true;
169     gc_data->desc_short.utfstring = a.value("comments").toString();
170   }
171 
172 
173   waypt_add(wpt_tmp);
174 }
175 
176 static void
nav_read()177 nav_read()
178 {
179   QXmlStreamReader reader;
180   gpsbabel::File file(read_fname);
181   file.open(QIODevice::ReadOnly);
182   reader.setDevice(&file);
183 
184   while (!reader.atEnd()) {
185     if (reader.tokenType() == QXmlStreamReader::StartElement) {
186       if (reader.name() == "CacheDetails") {
187         NaviReadCache(reader);
188       }
189     }
190     reader.readNext();
191   }
192   if (reader.hasError())  {
193     fatal(MYNAME ":Read error: %s (%s, line %ld, col %ld)\n",
194           qPrintable(reader.errorString()),
195           qPrintable(file.fileName()),
196           (long) reader.lineNumber(),
197           (long) reader.columnNumber());
198   }
199 }
200 
201 static void
nav_rd_deinit()202 nav_rd_deinit()
203 {
204 }
205 
206 ff_vecs_t navicache_vecs = {
207   ff_type_file,
208   { ff_cap_read, ff_cap_none, ff_cap_none },
209   nav_rd_init,
210   nullptr,
211   nav_rd_deinit,
212   nullptr,
213   nav_read,
214   nullptr,
215   nullptr,
216   &nav_args,
217   CET_CHARSET_UTF8, 0	/* CET-REVIEW */
218   , NULL_POS_OPS,
219   nullptr
220 };
221