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