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
24 #include <sys/types.h>
29 #include <curl/curl.h>
30 #include <curl/types.h>
31 #include <curl/easy.h>
34 #include <glib/gstdio.h>
37 #include "viktrwlayer.h"
38 #include "osm-traces.h"
40 #include "background.h"
43 * Login to use for OSM uploading.
45 static gchar
*user
= NULL
;
48 * Password to use for OSM uploading.
50 static gchar
*password
= NULL
;
53 * Mutex to protect auth. token
55 static GMutex
*login_mutex
= NULL
;
58 * Struct hosting needed info.
60 typedef struct _OsmTracesInfo
{
70 * Free an OsmTracesInfo struct.
72 static void oti_free(OsmTracesInfo
*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
;
79 g_free(oti
->track_name
); oti
->track_name
= NULL
;
81 g_object_unref(oti
->vtl
); oti
->vtl
= NULL
;
83 /* Main struct has been g_malloc'ed */
87 static const gchar
*get_default_user()
89 const gchar
*default_user
= NULL
;
91 /* Retrieve "standard" EMAIL varenv */
92 default_user
= g_getenv("EMAIL");
97 static void set_login(const gchar
*user_
, const gchar
*password_
)
100 if (login_mutex
== NULL
)
102 login_mutex
= g_mutex_new();
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
);
112 static gchar
*get_login()
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
);
124 void osm_traces_upload_file(const char *user
,
125 const char *password
,
127 const char *filename
,
128 const char *description
,
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
;
140 char *base_url
= "http://www.openstreetmap.org/api/0.4/gpx/create";
142 gchar
*user_pass
= get_login();
144 g_debug("%s: %s %s %s %s %s %s", __FUNCTION__
,
145 user
, password
, file
, filename
, description
, tags
);
148 curl
= curl_easy_init();
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
);
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",
167 CURLFORM_FILENAME
, filename
,
168 CURLFORM_CONTENTTYPE
, "text/xml", CURLFORM_END
);
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
);
181 /* Execute request */
182 res
= curl_easy_perform(curl
);
186 res
= curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &code
);
189 g_debug("received valid curl response: %ld", code
);
191 g_warning("failed to upload data: HTTP response is %ld", code
);
194 g_error("curl_easy_getinfo failed: %d", res
);
198 g_warning("curl request failed: %s", curl_error_buffer
);
202 g_free(user_pass
); user_pass
= NULL
;
205 curl_easy_cleanup(curl
);
209 * uploading function executed by the background" thread
211 static void osm_traces_upload_thread ( OsmTracesInfo
*oti
, gpointer threaddata
)
214 gchar
*filename
= NULL
;
216 GError
*error
= NULL
;
219 g_assert(oti
!= NULL
);
221 /* Opening temporary file */
222 fd
= g_file_open_tmp("viking_osm_upload_XXXXXX.gpx", &filename
, &error
);
224 g_error("failed to open temporary file: %s", strerror(errno
));
227 g_clear_error(&error
);
228 g_debug("%s: temporary file = %s", __FUNCTION__
, filename
);
231 file
= fdopen(fd
, "w");
233 /* writing gpx file */
234 if (oti
->track_name
!= NULL
)
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
);
241 /* Upload the whole VikTrwLayer */
242 a_gpx_write_file(oti
->vtl
, file
);
244 /* We can close the file */
245 /* This also close the associated fd */
248 /* finally, upload it */
249 osm_traces_upload_file(user
, password
, filename
,
250 oti
->name
, oti
->description
, oti
->tags
, oti
->public);
252 /* Removing temporary file */
253 ret
= g_unlink(filename
);
255 g_error("failed to unlink temporary file: %s", strerror(errno
));
260 * Uploading a VikTrwLayer
262 * @param vtl VikTrwLayer
263 * @param track_name if not null, the name of the track to upload
265 static void osm_traces_upload_viktrwlayer ( VikTrwLayer
*vtl
, const gchar
*track_name
)
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
,
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
;
283 GtkTooltips
* dialog_tips
;
285 dialog_tips
= gtk_tooltips_new();
287 user_label
= gtk_label_new("Email:");
288 user_entry
= gtk_entry_new();
290 gtk_entry_set_text(GTK_ENTRY(user_entry
), user
);
293 const gchar
*default_user
= get_default_user();
294 if (default_user
!= NULL
)
295 gtk_entry_set_text(GTK_ENTRY(user_entry
), default_user
);
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.");
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.");
319 name_label
= gtk_label_new("File's name:");
320 name_entry
= gtk_entry_new();
321 if (track_name
!= NULL
)
324 name
= vik_layer_get_name(VIK_LAYER(vtl
));
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.");
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",
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",
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",
364 if ( gtk_dialog_run ( GTK_DIALOG(dia
) ) == GTK_RESPONSE_ACCEPT
)
368 /* overwrite authentication info */
369 set_login(gtk_entry_get_text(GTK_ENTRY(user_entry
)),
370 gtk_entry_get_text(GTK_ENTRY(password_entry
)));
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
));
380 info
->track_name
= (track_name
== NULL
) ? NULL
: g_strdup(track_name
);
382 title
= g_strdup_printf("Uploading %s to OSM", info
->name
);
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
,
392 g_free ( title
); title
= NULL
;
394 gtk_widget_destroy ( dia
);
398 * Function called by the entry menu of a TrwLayer
400 void osm_traces_upload_cb ( gpointer layer_and_vlp
[2], guint file_type
)
402 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(layer_and_vlp
[0]), NULL
);
406 * Function called by the entry menu of a single track
408 void osm_traces_upload_track_cb ( gpointer pass_along
[6] )
410 osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along
[0]), pass_along
[3]);