]> git.street.me.uk Git - andy/viking.git/blame - src/osm-traces.c
Add realtime tracking to GPS layer.
[andy/viking.git] / src / osm-traces.c
CommitLineData
3e7553ae
GB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2007, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <errno.h>
28
29#include <curl/curl.h>
30#include <curl/types.h>
31#include <curl/easy.h>
32
33#include <glib.h>
34#include <glib/gstdio.h>
35
36#include "viking.h"
37#include "viktrwlayer.h"
38#include "osm-traces.h"
39#include "gpx.h"
40#include "background.h"
41
42/**
43 * Login to use for OSM uploading.
44 */
45static gchar *user = NULL;
46
47/**
48 * Password to use for OSM uploading.
49 */
50static gchar *password = NULL;
51
52/**
53 * Mutex to protect auth. token
54 */
55static GMutex *login_mutex = NULL;
56
57/**
58 * Struct hosting needed info.
59 */
60typedef struct _OsmTracesInfo {
61 gchar *name;
62 gchar *description;
63 gchar *tags;
64 gboolean public;
65 VikTrwLayer *vtl;
5092de80 66 gchar *track_name;
3e7553ae
GB
67} OsmTracesInfo;
68
69/**
70 * Free an OsmTracesInfo struct.
71 */
72static void oti_free(OsmTracesInfo *oti)
73{
74 if (oti) {
75 /* Fields have been g_strdup'ed */
76 g_free(oti->name); oti->name = NULL;
77 g_free(oti->description); oti->description = NULL;
78 g_free(oti->tags); oti->tags = NULL;
5092de80 79 g_free(oti->track_name); oti->track_name = NULL;
3e7553ae
GB
80
81 g_object_unref(oti->vtl); oti->vtl = NULL;
82 }
83 /* Main struct has been g_malloc'ed */
84 g_free(oti);
85}
86
624318ca 87static const gchar *get_default_user()
51c15f41
GB
88{
89 const gchar *default_user = NULL;
90
91 /* Retrieve "standard" EMAIL varenv */
92 default_user = g_getenv("EMAIL");
93
94 return default_user;
95}
96
3e7553ae
GB
97static void set_login(const gchar *user_, const gchar *password_)
98{
99 /* Allocate mutex */
100 if (login_mutex == NULL)
101 {
102 login_mutex = g_mutex_new();
103 }
104 g_mutex_lock(login_mutex);
105 g_free(user); user = NULL;
106 g_free(password); password = NULL;
107 user = g_strdup(user_);
108 password = g_strdup(password_);
109 g_mutex_unlock(login_mutex);
110}
111
112static gchar *get_login()
113{
114 gchar *user_pass = NULL;
115 g_mutex_lock(login_mutex);
116 user_pass = g_strdup_printf("%s:%s", user, password);
117 g_mutex_unlock(login_mutex);
118 return user_pass;
119}
120
121/*
122 * Upload a file
123 */
124void osm_traces_upload_file(const char *user,
125 const char *password,
126 const char *file,
127 const char *filename,
128 const char *description,
129 const char *tags,
130 gboolean public)
131{
132 CURL *curl;
133 CURLcode res;
134 char curl_error_buffer[CURL_ERROR_SIZE];
135 struct curl_slist *headers = NULL;
136 struct curl_httppost *post=NULL;
137 struct curl_httppost *last=NULL;
138 gchar *public_string;
139
140 char *base_url = "http://www.openstreetmap.org/api/0.4/gpx/create";
141
142 gchar *user_pass = get_login();
143
144 g_debug("%s: %s %s %s %s %s %s", __FUNCTION__,
145 user, password, file, filename, description, tags);
146
147 /* Init CURL */
148 curl = curl_easy_init();
149
150 /* Filling the form */
151 curl_formadd(&post, &last,
152 CURLFORM_COPYNAME, "description",
153 CURLFORM_COPYCONTENTS, description, CURLFORM_END);
154 curl_formadd(&post, &last,
155 CURLFORM_COPYNAME, "tags",
156 CURLFORM_COPYCONTENTS, tags, CURLFORM_END);
3e7553ae
GB
157 if (public)
158 public_string = "1";
159 else
160 public_string = "0";
161 curl_formadd(&post, &last,
162 CURLFORM_COPYNAME, "public",
163 CURLFORM_COPYCONTENTS, public_string, CURLFORM_END);
164 curl_formadd(&post, &last,
165 CURLFORM_COPYNAME, "file",
166 CURLFORM_FILE, file,
167 CURLFORM_FILENAME, filename,
168 CURLFORM_CONTENTTYPE, "text/xml", CURLFORM_END);
169
170 /* Prepare request */
171 /* As explained in http://wiki.openstreetmap.org/index.php/User:LA2 */
172 /* Expect: header seems to produce incompatibilites between curl and httpd */
173 headers = curl_slist_append(headers, "Expect: ");
174 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
175 curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
176 curl_easy_setopt(curl, CURLOPT_URL, base_url);
177 curl_easy_setopt(curl, CURLOPT_USERPWD, user_pass);
178 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
179 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &curl_error_buffer);
180
181 /* Execute request */
182 res = curl_easy_perform(curl);
183 if (res == CURLE_OK)
184 {
185 long code;
186 res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
187 if (res == CURLE_OK)
188 {
189 g_debug("received valid curl response: %ld", code);
190 if (code != 200)
191 g_warning("failed to upload data: HTTP response is %ld", code);
192 }
193 else
194 g_error("curl_easy_getinfo failed: %d", res);
195 }
196 else
197 {
198 g_warning("curl request failed: %s", curl_error_buffer);
199 }
200
201 /* Memory */
202 g_free(user_pass); user_pass = NULL;
203
204 curl_formfree(post);
205 curl_easy_cleanup(curl);
206}
207
208/**
209 * uploading function executed by the background" thread
210 */
211static void osm_traces_upload_thread ( OsmTracesInfo *oti, gpointer threaddata )
212{
213 FILE *file = NULL;
214 gchar *filename = NULL;
215 int fd;
216 GError *error = NULL;
217 int ret;
218
219 g_assert(oti != NULL);
220
221 /* Opening temporary file */
222 fd = g_file_open_tmp("viking_osm_upload_XXXXXX.gpx", &filename, &error);
223 if (fd < 0) {
224 g_error("failed to open temporary file: %s", strerror(errno));
225 return;
226 }
227 g_clear_error(&error);
228 g_debug("%s: temporary file = %s", __FUNCTION__, filename);
229
230 /* Creating FILE* */
231 file = fdopen(fd, "w");
232
233 /* writing gpx file */
5092de80
GB
234 if (oti->track_name != NULL)
235 {
236 /* Upload only the selected track */
237 VikTrack *track = vik_trw_layer_get_track(oti->vtl, oti->track_name);
238 a_gpx_write_track_file(oti->track_name, track, file);
239 }
240 else
241 /* Upload the whole VikTrwLayer */
242 a_gpx_write_file(oti->vtl, file);
3e7553ae
GB
243
244 /* We can close the file */
245 /* This also close the associated fd */
246 fclose(file);
247
248 /* finally, upload it */
249 osm_traces_upload_file(user, password, filename,
250 oti->name, oti->description, oti->tags, oti->public);
251
252 /* Removing temporary file */
253 ret = g_unlink(filename);
254 if (ret != 0) {
255 g_error("failed to unlink temporary file: %s", strerror(errno));
256 }
257}
258
259/**
260 * Uploading a VikTrwLayer
5092de80
GB
261 *
262 * @param vtl VikTrwLayer
263 * @param track_name if not null, the name of the track to upload
3e7553ae 264 */
5092de80 265static void osm_traces_upload_viktrwlayer ( VikTrwLayer *vtl, const gchar *track_name )
3e7553ae
GB
266{
267 GtkWidget *dia = gtk_dialog_new_with_buttons ("OSM upload",
268 VIK_GTK_WINDOW_FROM_LAYER(vtl),
269 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
270 GTK_STOCK_CANCEL,
271 GTK_RESPONSE_REJECT,
272 GTK_STOCK_OK,
273 GTK_RESPONSE_ACCEPT,
274 NULL);
275
276 const gchar *name = NULL;
277 GtkWidget *user_label, *user_entry;
278 GtkWidget *password_label, *password_entry;
279 GtkWidget *name_label, *name_entry;
280 GtkWidget *description_label, *description_entry;
281 GtkWidget *tags_label, *tags_entry;
282 GtkWidget *public;
283 GtkTooltips* dialog_tips;
284
285 dialog_tips = gtk_tooltips_new();
286
287 user_label = gtk_label_new("Email:");
288 user_entry = gtk_entry_new();
289 if (user != NULL)
290 gtk_entry_set_text(GTK_ENTRY(user_entry), user);
51c15f41
GB
291 else
292 {
293 const gchar *default_user = get_default_user();
294 if (default_user != NULL)
295 gtk_entry_set_text(GTK_ENTRY(user_entry), default_user);
296 }
3e7553ae
GB
297 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), user_label, FALSE, FALSE, 0);
298 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), user_entry, FALSE, FALSE, 0);
299 gtk_widget_show_all ( user_label );
300 gtk_widget_show_all ( user_entry );
301 gtk_tooltips_set_tip (dialog_tips, user_entry,
302 "The email used as login",
303 "Enter the email you use to login into www.openstreetmap.org.");
304
305 password_label = gtk_label_new("Password:");
306 password_entry = gtk_entry_new();
307 if (password != NULL)
308 gtk_entry_set_text(GTK_ENTRY(password_entry), password);
309 /* This is a password -> invisible */
310 gtk_entry_set_visibility(GTK_ENTRY(password_entry), FALSE);
311 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), password_label, FALSE, FALSE, 0);
312 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), password_entry, FALSE, FALSE, 0);
313 gtk_widget_show_all ( password_label );
314 gtk_widget_show_all ( password_entry );
315 gtk_tooltips_set_tip (dialog_tips, password_entry,
316 "The password used to login",
317 "Enter the password you use to login into www.openstreetmap.org.");
318
319 name_label = gtk_label_new("File's name:");
320 name_entry = gtk_entry_new();
5092de80
GB
321 if (track_name != NULL)
322 name = track_name;
323 else
324 name = vik_layer_get_name(VIK_LAYER(vtl));
3e7553ae
GB
325 gtk_entry_set_text(GTK_ENTRY(name_entry), name);
326 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), name_label, FALSE, FALSE, 0);
327 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), name_entry, FALSE, FALSE, 0);
328 gtk_widget_show_all ( name_label );
329 gtk_widget_show_all ( name_entry );
330 gtk_tooltips_set_tip (dialog_tips, name_entry,
331 "The name of the file on OSM",
332 "This is the name of the file created on the server. "
333 "This is not the name of the local file.");
334
335 description_label = gtk_label_new("Description:");
336 description_entry = gtk_entry_new();
337 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), description_label, FALSE, FALSE, 0);
338 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), description_entry, FALSE, FALSE, 0);
339 gtk_widget_show_all ( description_label );
340 gtk_widget_show_all ( description_entry );
341 gtk_tooltips_set_tip (dialog_tips, description_entry,
342 "The description of the trace",
343 "");
344
345 tags_label = gtk_label_new("Tags:");
346 tags_entry = gtk_entry_new();
347 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), tags_label, FALSE, FALSE, 0);
348 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), tags_entry, FALSE, FALSE, 0);
349 gtk_widget_show_all ( tags_label );
350 gtk_widget_show_all ( tags_entry );
351 gtk_tooltips_set_tip (dialog_tips, tags_entry,
352 "The tags associated to the trace",
353 "");
354
355 public = gtk_check_button_new_with_label("Public");
356 /* Set public by default */
357 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(public), TRUE);
358 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), public, FALSE, FALSE, 0);
359 gtk_widget_show_all ( public );
360 gtk_tooltips_set_tip (dialog_tips, public,
361 "Indicates if the trace is public or not",
362 "");
363
364 if ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
365 {
366 gchar *title = NULL;
367
368 /* overwrite authentication info */
369 set_login(gtk_entry_get_text(GTK_ENTRY(user_entry)),
370 gtk_entry_get_text(GTK_ENTRY(password_entry)));
371
372 /* Storing data for the future thread */
373 OsmTracesInfo *info = g_malloc(sizeof(OsmTracesInfo));
374 info->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(name_entry)));
375 info->description = g_strdup(gtk_entry_get_text(GTK_ENTRY(description_entry)));
376 /* TODO Normalize tags: they will be used as URL part */
377 info->tags = g_strdup(gtk_entry_get_text(GTK_ENTRY(tags_entry)));
378 info->public = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(public));
379 info->vtl = VIK_TRW_LAYER(g_object_ref(vtl));
5092de80 380 info->track_name = (track_name == NULL) ? NULL : g_strdup(track_name);
3e7553ae
GB
381
382 title = g_strdup_printf("Uploading %s to OSM", info->name);
383
384 /* launch the thread */
385 a_background_thread(VIK_GTK_WINDOW_FROM_LAYER(vtl), /* parent window */
386 title, /* description string */
387 (vik_thr_func) osm_traces_upload_thread, /* function to call within thread */
388 info, /* pass along data */
389 (vik_thr_free_func) oti_free, /* function to free pass along data */
390 (vik_thr_free_func) NULL,
391 1 );
392 g_free ( title ); title = NULL;
393 }
394 gtk_widget_destroy ( dia );
395}
396
397/**
5092de80 398 * Function called by the entry menu of a TrwLayer
3e7553ae
GB
399 */
400void osm_traces_upload_cb ( gpointer layer_and_vlp[2], guint file_type )
401{
5092de80
GB
402 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(layer_and_vlp[0]), NULL);
403}
404
405/**
406 * Function called by the entry menu of a single track
407 */
408void osm_traces_upload_track_cb ( gpointer pass_along[6] )
409{
410 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along[0]), pass_along[3]);
3e7553ae 411}