2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2007, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
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.
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.
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
29 #include <curl/curl.h>
30 #include <curl/types.h>
31 #include <curl/easy.h>
34 #include <glib/gstdio.h>
35 #include <glib/gi18n.h>
38 #include "viktrwlayer.h"
39 #include "osm-traces.h"
41 #include "background.h"
42 #include "preferences.h"
44 /* params will be osm_traces.username, osm_traces.password */
45 /* we have to make sure these don't collide. */
46 #define VIKING_OSM_TRACES_PARAMS_GROUP_KEY "osm_traces"
47 #define VIKING_OSM_TRACES_PARAMS_NAMESPACE "osm_traces."
50 * Login to use for OSM uploading.
52 static gchar
*user
= NULL
;
55 * Password to use for OSM uploading.
57 static gchar
*password
= NULL
;
60 * Mutex to protect auth. token
62 static GMutex
*login_mutex
= NULL
;
65 * Struct hosting needed info.
67 typedef struct _OsmTracesInfo
{
76 static VikLayerParam prefs
[] = {
77 { VIKING_OSM_TRACES_PARAMS_NAMESPACE
"username", VIK_LAYER_PARAM_STRING
, VIK_LAYER_GROUP_NONE
, N_("OSM username:"), VIK_LAYER_WIDGET_ENTRY
},
78 { VIKING_OSM_TRACES_PARAMS_NAMESPACE
"password", VIK_LAYER_PARAM_STRING
, VIK_LAYER_GROUP_NONE
, N_("OSM password:"), VIK_LAYER_WIDGET_PASSWORD
},
82 * Free an OsmTracesInfo struct.
84 static void oti_free(OsmTracesInfo
*oti
)
87 /* Fields have been g_strdup'ed */
88 g_free(oti
->name
); oti
->name
= NULL
;
89 g_free(oti
->description
); oti
->description
= NULL
;
90 g_free(oti
->tags
); oti
->tags
= NULL
;
91 g_free(oti
->track_name
); oti
->track_name
= NULL
;
93 g_object_unref(oti
->vtl
); oti
->vtl
= NULL
;
95 /* Main struct has been g_malloc'ed */
99 static const gchar
*get_default_user()
101 const gchar
*default_user
= NULL
;
103 /* Retrieve "standard" EMAIL varenv */
104 default_user
= g_getenv("EMAIL");
109 static void set_login(const gchar
*user_
, const gchar
*password_
)
112 if (login_mutex
== NULL
)
114 login_mutex
= g_mutex_new();
116 g_mutex_lock(login_mutex
);
117 g_free(user
); user
= NULL
;
118 g_free(password
); password
= NULL
;
119 user
= g_strdup(user_
);
120 password
= g_strdup(password_
);
121 g_mutex_unlock(login_mutex
);
124 static gchar
*get_login()
126 gchar
*user_pass
= NULL
;
127 g_mutex_lock(login_mutex
);
128 user_pass
= g_strdup_printf("%s:%s", user
, password
);
129 g_mutex_unlock(login_mutex
);
134 void osm_traces_init () {
136 a_preferences_register_group ( VIKING_OSM_TRACES_PARAMS_GROUP_KEY
, "OpenStreetMap traces" );
138 VikLayerParamData tmp
;
140 a_preferences_register(prefs
, tmp
, VIKING_OSM_TRACES_PARAMS_GROUP_KEY
);
142 a_preferences_register(prefs
+1, tmp
, VIKING_OSM_TRACES_PARAMS_GROUP_KEY
);
149 void osm_traces_upload_file(const char *user
,
150 const char *password
,
152 const char *filename
,
153 const char *description
,
159 char curl_error_buffer
[CURL_ERROR_SIZE
];
160 struct curl_slist
*headers
= NULL
;
161 struct curl_httppost
*post
=NULL
;
162 struct curl_httppost
*last
=NULL
;
163 gchar
*public_string
;
165 char *base_url
= "http://www.openstreetmap.org/api/0.5/gpx/create";
167 gchar
*user_pass
= get_login();
169 g_debug("%s: %s %s %s %s %s %s", __FUNCTION__
,
170 user
, password
, file
, filename
, description
, tags
);
173 curl
= curl_easy_init();
175 /* Filling the form */
176 curl_formadd(&post
, &last
,
177 CURLFORM_COPYNAME
, "description",
178 CURLFORM_COPYCONTENTS
, description
, CURLFORM_END
);
179 curl_formadd(&post
, &last
,
180 CURLFORM_COPYNAME
, "tags",
181 CURLFORM_COPYCONTENTS
, tags
, CURLFORM_END
);
186 curl_formadd(&post
, &last
,
187 CURLFORM_COPYNAME
, "public",
188 CURLFORM_COPYCONTENTS
, public_string
, CURLFORM_END
);
189 curl_formadd(&post
, &last
,
190 CURLFORM_COPYNAME
, "file",
192 CURLFORM_FILENAME
, filename
,
193 CURLFORM_CONTENTTYPE
, "text/xml", CURLFORM_END
);
195 /* Prepare request */
196 /* As explained in http://wiki.openstreetmap.org/index.php/User:LA2 */
197 /* Expect: header seems to produce incompatibilites between curl and httpd */
198 headers
= curl_slist_append(headers
, "Expect: ");
199 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, headers
);
200 curl_easy_setopt(curl
, CURLOPT_HTTPPOST
, post
);
201 curl_easy_setopt(curl
, CURLOPT_URL
, base_url
);
202 curl_easy_setopt(curl
, CURLOPT_USERPWD
, user_pass
);
203 curl_easy_setopt(curl
, CURLOPT_HTTPAUTH
, CURLAUTH_ANY
);
204 curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, curl_error_buffer
);
206 curl_easy_setopt ( curl
, CURLOPT_VERBOSE
, 1 );
208 /* Execute request */
209 res
= curl_easy_perform(curl
);
213 res
= curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &code
);
216 g_debug("received valid curl response: %ld", code
);
218 g_warning(_("failed to upload data: HTTP response is %ld"), code
);
221 g_error(_("curl_easy_getinfo failed: %d"), res
);
225 g_warning(_("curl request failed: %s"), curl_error_buffer
);
229 g_free(user_pass
); user_pass
= NULL
;
232 curl_easy_cleanup(curl
);
236 * uploading function executed by the background" thread
238 static void osm_traces_upload_thread ( OsmTracesInfo
*oti
, gpointer threaddata
)
240 /* Due to OSM limits, we have to enforce ele and time fields */
241 static GpxWritingOptions options
= { TRUE
, TRUE
};
243 gchar
*filename
= NULL
;
245 GError
*error
= NULL
;
248 g_assert(oti
!= NULL
);
250 /* Opening temporary file */
251 fd
= g_file_open_tmp("viking_osm_upload_XXXXXX.gpx", &filename
, &error
);
253 g_error(_("failed to open temporary file: %s"), strerror(errno
));
256 g_clear_error(&error
);
257 g_debug("%s: temporary file = %s", __FUNCTION__
, filename
);
260 file
= fdopen(fd
, "w");
262 /* writing gpx file */
263 if (oti
->track_name
!= NULL
)
265 /* Upload only the selected track */
266 VikTrack
*track
= vik_trw_layer_get_track(oti
->vtl
, oti
->track_name
);
267 a_gpx_write_track_file_options(&options
, oti
->track_name
, track
, file
);
271 /* Upload the whole VikTrwLayer */
272 a_gpx_write_file_options(&options
, oti
->vtl
, file
);
275 /* We can close the file */
276 /* This also close the associated fd */
280 /* finally, upload it */
281 osm_traces_upload_file(user
, password
, filename
,
282 oti
->name
, oti
->description
, oti
->tags
, oti
->public);
284 /* Removing temporary file */
285 ret
= g_unlink(filename
);
287 g_error(_("failed to unlink temporary file: %s"), strerror(errno
));
292 * Uploading a VikTrwLayer
294 * @param vtl VikTrwLayer
295 * @param track_name if not null, the name of the track to upload
297 static void osm_traces_upload_viktrwlayer ( VikTrwLayer
*vtl
, const gchar
*track_name
)
299 GtkWidget
*dia
= gtk_dialog_new_with_buttons (_("OSM upload"),
300 VIK_GTK_WINDOW_FROM_LAYER(vtl
),
301 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
308 const gchar
*default_user
= get_default_user();
309 const gchar
*pref_user
= a_preferences_get(VIKING_OSM_TRACES_PARAMS_NAMESPACE
"username")->s
;
310 const gchar
*pref_password
= a_preferences_get(VIKING_OSM_TRACES_PARAMS_NAMESPACE
"password")->s
;
311 const gchar
*name
= NULL
;
312 GtkWidget
*user_label
, *user_entry
;
313 GtkWidget
*password_label
, *password_entry
;
314 GtkWidget
*name_label
, *name_entry
;
315 GtkWidget
*description_label
, *description_entry
;
316 GtkWidget
*tags_label
, *tags_entry
;
318 GtkTooltips
* dialog_tips
;
320 dialog_tips
= gtk_tooltips_new();
322 user_label
= gtk_label_new(_("Email:"));
323 user_entry
= gtk_entry_new();
324 if (user
!= NULL
&& user
[0] != '\0')
325 gtk_entry_set_text(GTK_ENTRY(user_entry
), user
);
326 else if (pref_user
!= NULL
&& pref_user
[0] != '\0')
327 gtk_entry_set_text(GTK_ENTRY(user_entry
), pref_user
);
328 else if (default_user
!= NULL
)
329 gtk_entry_set_text(GTK_ENTRY(user_entry
), default_user
);
330 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), user_label
, FALSE
, FALSE
, 0);
331 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), user_entry
, FALSE
, FALSE
, 0);
332 gtk_widget_show_all ( user_label
);
333 gtk_widget_show_all ( user_entry
);
334 gtk_tooltips_set_tip (dialog_tips
, user_entry
,
335 _("The email used as login"),
336 _("Enter the email you use to login into www.openstreetmap.org."));
338 password_label
= gtk_label_new(_("Password:"));
339 password_entry
= gtk_entry_new();
340 if (password
!= NULL
&& password
[0] != '\0')
341 gtk_entry_set_text(GTK_ENTRY(password_entry
), password
);
342 else if (pref_password
!= NULL
)
343 gtk_entry_set_text(GTK_ENTRY(password_entry
), pref_password
);
344 /* This is a password -> invisible */
345 gtk_entry_set_visibility(GTK_ENTRY(password_entry
), FALSE
);
346 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), password_label
, FALSE
, FALSE
, 0);
347 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), password_entry
, FALSE
, FALSE
, 0);
348 gtk_widget_show_all ( password_label
);
349 gtk_widget_show_all ( password_entry
);
350 gtk_tooltips_set_tip (dialog_tips
, password_entry
,
351 _("The password used to login"),
352 _("Enter the password you use to login into www.openstreetmap.org."));
354 name_label
= gtk_label_new(_("File's name:"));
355 name_entry
= gtk_entry_new();
356 if (track_name
!= NULL
)
359 name
= vik_layer_get_name(VIK_LAYER(vtl
));
360 gtk_entry_set_text(GTK_ENTRY(name_entry
), name
);
361 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), name_label
, FALSE
, FALSE
, 0);
362 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), name_entry
, FALSE
, FALSE
, 0);
363 gtk_widget_show_all ( name_label
);
364 gtk_widget_show_all ( name_entry
);
365 gtk_tooltips_set_tip (dialog_tips
, name_entry
,
366 _("The name of the file on OSM"),
367 _("This is the name of the file created on the server. "
368 "This is not the name of the local file."));
370 description_label
= gtk_label_new(_("Description:"));
371 description_entry
= gtk_entry_new();
372 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), description_label
, FALSE
, FALSE
, 0);
373 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), description_entry
, FALSE
, FALSE
, 0);
374 gtk_widget_show_all ( description_label
);
375 gtk_widget_show_all ( description_entry
);
376 gtk_tooltips_set_tip (dialog_tips
, description_entry
,
377 _("The description of the trace"),
380 tags_label
= gtk_label_new(_("Tags:"));
381 tags_entry
= gtk_entry_new();
382 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), tags_label
, FALSE
, FALSE
, 0);
383 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), tags_entry
, FALSE
, FALSE
, 0);
384 gtk_widget_show_all ( tags_label
);
385 gtk_widget_show_all ( tags_entry
);
386 gtk_tooltips_set_tip (dialog_tips
, tags_entry
,
387 _("The tags associated to the trace"),
390 public = gtk_check_button_new_with_label(_("Public"));
391 /* Set public by default */
392 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(public), TRUE
);
393 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), public, FALSE
, FALSE
, 0);
394 gtk_widget_show_all ( public );
395 gtk_tooltips_set_tip (dialog_tips
, public,
396 _("Indicates if the trace is public or not"),
399 if ( gtk_dialog_run ( GTK_DIALOG(dia
) ) == GTK_RESPONSE_ACCEPT
)
403 /* overwrite authentication info */
404 set_login(gtk_entry_get_text(GTK_ENTRY(user_entry
)),
405 gtk_entry_get_text(GTK_ENTRY(password_entry
)));
407 /* Storing data for the future thread */
408 OsmTracesInfo
*info
= g_malloc(sizeof(OsmTracesInfo
));
409 info
->name
= g_strdup(gtk_entry_get_text(GTK_ENTRY(name_entry
)));
410 info
->description
= g_strdup(gtk_entry_get_text(GTK_ENTRY(description_entry
)));
411 /* TODO Normalize tags: they will be used as URL part */
412 info
->tags
= g_strdup(gtk_entry_get_text(GTK_ENTRY(tags_entry
)));
413 info
->public = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(public));
414 info
->vtl
= VIK_TRW_LAYER(g_object_ref(vtl
));
415 info
->track_name
= (track_name
== NULL
) ? NULL
: g_strdup(track_name
);
417 title
= g_strdup_printf(_("Uploading %s to OSM"), info
->name
);
419 /* launch the thread */
420 a_background_thread(VIK_GTK_WINDOW_FROM_LAYER(vtl
), /* parent window */
421 title
, /* description string */
422 (vik_thr_func
) osm_traces_upload_thread
, /* function to call within thread */
423 info
, /* pass along data */
424 (vik_thr_free_func
) oti_free
, /* function to free pass along data */
425 (vik_thr_free_func
) NULL
,
427 g_free ( title
); title
= NULL
;
429 gtk_widget_destroy ( dia
);
433 * Function called by the entry menu of a TrwLayer
435 void osm_traces_upload_cb ( gpointer layer_and_vlp
[2], guint file_type
)
437 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(layer_and_vlp
[0]), NULL
);
441 * Function called by the entry menu of a single track
443 void osm_traces_upload_track_cb ( gpointer pass_along
[6] )
445 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along
[0]), pass_along
[3]);