FIX:core: don't leak date when writing gpx logs
[navit-package] / navit / vehicle.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
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
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <glib.h>
23 #include "config.h"
24 #include "debug.h"
25 #include "coord.h"
26 #include "item.h"
27 #include "log.h"
28 #include "callback.h"
29 #include "plugin.h"
30 #include "vehicle.h"
31
32 struct vehicle {
33         struct vehicle_priv *priv;
34         struct vehicle_methods meth;
35         struct callback_list *cbl;
36         struct log *nmea_log, *gpx_log;
37         struct attr **attrs;
38 };
39
40 static void
41 vehicle_log_nmea(struct vehicle *this_, struct log *log)
42 {
43         struct attr pos_attr;
44         if (!this_->meth.position_attr_get)
45                 return;
46         if (!this_->meth.position_attr_get(this_->priv, attr_position_nmea, &pos_attr))
47                 return;
48         log_write(log, pos_attr.u.str, strlen(pos_attr.u.str));
49 }
50
51 static void
52 vehicle_log_gpx(struct vehicle *this_, struct log *log)
53 {
54         struct attr pos_attr;
55         char buffer[256];
56 #ifdef HAVE_GLIB
57         GTimeVal time; 
58         g_get_current_time(&time); 
59         gchar *iso8601 = g_time_val_to_iso8601(&time);
60 #endif
61
62         if (!this_->meth.position_attr_get)
63                 return;
64         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
65                 return;
66 #ifdef HAVE_GLIB
67         if (iso8601) {
68                 sprintf(buffer,"<trkpt lat=\"%f\" lon=\"%f\">\n\t<time>%s</time>\n</trkpt>\n",
69                         pos_attr.u.coord_geo->lat, pos_attr.u.coord_geo->lng, 
70                         iso8601);
71                 g_free(iso8601);
72         }
73 #else
74         sprintf(buffer,"<trkpt lat=\"%f\" lon=\"%f\">\n</trkpt>\n",
75                 pos_attr.u.coord_geo->lat, pos_attr.u.coord_geo->lng);
76 #endif
77         log_write(log, buffer, strlen(buffer));
78 }
79
80
81 static void
82 vehicle_log_textfile(struct vehicle *this_, struct log *log)
83 {
84         struct attr pos_attr;
85         char buffer[256];
86         if (!this_->meth.position_attr_get)
87                 return;
88         if (!this_->meth.position_attr_get(this_->priv, attr_position_coord_geo, &pos_attr))
89                 return;
90         sprintf(buffer,"%f %f type=trackpoint\n", pos_attr.u.coord_geo->lng, pos_attr.u.coord_geo->lat);
91         log_write(log, buffer, strlen(buffer));
92 }
93
94 static int
95 vehicle_add_log(struct vehicle *this_, struct log *log)
96 {
97         struct callback *cb;
98         struct attr type_attr;
99         if (!log_get_attr(log, attr_type, &type_attr, NULL))
100                 return 1;
101
102         if (!strcmp(type_attr.u.str, "nmea")) {
103                 cb=callback_new_2(callback_cast(vehicle_log_nmea), this_, log);
104         } else if (!strcmp(type_attr.u.str, "gpx")) {
105                 char *header =
106                     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx version=\"1.0\" creator=\"Navit http://navit.sourceforge.net\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n<trk>\n<trkseg>\n";
107                 char *trailer = "</trkseg>\n</trk>\n</gpx>\n";
108                 log_set_header(log, header, strlen(header));
109                 log_set_trailer(log, trailer, strlen(trailer));
110                 cb=callback_new_2(callback_cast(vehicle_log_gpx), this_, log);
111         } else if (!strcmp(type_attr.u.str, "textfile")) {
112                 char *header = "type=track\n";
113                 log_set_header(log, header, strlen(header));
114                 cb=callback_new_2(callback_cast(vehicle_log_textfile), this_, log);
115         } else
116                 return 1;
117         callback_list_add(this_->cbl, cb);
118         return 0;
119 }
120
121 struct vehicle *
122 vehicle_new(struct attr *parent, struct attr **attrs)
123 {
124         struct vehicle *this_;
125         struct attr *source;
126         struct vehicle_priv *(*vehicletype_new) (struct vehicle_methods *
127                                                  meth,
128                                                  struct callback_list *
129                                                  cbl,
130                                                  struct attr ** attrs);
131         char *type, *colon;
132
133         dbg(1, "enter\n");
134         source = attr_search(attrs, NULL, attr_source);
135         if (!source) {
136                 dbg(0, "no source\n");
137                 return NULL;
138         }
139
140         type = g_strdup(source->u.str);
141         colon = strchr(type, ':');
142         if (colon)
143                 *colon = '\0';
144         dbg(1, "source='%s' type='%s'\n", source->u.str, type);
145
146         vehicletype_new = plugin_get_vehicle_type(type);
147         if (!vehicletype_new) {
148                 dbg(0, "invalid type '%s'\n", type);
149                 return NULL;
150         }
151         this_ = g_new0(struct vehicle, 1);
152         this_->cbl = callback_list_new();
153         this_->priv = vehicletype_new(&this_->meth, this_->cbl, attrs);
154         if (!this_->priv) {
155                 dbg(0, "vehicletype_new failed\n");
156                 callback_list_destroy(this_->cbl);
157                 g_free(this_);
158                 return NULL;
159         }
160         this_->attrs=attr_list_dup(attrs);
161         dbg(1, "leave\n");
162
163         return this_;
164 }
165
166 int
167 vehicle_get_attr(struct vehicle *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
168 {
169         int ret;
170         if (this_->meth.position_attr_get) {
171                 ret=this_->meth.position_attr_get(this_->priv, type, attr);
172                 if (ret)
173                         return ret;
174         }
175         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
176 }
177
178 int
179 vehicle_set_attr(struct vehicle *this_, struct attr *attr,
180                  struct attr **attrs)
181 {
182         if (this_->meth.set_attr)
183                 return this_->meth.set_attr(this_->priv, attr, attrs);
184         return 0;
185 }
186
187 int
188 vehicle_add_attr(struct vehicle *this_, struct attr *attr)
189 {
190         switch (attr->type) {
191         case attr_callback:
192                 callback_list_add(this_->cbl, attr->u.callback);
193                 break;
194         case attr_log:
195                 return vehicle_add_log(this_, attr->u.log);
196         default:
197                 return 0;
198         }
199         return 1;
200 }
201
202 int
203 vehicle_remove_attr(struct vehicle *this_, struct attr *attr)
204 {
205         switch (attr->type) {
206         case attr_callback:
207                 callback_list_remove(this_->cbl, attr->u.callback);
208                 break;
209         default:
210                 return 0;
211         }
212         return 1;
213 }
214
215 void
216 vehicle_destroy(struct vehicle *this_)
217 {
218         callback_list_destroy(this_->cbl);
219         attr_list_free(this_->attrs);
220         g_free(this_);
221 }