1 /*
2 Copyright (C) 2003 Robert Lipe, robertlipe@usa.net
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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
17
18 */
19 #include "defs.h"
20 #include "cet_util.h"
21 #if HAVE_LIBEXPAT
22 #include <expat.h>
23 static XML_Parser psr;
24 #endif
25
26 static waypoint* wpt_tmp;
27
28 static gbfile* fin, *fout;
29
30 static char* noretired = NULL;
31
32 static
33 arglist_t nav_args[] = {
34 {
35 "noretired", &noretired, "Suppress retired geocaches",
36 NULL, ARGTYPE_BOOL, ARG_NOMINMAX
37 },
38 ARG_TERMINATOR
39 };
40
41 #define MYNAME "navicache"
42 #define MY_CBUF 4096
43 #define NC_URL "http://www.navicache.com/cgi-bin/db/displaycache2.pl?CacheID="
44
45 #if ! HAVE_LIBEXPAT
46 static void
nav_rd_init(const char * fname)47 nav_rd_init(const char* fname)
48 {
49 fatal(MYNAME ": This build excluded GPX support because expat was not installed.\n");
50 }
51
52 static void
nav_read(void)53 nav_read(void)
54 {
55 }
56 #else
57
58 static struct
59 nc_type_mapping {
60 geocache_type type;
61 const char* name;
62 } nc_type_map[] = {
63 { gt_unknown, "unknown" },
64 { gt_traditional, "normal" },
65 { gt_multi, "Multi-part" },
66 { gt_virtual, "Virtual" },
67 { gt_event, "event" }
68 };
69
70 static struct
71 nc_container_mapping {
72 geocache_container type;
73 const char* name;
74 } nc_container_map[] = {
75 { gc_other, "Unknown" },
76 { gc_micro, "Micro" },
77 { gc_regular, "Normal" },
78 { gc_large, "Large" },
79 { gc_virtual, "Virtual" }
80 };
81
82 static
83 geocache_type
nc_mktype(const char * t)84 nc_mktype(const char* t)
85 {
86 int i;
87 int sz = sizeof(nc_type_map) / sizeof(nc_type_map[0]);
88
89 for (i = 0; i < sz; i++) {
90 if (0 == case_ignore_strcmp(t, nc_type_map[i].name)) {
91 return nc_type_map[i].type;
92 }
93 }
94 return gt_unknown;
95 }
96
97 static
98 geocache_container
nc_mkcont(const char * t)99 nc_mkcont(const char* t)
100 {
101 int i;
102 int sz = sizeof(nc_container_map) / sizeof(nc_container_map[0]);
103
104 for (i = 0; i < sz; i++) {
105 if (0 == case_ignore_strcmp(t, nc_container_map[i].name)) {
106 return nc_container_map[i].type;
107 }
108 }
109 return gc_unknown;
110 }
111
112 static void
nav_start(void * data,const XML_Char * xml_el,const XML_Char ** xml_attr)113 nav_start(void* data, const XML_Char* xml_el, const XML_Char** xml_attr)
114 {
115 const char* el;
116 const char** attr;
117
118 el = xml_convert_to_char_string(xml_el);
119 attr = xml_convert_attrs_to_char_string(xml_attr);
120 if (0 == strcmp(el, "CacheDetails")) {
121 const char** ap;
122 geocache_data* gc_data;
123 wpt_tmp = waypt_new();
124 gc_data = waypt_alloc_gc_data(wpt_tmp);
125
126 for (ap = attr; *ap; ap+=2) {
127 if (0 == strcmp(ap[0], "cache_id")) {
128 int id;
129
130 id = atoi(ap[1]);
131 xasprintf(&wpt_tmp->shortname, "N%05X", id);
132 xasprintf(&wpt_tmp->url, "%s%d", NC_URL, id);
133 } else if (0 == strcmp(ap[0], "name")) {
134 wpt_tmp->description = xstrdup(ap[1]);
135 } else if (0 == strcmp(ap[0], "user_name")) {
136 gc_data->placer = xstrdup(ap[1]);
137 } else if (0 == strcmp(ap[0], "latitude")) {
138 sscanf(ap[1], "%lf",
139 &wpt_tmp->latitude);
140 } else if (0 == strcmp(ap[0], "longitude")) {
141 sscanf(ap[1], "%lf",
142 &wpt_tmp->longitude);
143 } else if (0 == strcmp(ap[0], "longitude")) {
144 sscanf(ap[1], "%lf",
145 &wpt_tmp->longitude);
146 } else if (0 == strcmp(ap[0], "difficulty")) {
147 float x;
148 sscanf(ap[1], "%f", &x);
149 gc_data->diff = x * 10;
150 } else if (0 == strcmp(ap[0], "terrain")) {
151 float x;
152 sscanf(ap[1], "%f", &x);
153 gc_data->terr = x * 10;
154 } else if (0 == strcmp(ap[0], "cache_type")) {
155 gc_data->type = nc_mktype(ap[1]);
156 if (!strcmp(ap[1], "normal")) {
157 wpt_tmp->icon_descr = "Geocache-regular";
158 } else if (!strcmp(ap[1], "multi-part")) {
159 wpt_tmp->icon_descr = "Geocache-multi";
160 } else if (!strcmp(ap[1], "moving_travelling")) {
161 wpt_tmp->icon_descr = "Geocache-moving";
162 } else {
163 // WARNING: casting away const-ness.
164 xasprintf((char**)&wpt_tmp->icon_descr,
165 "Geocache-%-.20s", ap[1]);
166 }
167 } else if (0 == strcmp(ap[0], "hidden_date")) {
168 struct tm tm;
169
170 sscanf(ap[1], "%d-%d-%d",
171 &tm.tm_year,
172 &tm.tm_mon,
173 &tm.tm_mday);
174 tm.tm_mon -= 1;
175 tm.tm_year -= 1900;
176 tm.tm_isdst = 0;
177 tm.tm_hour = 0;
178 tm.tm_min = 0;
179 tm.tm_sec = 0;
180 wpt_tmp->creation_time = mktime(&tm);
181 } else if (0 == strcmp(ap[0], "retired")) {
182 if (!strcmp(ap[1], "yes") && noretired) {
183 xfree(wpt_tmp);
184 return;
185 }
186 } else if (0 == strcmp(ap[0], "cache_size")) {
187 gc_data->container = nc_mkcont(ap[1]);
188 } else if (0 == strcmp(ap[0], "description")) {
189 gc_data->desc_long.is_html = 1;
190 gc_data->desc_long.utfstring = xstrdup(ap[1]);
191 } else if (0 == strcmp(ap[0], "comments")) {
192 gc_data->desc_short.is_html = 1;
193 gc_data->desc_short.utfstring = xstrdup(ap[1]);
194 }
195 }
196 waypt_add(wpt_tmp);
197 }
198
199 xml_free_converted_attrs(attr);
200 xml_free_converted_string(el);
201 }
202
203 static void
nav_end(void * data,const XML_Char * el)204 nav_end(void* data, const XML_Char* el)
205 {
206 }
207
208 static void
nav_rd_init(const char * fname)209 nav_rd_init(const char* fname)
210 {
211 fin = gbfopen(fname, "r", MYNAME);
212
213 psr = XML_ParserCreate(NULL);
214 if (!psr) {
215 fatal(MYNAME ":Cannot create XML parser\n");
216 }
217
218 XML_SetUnknownEncodingHandler(psr, cet_lib_expat_UnknownEncodingHandler, NULL);
219 XML_SetElementHandler(psr, nav_start, nav_end);
220 }
221
222 static void
nav_read(void)223 nav_read(void)
224 {
225 int len;
226 char buf[MY_CBUF];
227
228 while ((len = gbfread(buf, 1, sizeof(buf), fin))) {
229 if (!XML_Parse(psr, buf, len, gbfeof(fin))) {
230 fatal(MYNAME ":Parse error at %d: %s\n",
231 (int) XML_GetCurrentLineNumber(psr),
232 XML_ErrorString(XML_GetErrorCode(psr)));
233 }
234 }
235
236 XML_ParserFree(psr);
237 }
238
239 #endif
240
241 static void
nav_rd_deinit(void)242 nav_rd_deinit(void)
243 {
244 gbfclose(fin);
245 }
246
247 static void
nav_wr_init(const char * fname)248 nav_wr_init(const char* fname)
249 {
250 fatal(MYNAME ": Does not support writing Navicache files.\n");
251 fout = gbfopen(fname, "w", MYNAME);
252 }
253
254 static void
nav_wr_deinit(void)255 nav_wr_deinit(void)
256 {
257 gbfclose(fout);
258 }
259
260 static void
nav_write(void)261 nav_write(void)
262 {
263 }
264
265 ff_vecs_t navicache_vecs = {
266 ff_type_file,
267 { ff_cap_read, ff_cap_none, ff_cap_none },
268 nav_rd_init,
269 nav_wr_init,
270 nav_rd_deinit,
271 nav_wr_deinit,
272 nav_read,
273 nav_write,
274 NULL,
275 nav_args,
276 CET_CHARSET_ASCII, 0 /* CET-REVIEW */
277 };
278