2 * This file is part of sharing-plugin-gallery2
4 * Copyright (C) 2009 Heikki Kallasjoki. All rights reserved.
5 * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
7 * This code is licensed under a MIT-style license, that can be
8 * found in the file called "COPYING" in the root directory.
16 #include <sharing-http.h>
21 * @con: Connection to use
22 * @urlbase: Base URL to the Gallery 2 site
23 * @username: User name
25 * @cookies: Output parameter for any cookies set.
26 * @auth: Output paremeter for the authentication token.
28 * Logs in to the Gallery 2 service.
30 * Returns: Validation result.
32 SharingPluginInterfaceAccountValidateResult
33 gallery2_login (ConIcConnection* con,
34 const gchar* urlbase, const gchar* username, const gchar* password,
35 GHashTable** cookies, gchar** auth)
37 SharingPluginInterfaceAccountValidateResult ret = SHARING_ACCOUNT_VALIDATE_SUCCESS;
39 SharingHTTP* http = sharing_http_new ();
44 /* Do the login request */
46 gchar* url = g_strdup_printf("%s/main.php?g2_controller=remote:GalleryRemote&"
47 "g2_form[cmd]=login&g2_form[protocol_version]=2.0&"
48 "g2_form[uname]=%s&g2_form[password]=%s",
49 urlbase, username, password);
51 sharing_http_set_connection (http, con);
52 SharingHTTPRunResponse res = sharing_http_run (http, url);
57 /* Parse the response */
59 if (res == SHARING_HTTP_RUNRES_SUCCESS && sharing_http_get_res_code (http) == 200)
61 /* Split response into lines */
66 gsize content_len = 0;
67 const gchar* content = sharing_http_get_res_content (http, &content_len);
68 gchar* c = g_strndup (content, content_len); /* force \0 termination */
69 lines = g_strsplit_set (c, "\r\n", 0);
73 /* Process the lines */
75 *cookies = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
77 gboolean in_body = FALSE;
79 for (gchar** p = lines; *p; p++)
85 if (g_ascii_strncasecmp (line, "Set-Cookie:", 11) == 0)
87 /* Extract the key=value part of the cookie */
92 gchar* c = g_strchug (line+11); /* start of cookie data */
94 char* end = strchr (c, ';');
97 data = g_strsplit (c, "=", 2);
100 if (!data[0] || !data[1])
102 /* Bad Set-Cookie: header, ignore */
107 /* Insert into our table */
109 g_hash_table_replace (*cookies, data[0], data[1]);
110 g_free (data); /* not g_strfreev! strings still used in "cookies" */
115 if (g_str_has_prefix (line, "#__GR2PROTO__"))
123 /* Split key=value into fields */
125 gchar* value = strchr (line, '=');
126 if (!value) continue;
130 /* Process the necessary parts */
132 if (strcmp (line, "status") == 0 && strcmp (value, "0") != 0)
134 ULOG_ERR_L ("Gallery 2 login auth failed\n");
135 ret = SHARING_ACCOUNT_VALIDATE_FAILED;
139 if (strcmp (line, "auth_token") == 0)
141 *auth = g_strdup (value);
151 ULOG_ERR_L ("Gallery 2 login connection failed\n");
152 ret = SHARING_ACCOUNT_VALIDATE_ERROR_CONNECTION;
155 if (ret != SHARING_ACCOUNT_VALIDATE_SUCCESS)
157 if (*cookies) g_hash_table_unref (*cookies);
158 if (*auth) g_free (auth);
163 sharing_http_unref (http);
168 * gallery2_lookup_album:
169 * @con: Connection to use
170 * @urlbase: Base URL to the Gallery 2 site
171 * @albumpath: Slash-separated path to album
172 * @album: Output parameter to hold the album ID
173 * @cookies: Cookies from gallery2_login.
174 * @auth: Authentication token from gallery2_login.
176 * Retrieves the album id based on an album path.
178 SharingPluginInterfaceAccountValidateResult
179 gallery2_lookup_album (ConIcConnection* con,
180 const gchar* urlbase, const gchar* albumpath, gchar** album,
181 GHashTable* cookies, gchar* auth)
183 SharingPluginInterfaceAccountValidateResult ret = SHARING_ACCOUNT_VALIDATE_ERROR_UNKNOWN;
185 SharingHTTP* http = sharing_http_new ();
187 /* Prepare and send the request */
189 gchar* url = g_strdup_printf("%s/main.php?g2_controller=remote:GalleryRemote%s%s&"
190 "g2_form[cmd]=fetch-albums-prune&g2_form[protocol_version]=2.2&g2_form[no_perms]=yes",
192 auth ? "&g2_authToken=" : "", auth ? auth : "");
198 g_hash_table_iter_init (&iter, cookies);
199 while (g_hash_table_iter_next (&iter, &key, &value))
201 gchar* hdr = g_strdup_printf("Cookie: %s=%s", (gchar*)key, (gchar*)value);
202 sharing_http_add_req_header_line (http, hdr);
207 sharing_http_set_connection (http, con);
208 SharingHTTPRunResponse res = sharing_http_run (http, url);
213 /* Parse the response into an album map. */
215 GHashTable* album_names = 0; /* map string (display-name) -> GSList [ string (url-name) ] */
216 GHashTable* album_parent = 0; /* map string (url-name) -> string (url-name) */
217 gchar* album_root = 0; /* root album url-name */
218 gboolean valid = FALSE; /* true if the maps are usable */
219 char** lines = 0; /* raw data (response lines) */
221 if (res == SHARING_HTTP_RUNRES_SUCCESS && sharing_http_get_res_code (http) == 200)
224 gsize content_len = 0;
225 const gchar* content = sharing_http_get_res_body (http, &content_len);
226 gchar* c = g_strndup (content, content_len); /* force \0 termination */
227 lines = g_strsplit_set (c, "\r\n", 0);
231 gboolean in_body = FALSE;
232 gchar* current_ref_num = 0;
233 gchar* current_url_name = 0;
235 for (gchar** p = lines; *p; p++)
241 if (g_str_has_prefix (line, "#__GR2PROTO__"))
243 album_names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_slist_free);
244 album_parent = g_hash_table_new (g_str_hash, g_str_equal);
250 gchar* value = strchr (line, '=');
251 if (!value) continue;
255 if (strcmp (line, "status") == 0)
257 if (strcmp (value, "0") == 0)
261 else if (g_str_has_prefix (line, "album.name."))
263 current_ref_num = line + 11;
264 current_url_name = value;
266 else if (g_str_has_prefix (line, "album.title."))
268 if (!current_ref_num || strcmp (current_ref_num, line + 12) != 0)
270 GSList* others = g_hash_table_lookup (album_names, value);
271 if (others) g_hash_table_steal (album_names, value);
272 g_hash_table_insert (album_names, value, g_slist_prepend (others, current_url_name));
274 else if (g_str_has_prefix (line, "album.parent."))
276 if (!current_ref_num || strcmp (current_ref_num, line + 13) != 0)
278 g_hash_table_insert (album_parent, current_url_name, value);
279 if (strcmp (value, "0") == 0)
280 album_root = current_url_name;
285 ret = SHARING_ACCOUNT_VALIDATE_ERROR_CONNECTION;
287 sharing_http_unref (http);
289 /* Find the album we are interested in. */
293 if (album_names && album_parent && album_root && valid)
295 gchar* current_album = album_root;
296 gboolean seen_parents = FALSE; /* for the root special case */
297 gboolean found_final = FALSE; /* to make sure the last real component is found */
299 gchar** components = g_strsplit (albumpath, "/", 0);
301 for (gchar** p = components; *p; p++)
303 if (!**p) continue; /* ignore empty path components */
304 found_final = FALSE; /* this component needs to be found */
305 GSList* candidates = g_hash_table_lookup (album_names, *p);
306 /* bad case: no candidates at all */
307 if (!candidates) break;
308 /* special case 1: if only one candidate and no unseen parents, choose that */
309 if (!seen_parents && !g_slist_next (candidates))
312 current_album = candidates->data;
315 /* general case: find a candidate with an acceptable parent */
318 gchar* parent = g_hash_table_lookup (album_parent, candidates->data);
319 /* suitable parents: current_album, or (if no specified parents) null or 0 (explicit root case) */
320 if ((parent && strcmp (parent, current_album) == 0)
321 || (!seen_parents && (!parent || strcmp (parent, "0") == 0)))
324 current_album = candidates->data;
327 candidates = g_slist_next (candidates); /* try next */
331 g_strfreev (components);
335 *album = g_strdup(current_album);
336 ret = SHARING_ACCOUNT_VALIDATE_SUCCESS;
340 if (album_names) g_hash_table_unref (album_names);
341 if (album_parent) g_hash_table_unref (album_parent);
347 /* gallery2_send callback helper declarations */
349 struct gallery2_send_record
351 SharingTransfer* transfer;
352 gdouble progress_start;
353 gdouble progress_end;
358 gboolean gallery2_send_callback (SharingHTTP* http, guint64 bytes_sent, gpointer user_data);
362 * @con: Connection to use
363 * @transfer: Sharing transfer object
364 * @progress_start: Initial state of progress meter
365 * @progress_end: Desired final state of progress meter
366 * @dms: Dead man's switch
367 * @media: Media item to send
368 * @urlbase: Base URL to the Gallery 2 site
369 * @album: Album ID from gallery2_lookup_album.
370 * @cookies: Cookies from gallery2_login.
371 * @auth: Authentication token from gallery2_login.
373 * Sends a media item to a Gallery 2 service.
375 * Returns: Send result.
377 SharingPluginInterfaceSendResult
378 gallery2_send (ConIcConnection* con,
379 SharingTransfer* transfer, gdouble progress_start, gdouble progress_end, gboolean *dms,
380 SharingEntryMedia* media,
381 const gchar* urlbase, const gchar* album, GHashTable* cookies, gchar* auth)
383 struct gallery2_send_record rec = {
384 .transfer = transfer,
385 .progress_start = progress_start,
386 .progress_end = progress_end,
391 SharingPluginInterfaceSendResult ret = SHARING_SEND_SUCCESS;
393 SharingHTTP* http = sharing_http_new ();
395 /* Prepare and send the request */
397 /* gchar* album = "1652"; */ /* TODO: get from UI/login */
399 gchar* media_title = sharing_entry_media_get_title (media);
400 gchar* media_mime = sharing_entry_media_get_mime (media);
401 gchar* media_filename = sharing_entry_media_get_filename (media);
403 const gchar* desc = sharing_entry_media_get_desc (media);
405 gchar* url = g_strdup_printf("%s/main.php?g2_controller=remote:GalleryRemote%s%s&"
406 "g2_form[cmd]=add-item&g2_form[protocol_version]=2.0&"
407 "g2_form[set_albumName]=%s&g2_form[caption]=%s"
410 auth ? "&g2_authToken=" : "", auth ? auth : "",
412 desc ? "&g2_form[extrafield.Summary]=" : "", desc ? desc : "",
413 desc ? "&g2_form[extrafield.Description]=" : "", desc ? desc : "");
419 g_hash_table_iter_init (&iter, cookies);
420 while (g_hash_table_iter_next (&iter, &key, &value))
422 gchar* hdr = g_strdup_printf("Cookie: %s=%s", (gchar*)key, (gchar*)value);
423 sharing_http_add_req_header_line (http, hdr);
428 sharing_http_add_req_multipart_file_with_filename (http,
430 sharing_entry_media_get_localpath (media),
431 media_mime ? media_mime : "image/jpeg",
432 media_filename ? media_filename : "unknown.jpg");
434 g_free (media_title);
436 g_free (media_filename);
438 media_title = media_mime = media_filename = 0;
440 rec.media_bytes = sharing_entry_media_get_size (media);
441 sharing_http_set_progress_callback (http, gallery2_send_callback, &rec);
444 sharing_http_set_connection (http, con);
445 SharingHTTPRunResponse res = sharing_http_run (http, url);
451 /* Parse the response */
453 if (res == SHARING_HTTP_RUNRES_SUCCESS && sharing_http_get_res_code (http) == 200)
458 gsize content_len = 0;
459 const gchar* content = sharing_http_get_res_body (http, &content_len);
460 gchar* c = g_strndup (content, content_len); /* force \0 termination */
461 lines = g_strsplit_set (c, "\r\n", 0);
465 gboolean in_body = FALSE;
466 ret = SHARING_SEND_ERROR_UNKNOWN;
468 for (gchar** p = lines; *p; p++)
474 if (g_str_has_prefix (line, "#__GR2PROTO__"))
479 gchar* value = strchr (line, '=');
480 if (!value) continue;
484 if (strcmp (line, "status") == 0)
486 if (strcmp (value, "0") == 0)
487 ret = SHARING_SEND_SUCCESS;
494 else if (res == SHARING_HTTP_RUNRES_CANCELLED)
495 ret = SHARING_SEND_CANCELLED;
497 ret = SHARING_SEND_ERROR_CONNECTION;
499 sharing_http_unref (http);
502 sharing_transfer_set_progress (transfer, progress_end);
507 /* gallery2_send callback implementation */
509 gboolean gallery2_send_callback (SharingHTTP* http, guint64 bytes_sent, gpointer user_data)
511 struct gallery2_send_record* rec = user_data;
513 if (!sharing_transfer_continue (rec->transfer))
518 gdouble progress = (rec->progress_start + rec->progress_end) / 2.0;
520 if (rec->media_bytes)
522 if (bytes_sent >= rec->media_bytes)
523 progress = rec->progress_end;
525 progress = rec->progress_start + (bytes_sent / (gdouble)rec->media_bytes) * (rec->progress_end - rec->progress_start);
528 sharing_transfer_set_progress (rec->transfer, progress);