Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
piwigo.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2018-2022 Pascal Obry.
4 Copyright (C) 2019, 2023, 2025 Aurélien PIERRE.
5 Copyright (C) 2019 Denis Dyakov.
6 Copyright (C) 2019 Heiko Bauke.
7 Copyright (C) 2019 Jacques Le Clerc.
8 Copyright (C) 2019 jakubfi.
9 Copyright (C) 2019, 2021 luzpaz.
10 Copyright (C) 2019 Philippe Weyland.
11 Copyright (C) 2020-2021 Diederik Ter Rahe.
12 Copyright (C) 2020 Marco.
13 Copyright (C) 2020 Tobias Ellinghaus.
14 Copyright (C) 2021 Hubert Kowalski.
15 Copyright (C) 2021 Ralf Brown.
16 Copyright (C) 2022 Martin Bařinka.
17
18 darktable is free software: you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation, either version 3 of the License, or
21 (at your option) any later version.
22
23 darktable is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with darktable. If not, see <http://www.gnu.org/licenses/>.
30*/
31
32#include "bauhaus/bauhaus.h"
33#include "common/darktable.h"
35#include "common/image.h"
36#include "common/image_cache.h"
37#include "common/imageio.h"
39#include "common/metadata.h"
41#include "common/tags.h"
42#include "common/curl_tools.h"
43#include "control/conf.h"
44#include "control/control.h"
45#include "dtgtk/button.h"
46#include "gui/gtk.h"
48#include <curl/curl.h>
49#include <json-glib/json-glib.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <unistd.h>
53#include <inttypes.h>
54
55DT_MODULE(1)
56
57#define piwigo_EXTRA_VERBOSE FALSE
58
59#define MAX_ALBUM_NAME_SIZE 100
60
62{
64 CURL *curl_ctx;
65 JsonParser *json_parser;
66 JsonObject *response;
67 gboolean authenticated;
69 gchar *url;
70
71 gchar *server;
72 gchar *username;
73 gchar *password;
74 gchar *pwg_token;
75 gboolean error_occured;
77
85
86typedef struct _piwigo_account_t
87{
88 gchar *server;
89 gchar *username;
90 gchar *password;
92
109
110typedef struct _curl_args_t
111{
112 char name[100];
113 char value[512];
115
117{
119 int64_t album_id;
121 char *album;
122 gboolean new_album;
124 gboolean export_tags; // deprecated - let here not to change params size. to be removed on next version change
125 gchar *tags;
127
128/* low-level routine doing the HTTP POST request */
129static void _piwigo_api_post(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth);
130
131static size_t curl_write_data_cb(void *ptr, size_t size, size_t nmemb, void *data)
132{
133 GString *string = (GString *)data;
134 g_string_append_len(string, ptr, size * nmemb);
135#if piwigo_EXTRA_VERBOSE == TRUE
136 g_printf("server reply: %s\n", string->str);
137#endif
138 return size * nmemb;
139}
140
141static GList *_piwigo_query_add_arguments(GList *args, const char *name, const char *value)
142{
143 _curl_args_t *arg = malloc(sizeof(_curl_args_t));
144 g_strlcpy(arg->name, name, sizeof(arg->name));
145 g_strlcpy(arg->value, value, sizeof(arg->value));
146 return g_list_append(args, arg);
147}
148
150{
151 _piwigo_api_context_t *ctx = malloc(sizeof(struct _piwigo_api_context_t));
152
153 ctx->curl_ctx = curl_easy_init();
154 ctx->json_parser = json_parser_new();
155 ctx->authenticated = FALSE;
156 ctx->url = NULL;
157 ctx->cookie_file = NULL;
158 ctx->error_occured = FALSE;
159 ctx->pwg_token = NULL;
160 return ctx;
161}
162
164{
165 if(*ctx)
166 {
167 curl_easy_cleanup((*ctx)->curl_ctx);
168 if((*ctx)->cookie_file) g_unlink((*ctx)->cookie_file);
169 g_object_unref((*ctx)->json_parser);
170 dt_free((*ctx)->cookie_file);
171 dt_free((*ctx)->url);
172 dt_free((*ctx)->server);
173 dt_free((*ctx)->username);
174 dt_free((*ctx)->password);
175 dt_free((*ctx)->pwg_token);
176 dt_free(*ctx);
177 }
178}
179
180static void _piwigo_free_account(void *data)
181{
182 _piwigo_account_t *account = (_piwigo_account_t *)data;
183 dt_free(account->server);
184 dt_free(account->username);
185 dt_free(account->password);
186}
187
189{
190 if(IS_NULL_PTR(ui->accounts))
191 {
192 g_list_free_full(ui->accounts, _piwigo_free_account);
193 ui->accounts = NULL;
194 }
195
196 GHashTable *table = dt_pwstorage_get("piwigo");
197 GHashTableIter iter;
198 gpointer key, value;
199
200 g_hash_table_iter_init (&iter, table);
201
202 while (g_hash_table_iter_next (&iter, &key, &value))
203 {
204 if(key && value)
205 {
206 gchar *data = (gchar *)value;
207 JsonParser *parser = json_parser_new();
208 json_parser_load_from_data(parser, data, strlen(data), NULL);
209 JsonNode *root = json_parser_get_root(parser);
210
211 if(root)
212 {
213 JsonObject *obj = json_node_get_object(root);
214 _piwigo_account_t *account = malloc(sizeof(_piwigo_account_t));
215
216 account->server = g_strdup(json_object_get_string_member(obj, "server"));
217 account->username = g_strdup(json_object_get_string_member(obj, "username"));
218 account->password = g_strdup(json_object_get_string_member(obj, "password"));
219
220 if(account->server && strlen(account->server)>0)
221 ui->accounts = g_list_append(ui->accounts, account);
222 else
223 dt_free(account); // we didn't add account to list, freeing it
224 }
225
226 g_object_unref(parser);
227 }
228 }
229
230 g_hash_table_destroy(table);
231}
232
234{
235 if(IS_NULL_PTR(server)) return NULL;
236
237 for(const GList *a = ui->accounts; a; a = g_list_next(a))
238 {
239 _piwigo_account_t *account = (_piwigo_account_t *)a->data;;
240 if(account->server && !strcmp(server, account->server)) return account;
241 }
242
243 return NULL;
244}
245
247{
249 JsonBuilder *builder = json_builder_new();
250 json_builder_begin_object(builder);
251 json_builder_set_member_name(builder, "server");
252 json_builder_add_string_value(builder, gtk_entry_get_text(ui->server_entry));
253 json_builder_set_member_name(builder, "username");
254 json_builder_add_string_value(builder, gtk_entry_get_text(ui->user_entry));
255 json_builder_set_member_name(builder, "password");
256 json_builder_add_string_value(builder, gtk_entry_get_text(ui->pwd_entry));
257
258 json_builder_end_object(builder);
259
260 JsonNode *node = json_builder_get_root(builder);
261 JsonGenerator *generator = json_generator_new();
262 json_generator_set_root(generator, node);
263#if JSON_CHECK_VERSION(0, 14, 0)
264 json_generator_set_pretty(generator, FALSE);
265#endif
266 gchar *data = json_generator_to_data(generator, NULL);
267
268 json_node_free(node);
269 g_object_unref(generator);
270 g_object_unref(builder);
271
272 GHashTable *table = dt_pwstorage_get("piwigo");
273 g_hash_table_insert(table, g_strdup(gtk_entry_get_text(ui->server_entry)), data);
274 dt_pwstorage_set("piwigo", table);
275 g_hash_table_destroy(table);
276}
277
279static void _piwigo_set_status(dt_storage_piwigo_gui_data_t *ui, gchar *message, gchar *color)
280{
281 if(IS_NULL_PTR(color)) color = "#ffffff";
282 gchar mup[512] = { 0 };
283 snprintf(mup, sizeof(mup), "<span foreground=\"%s\" ><small>%s</small></span>", color, message);
284 gtk_label_set_markup(ui->status_label, mup);
285 gtk_widget_set_tooltip_markup(GTK_WIDGET(ui->status_label), mup);
286}
287
288static int _piwigo_api_post_internal(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
289{
290 curl_mime *form = NULL;
291
292 GString *url = g_string_new(ctx->url);
293
294 // send the requests
295 GString *response = g_string_new("");
296
298
299 curl_easy_setopt(ctx->curl_ctx, CURLOPT_URL, url->str);
300 curl_easy_setopt(ctx->curl_ctx, CURLOPT_POST, 1);
301 curl_easy_setopt(ctx->curl_ctx, CURLOPT_WRITEFUNCTION, curl_write_data_cb);
302 curl_easy_setopt(ctx->curl_ctx, CURLOPT_WRITEDATA, response);
303
304 if(isauth)
305 {
306 /* construct a temporary file name */
307 char cookie_fmt[PATH_MAX] = { 0 };
308 dt_loc_get_tmp_dir(cookie_fmt, sizeof(cookie_fmt));
309 g_strlcat(cookie_fmt, "/cookies.%.4lf.txt", sizeof(cookie_fmt));
310
311 ctx->cookie_file = g_strdup_printf(cookie_fmt, dt_get_wtime());
312
313 // not that this is safe as the cookie file is written only when the curl context is finalized.
314 // At this stage we unlink the file.
315 curl_easy_setopt(ctx->curl_ctx, CURLOPT_COOKIEJAR, ctx->cookie_file);
316 }
317 else
318 {
319 curl_easy_setopt(ctx->curl_ctx, CURLOPT_COOKIEFILE, ctx->cookie_file);
320 }
321
322 if(filename)
323 {
324 curl_mimepart *field = NULL;
325
326 form = curl_mime_init(ctx->curl_ctx);
327
328 for(const GList *a = args; a; a = g_list_next(a))
329 {
330 _curl_args_t *ca = (_curl_args_t *)a->data;
331 field = curl_mime_addpart(form);
332 curl_mime_name(field, ca->name);
333 curl_mime_data(field, ca->value, CURL_ZERO_TERMINATED);
334 }
335
336 field = curl_mime_addpart(form);
337 curl_mime_name(field, "image");
338 curl_mime_filedata(field, filename);
339
340 curl_easy_setopt(ctx->curl_ctx, CURLOPT_MIMEPOST, form);
341 }
342 else
343 {
344 GString *gargs = g_string_new("");
345
346 for(const GList *a = args; a; a = g_list_next(a))
347 {
348 _curl_args_t *ca = (_curl_args_t *)a->data;
349 if(a!=args) g_string_append(gargs, "&");
350 g_string_append(gargs, ca->name);
351 g_string_append(gargs, "=");
352 g_string_append(gargs, ca->value);
353 }
354
355 curl_easy_setopt(ctx->curl_ctx, CURLOPT_COPYPOSTFIELDS, gargs->str);
356 g_string_free(gargs, TRUE);
357 }
358
359 const int res = curl_easy_perform(ctx->curl_ctx);
360
361#if piwigo_EXTRA_VERBOSE == TRUE
362 g_printf("curl_easy_perform status %d\n", res);
363#endif
364
365 if(filename) curl_mime_free(form);
366
367 g_string_free(url, TRUE);
368
369 ctx->response = NULL;
370
371 if(res == CURLE_OK)
372 {
373 GError *error = NULL;
374 gboolean ret = json_parser_load_from_data(ctx->json_parser, response->str, response->len, &error);
375 if(!ret) goto cleanup;
376 JsonNode *root = json_parser_get_root(ctx->json_parser);
377 // we should always have a dict
378 if(json_node_get_node_type(root) != JSON_NODE_OBJECT) goto cleanup;
379 ctx->response = json_node_get_object(root);
380 const char *status = json_object_get_string_member(ctx->response, "stat");
381 ctx->error_occured = (status && (strcmp(status,"fail")==0));
382 }
383 else
384 ctx->error_occured = TRUE;
385
386 cleanup:
387 g_string_free(response, TRUE);
388 return res;
389}
390
392{
393 GList *args = NULL;
394
395 args = _piwigo_query_add_arguments(args, "method", "pwg.session.login");
396 args = _piwigo_query_add_arguments(args, "username", ctx->username);
397 args = _piwigo_query_add_arguments(args, "password", ctx->password);
398 if(!strcmp(ctx->server, "piwigo.com"))
399 ctx->url = g_strdup_printf("https://%s.piwigo.com/ws.php?format=json", ctx->username);
400 else if(strstr(ctx->server, "http") == ctx->server)
401 ctx->url = g_strdup_printf("%s/ws.php?format=json", ctx->server);
402 else
403 ctx->url = g_strdup_printf("https://%s/ws.php?format=json", ctx->server);
404
405 _piwigo_api_post(ctx, args, NULL, TRUE);
406
407 g_list_free(args);
408 args = NULL;
409
410 // getStatus to retrieve the pwd_token
411
412 args = NULL;
413
414 args = _piwigo_query_add_arguments(args, "method", "pwg.session.getStatus");
415
416 _piwigo_api_post(ctx, args, NULL, TRUE);
417
418 if(ctx->response && !ctx->error_occured)
419 {
420 JsonObject *result = json_node_get_object(json_object_get_member(ctx->response, "result"));
421 const gchar *pwg_token = json_object_get_string_member(result, "pwg_token");
422 ctx->pwg_token = g_strdup(pwg_token);
423 }
424
425 g_list_free(args);
426 args = NULL;
427}
428
429static void _piwigo_api_post(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
430{
431 int res = _piwigo_api_post_internal(ctx, args, filename, isauth);
432
433 if(res == CURLE_COULDNT_CONNECT || res == CURLE_SSL_CONNECT_ERROR)
434 {
435#if piwigo_EXTRA_VERBOSE == TRUE
436 g_printf("curl post error (%d), try authentication again\n", res);
437#endif
438
439 // recreate a new CURL connection
440 curl_easy_cleanup(ctx->curl_ctx);
441 ctx->curl_ctx = curl_easy_init();
442 ctx->authenticated = FALSE;
443
444 if(!isauth)
445 {
446 // an error during the curl post command, could be an authentication issue, try to authenticate again
447 // but only if this is not an authentication post, otherwise this will happen below anyway.
449 }
450
451 // authentication ok, send again
452 if(ctx->response && !ctx->error_occured)
453 {
454 ctx->authenticated = TRUE;
455#if piwigo_EXTRA_VERBOSE == TRUE
456 g_printf("authenticated again, retry\n");
457#endif
458 res = _piwigo_api_post_internal(ctx, args, filename, isauth);
459#if piwigo_EXTRA_VERBOSE == TRUE
460 g_printf("second post exit with status %d\n", res);
461#endif
462 }
463 else
464 {
465#if piwigo_EXTRA_VERBOSE == TRUE
466 g_printf("failed second authentication\n");
467#endif
468 }
469 }
470}
471
473{
474 if(IS_NULL_PTR(ui->api)) ui->api = _piwigo_ctx_init();
475
476 ui->api->server = g_strdup(gtk_entry_get_text(ui->server_entry));
477 ui->api->username = g_uri_escape_string(gtk_entry_get_text(ui->user_entry), NULL, FALSE);
478 ui->api->password = g_uri_escape_string(gtk_entry_get_text(ui->pwd_entry), NULL, FALSE);
479
481
482 ui->api->authenticated = FALSE;
483
484 if(ui->api->response && !ui->api->error_occured)
485 {
486 ui->api->authenticated = TRUE;
487 gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), ui->api->authenticated);
488
489 if(ui->api->authenticated)
490 {
491 _piwigo_set_status(ui, _("authenticated"), "#7fe07f");
492 dt_conf_set_string("plugins/imageio/storage/export/piwigo/server", ui->api->server);
494 }
495 else
496 {
497 const gchar *errormessage = json_object_get_string_member(ui->api->response, "message");
498 fprintf(stderr, "[imageio_storage_piwigo] could not authenticate: `%s'!\n", errormessage);
499 _piwigo_set_status(ui, _("not authenticated"), "#e07f7f");
501 }
502 }
503 else
504 {
505 _piwigo_set_status(ui, _("not authenticated, cannot reach server"), "#e07f7f");
507 }
508}
509
510static void _piwigo_entry_changed(GtkEntry *entry, gpointer data)
511{
513
514 _piwigo_set_status(ui, _("not authenticated"), "#e07f7f");
515 gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), FALSE);
516
517 if(ui->api) _piwigo_ctx_destroy(&ui->api);
518}
519
520static void _piwigo_server_entry_changed(GtkEntry *entry, gpointer data)
521{
523
524 if(ui->api)
525 {
526 _piwigo_set_status(ui, _("not authenticated"), "#e07f7f");
528 gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), FALSE);
529 }
530}
531
532static void _piwigo_account_changed(GtkComboBox *cb, gpointer data)
533{
536 const _piwigo_account_t *account = _piwigo_get_account(ui, value);
537
538 if(account)
539 {
540 gtk_entry_set_text(ui->server_entry, account->server);
541 gtk_entry_set_text(ui->user_entry, account->username);
542 gtk_entry_set_text(ui->pwd_entry, account->password);
543 }
544}
545
546static void _piwigo_album_changed(GtkComboBox *cb, gpointer data)
547{
550
551 // early return if the combo is not yet populated
552 if(IS_NULL_PTR(value)) return;
553
554 if(strcmp(value, _("create new album")) == 0)
555 {
556 gtk_widget_set_no_show_all(GTK_WIDGET(ui->create_box), FALSE);
557 gtk_widget_show_all(GTK_WIDGET(ui->create_box));
558 }
559 else
560 {
561 gtk_widget_hide(GTK_WIDGET(ui->create_box));
562
563 // As the album name has spaces as prefix (for indentation) and a
564 // count of entries in parenthesis as suffix, we need to do some clean-up.
565 gchar *v = g_strstrip(g_strdup(value));
566 gchar *p = v + strlen(v) - 1;
567 if(*p == ')')
568 {
569 while(p != v && *p != '(') p--;
570 if(*p == '(')
571 {
572 p--;
573 if(p >= v) *p = '\0';
574 }
575 }
576 dt_conf_set_string("storage/piwigo/last_album", v);
577 dt_free(v);
578 }
579}
580
582static void _piwigo_refresh_albums(dt_storage_piwigo_gui_data_t *ui, const gchar *select_album)
583{
584 gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), FALSE);
585 gtk_widget_set_sensitive(GTK_WIDGET(ui->parent_album_list), FALSE);
586
587 if(IS_NULL_PTR(ui->api) || ui->api->authenticated == FALSE)
588 {
590 if(IS_NULL_PTR(ui->api) || !ui->api->authenticated) return;
591 }
592
593 gchar *to_select;
594 int index = 0;
595
596 // get the new album name, it will be checked in the
597 if(IS_NULL_PTR(select_album))
598 {
599 to_select = g_strdup(dt_bauhaus_combobox_get_text(ui->album_list));
600 if(to_select)
601 {
602 // cut the count of picture in album to get the name only
603 gchar *p = to_select;
604 while(*p)
605 {
606 if(*p == ' ' && *(p+1) == '(')
607 {
608 *p = '\0';
609 break;
610 }
611 p++;
612 }
613 }
614 }
615 else
616 to_select = g_strdup(select_album);
617
618 // First clear the combobox except first 2 items (none / create new album)
621 g_list_free(ui->albums);
622 ui->albums = NULL;
623
624 GList *args = NULL;
625
626 args = _piwigo_query_add_arguments(args, "method", "pwg.categories.getList");
627 args = _piwigo_query_add_arguments(args, "cat_id", "0");
628 args = _piwigo_query_add_arguments(args, "recursive", "true");
629
630 _piwigo_api_post(ui->api, args, NULL, FALSE);
631
632 g_list_free(args);
633 args = NULL;
634
635 if(ui->api->response && !ui->api->error_occured)
636 {
637 dt_bauhaus_combobox_add(ui->album_list, _("create new album"));
639
640 JsonObject *result = json_node_get_object(json_object_get_member(ui->api->response, "result"));
641 JsonArray *albums = json_object_get_array_member(result, "categories");
642
643 if(json_array_get_length(albums)>0 && index==0) index = 1;
644 if(index > json_array_get_length(albums) - 1) index = json_array_get_length(albums) - 1;
645
646 for(int i = 0; i < json_array_get_length(albums); i++)
647 {
648 char data[MAX_ALBUM_NAME_SIZE] = { 0 };
649 JsonObject *album = json_array_get_object_element(albums, i);
650
651 _piwigo_album_t *new_album = g_malloc0(sizeof(struct _piwigo_album_t));
652
653 g_strlcpy(new_album->name, json_object_get_string_member(album, "name"), sizeof(new_album->name));
654 new_album->id = json_object_get_int_member(album, "id");
655 new_album->size = json_object_get_int_member(album, "nb_images");
656 const int isroot = json_object_get_null_member(album, "id_uppercat");
657 int indent = 0;
658
659 if(!isroot)
660 {
661 // Ids of parent albums coma separated
662 const char *hierarchy = json_object_get_string_member(album, "uppercats");
663 char const *p = hierarchy;
664 while(*p++) if(*p == ',') indent++;
665 }
666
667 g_snprintf(data, sizeof(data), "%*c%s (%" PRId64 ")", indent * 3, ' ', new_album->name, new_album->size);
668
669 if(to_select && !strcmp(new_album->name, to_select)) index = i + 1;
670
671 g_strlcpy(new_album->label, data, sizeof(new_album->label));
672
673 ui->albums = g_list_append(ui->albums, new_album);
674
677 }
678 }
679 else
680 dt_control_log(_("cannot refresh albums"));
681
682 dt_free(to_select);
683
684 gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), TRUE);
685 gtk_widget_set_sensitive(GTK_WIDGET(ui->parent_album_list), TRUE);
688}
689
690
692{
693 GList *args = NULL;
694
695 args = _piwigo_query_add_arguments(args, "method", "pwg.categories.add");
696 args = _piwigo_query_add_arguments(args, "name", p->album);
697 if(p->parent_album_id != 0)
698 {
699 char pid[100];
700 snprintf(pid, sizeof(pid), "%"PRId64, p->parent_album_id);
701 args = _piwigo_query_add_arguments(args, "parent", pid);
702 }
703 args = _piwigo_query_add_arguments(args, "status", p->privacy==0?"public":"private");
704
705 _piwigo_api_post(p->api, args, NULL, FALSE);
706
707 g_list_free(args);
708 args = NULL;
709
710 if(!p->api->response || p->api->error_occured)
711 {
712 return FALSE;
713 }
714 else
715 {
716 JsonObject *result = json_node_get_object(json_object_get_member(p->api->response, "result"));
717 // set new album id in parameter
718 p->album_id = json_object_get_int_member(result, "id");
719 }
720
721 return TRUE;
722}
723
725 gchar *author, gchar *caption, gchar *description)
726{
727 GList *args = NULL;
728 char cat[10];
729 char privacy[10];
730
731 // upload picture
732
733 snprintf(cat, sizeof(cat), "%"PRId64, p->album_id);
734 snprintf(privacy, sizeof(privacy), "%d", p->privacy);
735
736 args = _piwigo_query_add_arguments(args, "method", "pwg.images.addSimple");
737 args = _piwigo_query_add_arguments(args, "image", fname);
738 args = _piwigo_query_add_arguments(args, "category", cat);
739 args = _piwigo_query_add_arguments(args, "level", privacy);
740
741 if(caption && strlen(caption)>0)
742 args = _piwigo_query_add_arguments(args, "name", caption);
743
744 if(author && strlen(author)>0)
745 args = _piwigo_query_add_arguments(args, "author", author);
746
747 if(description && strlen(description)>0)
748 args = _piwigo_query_add_arguments(args, "comment", description);
749
750 if(p->tags && strlen(p->tags)>0)
751 args = _piwigo_query_add_arguments(args, "tags", p->tags);
752
753 _piwigo_api_post(p->api, args, fname, FALSE);
754
755 g_list_free(args);
756 args = NULL;
757
758 return !p->api->error_occured;
759}
760
761// Login button pressed...
762static void _piwigo_login_clicked(GtkButton *button, gpointer data)
763{
766
767 gchar *last_album = dt_conf_get_string("storage/piwigo/last_album");
768 _piwigo_refresh_albums(ui, last_album);
769 dt_conf_set_string("storage/piwigo/last_album", last_album);
770 dt_free(last_album);
771}
772
773// Refresh button pressed...
774static void _piwigo_refresh_clicked(GtkButton *button, gpointer data)
775{
777
778 gchar *last_album = dt_conf_get_string("storage/piwigo/last_album");
779 _piwigo_refresh_albums(ui, NULL);
780 dt_conf_set_string("storage/piwigo/last_album", last_album);
781 dt_free(last_album);
782}
783
784const char *name(const struct dt_imageio_module_storage_t *self)
785{
786 return _("Piwigo website");
787}
788
790{
793
794 ui->albums = NULL;
795 ui->accounts = NULL;
796 ui->api = NULL;
797
798 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
799
801
802 gchar *server = dt_conf_get_string("plugins/imageio/storage/export/piwigo/server");
803
804 // look for last server information
805 _piwigo_account_t *last_account = _piwigo_get_account(ui, server);
806
807 GtkWidget *hbox, *label, *button;
808
809 // account
811 dt_bauhaus_widget_set_label(ui->account_list, N_("accounts"));
812 int account_index = -1, index=0;
813 for(const GList *a = ui->accounts; a; a = g_list_next(a))
814 {
815 _piwigo_account_t *account = (_piwigo_account_t *)a->data;
817 if(!strcmp(account->server, server)) account_index = index;
818 index++;
819 }
820 gtk_widget_set_hexpand(ui->account_list, TRUE);
821 g_signal_connect(G_OBJECT(ui->account_list), "value-changed", G_CALLBACK(_piwigo_account_changed), (gpointer)ui);
822 gtk_box_pack_start(GTK_BOX(self->widget), ui->account_list, FALSE, FALSE, 0);
823
824 // server
825 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
826 ui->server_entry = GTK_ENTRY(gtk_entry_new());
828 gtk_widget_set_tooltip_text(GTK_WIDGET(ui->server_entry),
829 _("the server name\ndefault protocol is https\nspecify http:// if non secure server"));
830 gtk_widget_set_hexpand(GTK_WIDGET(ui->server_entry), TRUE);
831 gtk_entry_set_text(ui->server_entry, last_account?last_account->server:"piwigo.com");
832 g_signal_connect(G_OBJECT(ui->server_entry), "changed", G_CALLBACK(_piwigo_server_entry_changed), (gpointer)ui);
833 gtk_entry_set_width_chars(GTK_ENTRY(ui->server_entry), 0);
834 gtk_box_pack_start(GTK_BOX(hbox), dt_ui_label_new(_("server")), FALSE, FALSE, 0);
835 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ui->server_entry), TRUE, TRUE, 0);
836 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), TRUE, TRUE, 0);
837 dt_free(server);
838
839 // login
840 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
841 ui->user_entry = GTK_ENTRY(gtk_entry_new());
843 gtk_widget_set_hexpand(GTK_WIDGET(ui->user_entry), TRUE);
844 gtk_entry_set_text(ui->user_entry, last_account?last_account->username:"");
845 g_signal_connect(G_OBJECT(ui->user_entry), "changed", G_CALLBACK(_piwigo_entry_changed), (gpointer)ui);
846 gtk_entry_set_width_chars(GTK_ENTRY(ui->user_entry), 0);
847 gtk_box_pack_start(GTK_BOX(hbox), dt_ui_label_new(_("user")), FALSE, FALSE, 0);
848 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ui->user_entry), TRUE, TRUE, 0);
849 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), TRUE, TRUE, 0);
850
851 // password
852 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
853 ui->pwd_entry = GTK_ENTRY(gtk_entry_new());
855 gtk_entry_set_visibility(GTK_ENTRY(ui->pwd_entry), FALSE);
856 gtk_widget_set_hexpand(GTK_WIDGET(ui->pwd_entry), TRUE);
857 gtk_entry_set_text(ui->pwd_entry, last_account?last_account->password:"");
858 g_signal_connect(G_OBJECT(ui->pwd_entry), "changed", G_CALLBACK(_piwigo_entry_changed), (gpointer)ui);
859 gtk_entry_set_width_chars(GTK_ENTRY(ui->pwd_entry), 0);
860 gtk_box_pack_start(GTK_BOX(hbox), dt_ui_label_new(_("password")), FALSE, FALSE, 0);
861 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ui->pwd_entry), TRUE, TRUE, 0);
862 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), TRUE, TRUE, 0);
863
864 // login button
865 button = gtk_button_new_with_label(_("login"));
866 gtk_widget_set_tooltip_text(button, _("piwigo login"));
867 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_piwigo_login_clicked), (gpointer)ui);
868 gtk_box_pack_start(GTK_BOX(self->widget), button, FALSE, FALSE, 0);
869
870 // status area
871 ui->status_label = GTK_LABEL(gtk_label_new(NULL));
872 gtk_label_set_ellipsize(ui->status_label, PANGO_ELLIPSIZE_END);
873 gtk_widget_set_halign(GTK_WIDGET(ui->status_label), GTK_ALIGN_START);
874 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(ui->status_label), FALSE, FALSE, 0);
875
876 // select account
877 if(account_index != -1) dt_bauhaus_combobox_set(ui->account_list, account_index);
878
879 // permissions list
881 dt_bauhaus_widget_set_label(ui->permission_list, N_("visible to"));
882 dt_bauhaus_combobox_add(ui->permission_list, _("everyone"));
883 dt_bauhaus_combobox_add(ui->permission_list, _("contacts"));
884 dt_bauhaus_combobox_add(ui->permission_list, _("friends"));
887 dt_bauhaus_combobox_set(ui->permission_list, 0); // Set default permission to everyone
888 gtk_box_pack_start(GTK_BOX(self->widget), ui->permission_list, FALSE, FALSE, 0);
889
890 // album list
891 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
892
893 ui->album_list = dt_bauhaus_combobox_new(darktable.bauhaus, DT_GUI_MODULE(NULL)); // Available albums
894 dt_bauhaus_widget_set_label(ui->album_list, N_("album"));
895 g_signal_connect(G_OBJECT(ui->album_list), "value-changed", G_CALLBACK(_piwigo_album_changed), (gpointer)ui);
896 gtk_widget_set_sensitive(ui->album_list, FALSE);
897 gtk_box_pack_start(GTK_BOX(hbox), ui->album_list, TRUE, TRUE, 0);
898
900 gtk_widget_set_tooltip_text(button, _("refresh album list"));
901 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_piwigo_refresh_clicked), (gpointer)ui);
902 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
903
904 gtk_box_pack_start(GTK_BOX(self->widget), hbox, FALSE, FALSE, 0);
905
906 // new album
907 ui->create_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
908 gtk_widget_set_no_show_all(GTK_WIDGET(ui->create_box), TRUE);
909 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(ui->create_box), FALSE, FALSE, 0);
910
911 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
912
913 label = gtk_label_new(_("title"));
914 g_object_set(G_OBJECT(label), "xalign", 0.0, (gchar *)0);
915 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
916
917 ui->new_album_entry = GTK_ENTRY(gtk_entry_new()); // Album title
919 gtk_entry_set_text(ui->new_album_entry, _("new album"));
920 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(ui->new_album_entry), TRUE, TRUE, 0);
921 gtk_entry_set_width_chars(GTK_ENTRY(ui->new_album_entry), 0);
922
923 gtk_box_pack_start(ui->create_box, hbox, FALSE, FALSE, 0);
924
925 // parent album list
927 dt_bauhaus_widget_set_label(ui->parent_album_list, N_("parent album"));
928 gtk_widget_set_sensitive(ui->parent_album_list, TRUE);
929 gtk_box_pack_start(ui->create_box, ui->parent_album_list, TRUE, TRUE, 0);
930
931 _piwigo_set_status(ui, _("click login button to start"), "#ffffff");
932}
933
935{
936 dt_free(self->gui_data);
937}
938
942
943static gboolean _finalize_store(gpointer user_data)
944{
946
947 // notify that uploads are completed to empty the lounge
948
949 if(!g->api->error_occured)
950 {
951 GList *args = NULL;
952
953 args = _piwigo_query_add_arguments(args, "method", "pwg.images.uploadCompleted");
954 args = _piwigo_query_add_arguments(args, "pwg_token", g->api->pwg_token);
955
956 _piwigo_api_post(g->api, args, NULL, FALSE);
957
958 g_list_free(args);
959 args = NULL;
960 }
961
963
964 return FALSE;
965}
966
968{
969 g_main_context_invoke(NULL, _finalize_store, self->gui_data);
970}
971
972int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid,
973 dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total,
974 const gboolean high_quality, const gboolean export_masks,
975 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent,
976 dt_export_metadata_t *metadata)
977{
979
980 gint result = 0;
981
982 const char *ext = format->extension(fdata);
983
984 // Let's upload image...
985
986 /* construct a temporary file name */
987 char fname[PATH_MAX] = { 0 };
988 dt_loc_get_tmp_dir(fname, sizeof(fname));
989 g_strlcat(fname, "/darktable.XXXXXX.", sizeof(fname));
990 g_strlcat(fname, ext, sizeof(fname));
991
992 char *caption = NULL;
993 char *description = NULL;
994 char *author = NULL;
995
996 gint fd = g_mkstemp(fname);
997 if(fd == -1)
998 {
999 dt_control_log("failed to create temporary image for piwigo export");
1000 fprintf(stderr, "failed to create tempfile: %s\n", fname);
1001 return 1;
1002 }
1003 close(fd);
1004
1005 if((metadata->flags & DT_META_METADATA) && !(metadata->flags & DT_META_CALCULATED))
1006 {
1007 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r');
1008 // If title is not existing, then use the filename without extension. If not, then use title instead
1009 GList *title = dt_metadata_get(img->id, "Xmp.dc.title", NULL);
1010 if(!IS_NULL_PTR(title))
1011 {
1012 caption = g_strdup(title->data);
1013 g_list_free_full(title, dt_free_gpointer);
1014 title = NULL;
1015 }
1016 else
1017 {
1018 caption = g_path_get_basename(img->filename);
1019 gchar *dot = g_strrstr(caption, ".");
1020 if(dot) dot[0] = '\0'; // chop extension...
1021 }
1022
1023 GList *desc = dt_metadata_get(img->id, "Xmp.dc.description", NULL);
1024 if(!IS_NULL_PTR(desc))
1025 {
1026 description = g_strdup(desc->data);
1027 g_list_free_full(desc, dt_free_gpointer);
1028 desc = NULL;
1029 }
1031
1032 GList *auth = dt_metadata_get(img->id, "Xmp.dc.creator", NULL);
1033 if(!IS_NULL_PTR(auth))
1034 {
1035 author = g_strdup(auth->data);
1036 g_list_free_full(auth, dt_free_gpointer);
1037 auth = NULL;
1038 }
1039 }
1040 if(dt_imageio_export(imgid, fname, format, fdata, TRUE, TRUE, export_masks, icc_type, icc_filename,
1041 icc_intent, self, sdata, num, total, metadata) != 0)
1042 {
1043 fprintf(stderr, "[imageio_storage_piwigo] could not export to file: `%s'!\n", fname);
1044 dt_control_log(_("could not export to file `%s'!"), fname);
1045 result = 1;
1046 goto cleanup;
1047 }
1049 {
1050 gboolean status = TRUE;
1052
1053 if(metadata->flags & DT_META_TAG)
1054 {
1055 GList *tags_list = dt_tag_get_list_export(imgid, metadata->flags);
1056 p->tags = dt_util_glist_to_str(",", tags_list);
1057 g_list_free_full(tags_list, dt_free_gpointer);
1058 tags_list = NULL;
1059 }
1060
1061 if(p->new_album)
1062 {
1064 if(!status) dt_control_log(_("cannot create a new piwigo album!"));
1065 }
1066
1067 if(status)
1068 {
1069 status = _piwigo_api_upload_photo(p, fname, author, caption, description);
1070 if(!status)
1071 {
1072 fprintf(stderr, "[imageio_storage_piwigo] could not upload to piwigo!\n");
1073 dt_control_log(_("could not upload to piwigo!"));
1074 result = 1;
1075 }
1076 else if(p->new_album)
1077 {
1078 // we do not want to create more albums when multiple upload
1079 p->new_album = FALSE;
1080 _piwigo_refresh_albums(ui, p->album);
1081 }
1082 }
1083 if(p->tags)
1084 {
1085 dt_free(p->tags);
1086 }
1087 }
1089
1090cleanup:
1091
1092 // And remove from filesystem..
1093 g_unlink(fname);
1094 dt_free(caption);
1096 dt_free(author);
1097
1098 if(!result)
1099 {
1100 // this makes sense only if the export was successful
1101 dt_control_log(ngettext("%d/%d exported to piwigo webalbum", "%d/%d exported to piwigo webalbum", num),
1102 num, total);
1103 }
1104 return result;
1105}
1106
1108{
1109 return sizeof(int64_t);
1110}
1111
1113{
1114}
1115
1116static uint64_t _piwigo_album_id(const gchar *name, GList *albums)
1117{
1118 uint64_t id = 0;
1119
1120 for(const GList *a = albums; a; a = g_list_next(a))
1121 {
1122 _piwigo_album_t *album = (_piwigo_album_t *)a->data;
1123 if(!strcmp(name, album->label))
1124 {
1125 id = album->id;
1126 break;
1127 }
1128 }
1129
1130 return id;
1131}
1132
1134{
1136 if(IS_NULL_PTR(ui)) return NULL; // gui not initialized, CLI mode
1138
1139 if(IS_NULL_PTR(p)) return NULL;
1140
1141 // fill d from controls in ui
1142 if(ui->api && ui->api->authenticated == TRUE)
1143 {
1144 // create a new context for the import. set username/password to be able to connect.
1145 p->api = _piwigo_ctx_init();
1146 p->api->authenticated = FALSE;
1147 p->api->server = g_strdup(ui->api->server);
1148 p->api->username = g_strdup(ui->api->username);
1149 p->api->password = g_strdup(ui->api->password);
1150
1152
1153 int index = dt_bauhaus_combobox_get(ui->album_list);
1154
1155 p->album_id = 0;
1156 p->tags = NULL;
1157
1159 {
1160 case 0: // everyone
1161 p->privacy = 0;
1162 break;
1163 case 1: // contacts
1164 p->privacy = 1;
1165 break;
1166 case 2: // friends
1167 p->privacy = 2;
1168 break;
1169 case 3: // family
1170 p->privacy = 4;
1171 break;
1172 default: // you / admin
1173 p->privacy = 8;
1174 }
1175
1176 if(index >= 0)
1177 {
1178 switch(index)
1179 {
1180 case 0: // Create album
1182 p->album = g_strdup(gtk_entry_get_text(ui->new_album_entry));
1183 p->new_album = TRUE;
1184 break;
1185
1186 default:
1187 p->album = g_strdup(dt_bauhaus_combobox_get_text(ui->album_list));
1188 p->new_album = FALSE;
1189
1190 if(IS_NULL_PTR(p->album))
1191 {
1192 // Something went wrong...
1193 fprintf(stderr, "Something went wrong.. album index %d = NULL\n", index - 2);
1194 goto cleanup;
1195 }
1196
1197 p->album_id = _piwigo_album_id(p->album, ui->albums);
1198
1199 if(!p->album_id)
1200 {
1201 fprintf(stderr, "[imageio_storage_piwigo] cannot find album `%s'!\n", p->album);
1202 goto cleanup;
1203 }
1204
1205 break;
1206 }
1207 }
1208 else
1209 goto cleanup;
1210 }
1211 else
1212 goto cleanup;
1213
1214 return p;
1215
1216 cleanup:
1217 dt_free(p);
1218 return NULL;
1219}
1220
1221int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
1222{
1223 if(size != self->params_size(self)) return 1;
1224 // gui stuff not updated, as sensitive user data is not stored in the preset.
1225 // TODO: store name/hash in kwallet/etc module and get encrypted stuff from there!
1226 return 0;
1227}
1228
1230{
1231 if(strcmp(format->mime(NULL), "image/jpeg") == 0)
1232 return 1;
1233 else if(strcmp(format->mime(NULL), "image/png") == 0)
1234 return 1;
1235
1236 return 0;
1237}
1238
1240{
1242
1243 if(p)
1244 {
1245 dt_free(p->album);
1246 dt_free(p->tags);
1247 _piwigo_ctx_destroy(&p->api);
1248 dt_free(p);
1249 }
1250}
1251
1252// clang-format off
1253// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1254// vim: shiftwidth=2 expandtab tabstop=2 cindent
1255// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1256// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:160
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:2189
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2162
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
void dt_bauhaus_combobox_add_aligned(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align)
Definition bauhaus.c:2033
@ DT_BAUHAUS_COMBOBOX_ALIGN_LEFT
Definition bauhaus.h:124
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:134
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
dt_iop_color_intent_t
Definition colorspaces.h:63
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
char * key
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
char * name
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_string(const char *name, const char *val)
void dt_control_log(const char *msg,...)
Definition control.c:761
void dt_curl_init(CURL *curl, gboolean verbose)
Definition curl_tools.c:35
darktable_t darktable
Definition darktable.c:181
#define DT_MODULE(MODVER)
Definition darktable.h:140
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
static double dt_get_wtime(void)
Definition darktable.h:914
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_NONE
Definition dtgtk/paint.h:60
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
Definition gtk.c:3225
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
#define DT_GUI_MODULE(x)
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
Definition imageio.c:765
const float v
@ DT_META_TAG
@ DT_META_CALCULATED
@ DT_META_METADATA
size_t size
Definition mipmap_cache.c:3
void * get_params(dt_imageio_module_storage_t *self)
Definition piwigo.c:1133
static _piwigo_api_context_t * _piwigo_ctx_init(void)
Definition piwigo.c:149
int supported(dt_imageio_module_storage_t *storage, dt_imageio_module_format_t *format)
Definition piwigo.c:1229
static uint64_t _piwigo_album_id(const gchar *name, GList *albums)
Definition piwigo.c:1116
void finalize_store(struct dt_imageio_module_storage_t *self, dt_imageio_module_data_t *data)
Definition piwigo.c:967
static void _piwigo_login_clicked(GtkButton *button, gpointer data)
Definition piwigo.c:762
static void _piwigo_authenticate(dt_storage_piwigo_gui_data_t *ui)
Definition piwigo.c:472
static gboolean _finalize_store(gpointer user_data)
Definition piwigo.c:943
static void _piwigo_api_authenticate(_piwigo_api_context_t *ctx)
Definition piwigo.c:391
static int _piwigo_api_post_internal(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
Definition piwigo.c:288
static void _piwigo_load_account(dt_storage_piwigo_gui_data_t *ui)
Definition piwigo.c:188
static _piwigo_account_t * _piwigo_get_account(dt_storage_piwigo_gui_data_t *ui, const gchar *server)
Definition piwigo.c:233
static gboolean _piwigo_api_create_new_album(dt_storage_piwigo_params_t *p)
Definition piwigo.c:691
static void _piwigo_entry_changed(GtkEntry *entry, gpointer data)
Definition piwigo.c:510
void gui_cleanup(dt_imageio_module_storage_t *self)
Definition piwigo.c:934
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
Definition piwigo.c:1239
static void _piwigo_free_account(void *data)
Definition piwigo.c:180
#define MAX_ALBUM_NAME_SIZE
Definition piwigo.c:59
static void _piwigo_set_status(dt_storage_piwigo_gui_data_t *ui, gchar *message, gchar *color)
Definition piwigo.c:279
static size_t curl_write_data_cb(void *ptr, size_t size, size_t nmemb, void *data)
Definition piwigo.c:131
size_t params_size(dt_imageio_module_storage_t *self)
Definition piwigo.c:1107
void gui_init(dt_imageio_module_storage_t *self)
Definition piwigo.c:789
static GList * _piwigo_query_add_arguments(GList *args, const char *name, const char *value)
Definition piwigo.c:141
void init(dt_imageio_module_storage_t *self)
Definition piwigo.c:1112
void gui_reset(dt_imageio_module_storage_t *self)
Definition piwigo.c:939
static gboolean _piwigo_api_upload_photo(dt_storage_piwigo_params_t *p, gchar *fname, gchar *author, gchar *caption, gchar *description)
Definition piwigo.c:724
static void _piwigo_api_post(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
Definition piwigo.c:429
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
Definition piwigo.c:1221
static void _piwigo_account_changed(GtkComboBox *cb, gpointer data)
Definition piwigo.c:532
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
Definition piwigo.c:972
static void _piwigo_ctx_destroy(_piwigo_api_context_t **ctx)
Definition piwigo.c:163
static void _piwigo_refresh_albums(dt_storage_piwigo_gui_data_t *ui, const gchar *select_album)
Definition piwigo.c:582
static void _piwigo_refresh_clicked(GtkButton *button, gpointer data)
Definition piwigo.c:774
#define piwigo_EXTRA_VERBOSE
Definition piwigo.c:57
static void _piwigo_album_changed(GtkComboBox *cb, gpointer data)
Definition piwigo.c:546
static void _piwigo_set_account(dt_storage_piwigo_gui_data_t *ui)
Definition piwigo.c:246
static void _piwigo_server_entry_changed(GtkEntry *entry, gpointer data)
Definition piwigo.c:520
GHashTable * dt_pwstorage_get(const gchar *slot)
Definition pwstorage.c:228
gboolean dt_pwstorage_set(const gchar *slot, GHashTable *table)
Definition pwstorage.c:204
struct _GtkWidget GtkWidget
Definition splash.h:29
unsigned __int64 uint64_t
Definition strptime.c:75
char value[512]
Definition piwigo.c:113
char name[100]
Definition piwigo.c:112
gchar * password
Definition piwigo.c:90
gchar * username
Definition piwigo.c:89
gchar * server
Definition piwigo.c:88
int64_t id
Definition piwigo.c:80
int64_t size
Definition piwigo.c:83
char label[100]
Definition piwigo.c:82
char name[100]
Definition piwigo.c:81
gchar * cookie_file
Definition piwigo.c:68
JsonObject * response
Definition piwigo.c:66
gboolean authenticated
Definition piwigo.c:67
CURL * curl_ctx
curl context
Definition piwigo.c:64
gboolean error_occured
Definition piwigo.c:75
JsonParser * json_parser
Definition piwigo.c:65
dt_pthread_mutex_t plugin_threadsafe
Definition darktable.h:793
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_image_cache_t * image_cache
Definition darktable.h:777
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
int32_t id
Definition image.h:319
GModule *GtkWidget * widget
GtkWidget * parent_album_list
Definition piwigo.c:100
GtkWidget * permission_list
Definition piwigo.c:99
_piwigo_api_context_t * api
Definition piwigo.c:107
_piwigo_api_context_t * api
Definition piwigo.c:118
GList * dt_tag_get_list_export(int32_t imgid, int32_t flags)
Definition tags.c:963
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)
Definition utility.c:166