--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include <mipea/gpio.h>
+#include <curl/curl.h>
+#include <qrencode.h>
+
+#include "photobox_photo.h"
+#include "apikey.h"
+
+// fehlt in glib??
+#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
+
+void pb_exit(void);
+
+void pb_show_main(void);
+void pb_show_send(void);
+void pb_show_qr(void);
+
+gboolean pb_poll_buttton(void);
+gboolean pb_countdown(void);
+void pb_takepic(void);
+
+int pb_cp_dp(char *id);
+
+static GtkWidget *img;
+static GtkWidget *button_take;
+static GtkWidget *label_countdown;
+
+static GtkWidget *button_upload;
+static GtkWidget *button_cancel;
+
+static GtkWidget *qr_img;
+static GtkWidget *qr_label;
+static GtkWidget *qr_button_back;
+
+static const unsigned int IMG_WIDTH = 512;
+static const unsigned int IMG_HEIGHT = 384;
+static const unsigned int QR_SIZE = 350;
+
+static unsigned int button_pin = 26;
+
+int main(int argc, char *argv[])
+{
+ if (pb_ph_init() != 0) {
+ fprintf(stderr, "ERROR: pb_ph_init\n");
+ return 1;
+ }
+ if (gpio_map() == NULL) {
+ fprintf(stderr, "ERROR: gpio_map\n");
+ return 1;
+ }
+ gtk_init(&argc, &argv);
+
+ signal(SIGCHLD, SIG_IGN);
+
+ // GPIO
+ gpio_inp(button_pin);
+ gpio_pud(button_pin, PUD_UP);
+
+ // WINDOW
+ GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), "Photobox");
+ gtk_window_fullscreen(GTK_WINDOW(window));
+ //g_signal_connect(window, "delete-event", G_CALLBACK(pb_gui_on_delete_main), NULL);
+ g_signal_connect(window, "destroy", G_CALLBACK(pb_exit), NULL);
+ // hide cursor
+ gtk_widget_realize(window);
+ GdkCursor* cursor_blank = gdk_cursor_new(GDK_BLANK_CURSOR);
+ gdk_window_set_cursor(gtk_widget_get_window(window), cursor_blank);
+
+ // BOX VERTICAL
+ GtkWidget *box_v = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add(GTK_CONTAINER(window), box_v);
+ gtk_widget_show(box_v);
+
+ // BOX HORIZONTAL
+ GtkWidget *box_h = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_end(GTK_BOX(box_v), box_h, TRUE, FALSE, 0);
+ gtk_widget_show(box_h);
+
+ // IMAGE
+ img = gtk_image_new_from_file("no_signal.png");
+ gtk_box_pack_end(GTK_BOX(box_v), img, TRUE, FALSE, 0);
+
+ // BUTTON: TAKE PICTURE
+ button_take = gtk_button_new();
+ // label
+ GtkWidget *button_take_label = gtk_label_new(NULL);
+ gtk_label_set_markup(GTK_LABEL(button_take_label), "<span font='50'>Bild aufnehmen</span>");
+ gtk_container_add(GTK_CONTAINER(button_take), button_take_label);
+ gtk_widget_show(button_take_label);
+ // /label
+ gtk_box_pack_start(GTK_BOX(box_h), button_take, TRUE, FALSE, 0);
+ g_signal_connect(button_take, "clicked", G_CALLBACK(pb_countdown), NULL);
+
+ // COUNTDOWN LABEL
+ label_countdown = gtk_label_new(NULL);
+ gtk_box_pack_end(GTK_BOX(box_v), label_countdown, TRUE, FALSE, 0);
+
+ // BUTTON: UPLOAD
+ button_upload = gtk_button_new_with_label("Hochladen");
+ //g_signal_connect(button_upload, "clicked", G_CALLBACK(pb_exit), NULL);
+ g_signal_connect(button_upload, "clicked", G_CALLBACK(pb_show_qr), NULL);
+ gtk_box_pack_start(GTK_BOX(box_h), button_upload, TRUE, FALSE, 0);
+
+ // BUTTON: CANCEL
+ button_cancel = gtk_button_new_with_label("Abbrechen");
+ //g_signal_connect(button_cancel, "clicked", G_CALLBACK(pb_exit), NULL);
+ g_signal_connect(button_cancel, "clicked", G_CALLBACK(pb_show_main), NULL);
+ gtk_box_pack_start(GTK_BOX(box_h), button_cancel, TRUE, FALSE, 0);
+
+ // QR CODE IMAGE
+ qr_img = gtk_image_new_from_file("no_signal.png");
+ gtk_box_pack_end(GTK_BOX(box_v), qr_img, TRUE, FALSE, 0);
+
+ // QR CODE LABEL
+ qr_label = gtk_label_new(NULL);
+ gtk_label_set_justify(GTK_LABEL(qr_label), GTK_JUSTIFY_CENTER);
+ gtk_label_set_line_wrap(GTK_LABEL(qr_label), TRUE);
+ gtk_box_pack_end(GTK_BOX(box_v), qr_label, TRUE, FALSE, 0);
+
+ // QR BUTTON BACK
+ qr_button_back = gtk_button_new_with_label("Zurück");
+ g_signal_connect(qr_button_back, "clicked", G_CALLBACK(pb_show_main), NULL);
+ //g_signal_connect(qr_button_back, "clicked", G_CALLBACK(pb_exit), NULL);
+ gtk_box_pack_start(GTK_BOX(box_h), qr_button_back, TRUE, FALSE, 0);
+
+ pb_show_main();
+ gtk_widget_show(window);
+
+ gtk_main();
+
+ return 0;
+}
+
+void pb_exit(void)
+{
+ gpio_unmap();
+ gtk_main_quit();
+}
+
+void pb_show_main(void)
+{
+ gtk_widget_hide(img);
+ gtk_widget_hide(button_upload);
+ gtk_widget_hide(button_cancel);
+ gtk_widget_hide(qr_img);
+ gtk_widget_hide(qr_label);
+ gtk_widget_hide(qr_button_back);
+
+ gtk_widget_show(button_take);
+
+ // take picture with button
+ g_idle_add(G_SOURCE_FUNC(pb_poll_buttton), NULL);
+}
+
+void pb_show_send(void)
+{
+ gtk_widget_show(img);
+ gtk_widget_show(button_upload);
+ gtk_widget_show(button_cancel);
+
+ gtk_widget_hide(label_countdown);
+}
+
+void pb_show_qr(void)
+{
+ gtk_widget_hide(img);
+ gtk_widget_hide(button_upload);
+ gtk_widget_hide(button_cancel);
+
+ gtk_widget_show(qr_img);
+ gtk_widget_show(qr_label);
+ gtk_widget_show(qr_button_back);
+
+ // id from time
+ char id[7];
+ strftime(id, 7, "%H%M%S", localtime(&(time_t) {time(NULL)}));
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // child -> copy and upload
+ if (pb_cp_dp(id) < 0) {
+ fprintf(stderr, "Error: pb_cp_dp\n");
+ exit(EXIT_FAILURE);
+ } else {
+ exit(EXIT_SUCCESS);
+ }
+ } else if (pid < 0) {
+ fprintf(stderr, "FORK ERROR!!!!!\n");
+ // TODO: dont show qr
+ }
+
+ // url qr should point to
+ // example: https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a?dl=0&preview=c1b052c5.jpg
+ char url[] = "https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a?dl=0&preview=xxxxxx.jpg";
+ for (unsigned int i = 0; i < 6; ++i) {
+ url[i + 82] = id[i];
+ }
+
+ // generate qr code
+ QRcode *qr = QRcode_encodeString(url, 0, QR_ECLEVEL_H, QR_MODE_8, 1);
+ if (qr == NULL) {
+ perror("Failed to generate QR-Code");
+ pb_exit();
+ }
+
+ unsigned int size = qr->width;
+ char values[10];
+ sprintf(values, "%d %d 2 1", size, size);
+
+ const char *xface[3 + size];
+ xface[0] = values;
+ xface[1] = "a c #ffffff";
+ xface[2] = "b c #000000";
+
+ char qrcode_char[size][size + 1];
+ for (unsigned int i = 0; i < size; ++i) {
+ qrcode_char[i][size] = '\0';
+ for (unsigned int j = 0; j < size; ++j) {
+ qrcode_char[i][j] = qr->data[j + i * size] & 1 ? 'b' : 'a';
+ }
+ xface[3 + i] = &qrcode_char[i][0];
+ }
+ QRcode_free(qr);
+
+ GdkPixbuf *pb = gdk_pixbuf_new_from_xpm_data(xface);
+
+ pb = gdk_pixbuf_scale_simple(pb, QR_SIZE, QR_SIZE, GDK_INTERP_NEAREST);
+ gtk_image_set_from_pixbuf((GtkImage *)qr_img, pb);
+ g_clear_object(&pb);
+
+ char text[] = "<span font='12'>QR-Code scannen oder auf <b>https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a</b> gehen. <small>Der Upload kann einige Minuten dauern.</small></span>";
+ gtk_label_set_markup(GTK_LABEL(qr_label), text);
+}
+
+gboolean pb_poll_buttton(void)
+{
+ if (gpio_tst(button_pin) == 0) {
+ pb_countdown();
+ return G_SOURCE_REMOVE;
+ } else {
+ return G_SOURCE_CONTINUE;
+ }
+}
+
+gboolean pb_countdown(void)
+{
+ static int num = 0;
+
+ switch(num) {
+ case 0:
+ num = 5;
+
+ g_idle_remove_by_data(NULL);
+
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>5</span>");
+ gtk_widget_hide(button_take);
+ gtk_widget_show(label_countdown);
+
+ g_timeout_add(1000, G_SOURCE_FUNC(pb_countdown), NULL);
+ return G_SOURCE_CONTINUE;
+ case 5:
+ num = 4;
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>4</span>");
+ return G_SOURCE_CONTINUE;
+ case 4:
+ num = 3;
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>3</span>");
+ return G_SOURCE_CONTINUE;
+ case 3:
+ num = 2;
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>2</span>");
+ return G_SOURCE_CONTINUE;
+ case 2:
+ num = 1;
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>1</span>");
+ return G_SOURCE_CONTINUE;
+ case 1:
+ num = 0;
+ gtk_label_set_markup(GTK_LABEL(label_countdown),
+ "<span font='300' color='red'>0</span>");
+
+ // 0 zeigen bevor der anfängt zu rechnen
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+
+ // bild aufnehmen
+ pb_takepic();
+ pb_show_send();
+ return G_SOURCE_REMOVE;
+ }
+ // wenn das passiert ist was schief gelaufen
+ printf("etwas ist sehr schief gelaufen\n");
+ return G_SOURCE_REMOVE;
+}
+
+void pb_takepic(void)
+{
+ char *fn = "tmp.jpg";
+ if (pb_ph_capture_file(fn) != 0) {
+ fprintf(stderr, "ERROR: pb_ph_capture_file\n");
+ gtk_main_quit();
+ return;
+ }
+
+ GdkPixbuf *pb = gdk_pixbuf_new_from_file(fn, NULL);
+ pb = gdk_pixbuf_scale_simple(pb, IMG_WIDTH, IMG_HEIGHT, GDK_INTERP_BILINEAR);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(img), pb);
+ g_clear_object(&pb);
+}
+
+int pb_cp_dp(char *id)
+{
+ char buffer[4096];
+ size_t num_read;
+ size_t dest_fsize;
+
+ char src[] = "tmp.jpg";
+ char dest[] = "bilder/xxxxxx.jpg";
+ char dropbox_arg[] = "Dropbox-API-Arg: {\"path\": \"/bilder/xxxxxx.jpg\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}";
+
+ for (unsigned int i = 0; i < 6; ++i) {
+ dest[i + 7] = id[i];
+ dropbox_arg[i + 35] = id[i];
+ }
+
+ FILE *src_file = fopen(src, "rb");
+ if (src_file == NULL) {
+ perror("Error opening \"tmp.jpg\"");
+ return -1;
+ }
+ FILE *dest_file = fopen(dest, "wb+");
+ if (dest_file == NULL) {
+ fclose(src_file);
+ perror("Error opening destination file");
+ return -1;
+ }
+
+ do {
+ num_read = fread(buffer, 1, 4096, src_file);
+ dest_fsize += num_read;
+ if (fwrite(buffer, 1, num_read, dest_file) != num_read && ferror(dest_file) != 0) {
+ fprintf(stderr, "Error writing to destination file");
+ goto error_file;
+ }
+ } while(num_read == 4096);
+ if (ferror(src_file) != 0) {
+ fprintf(stderr, "Error reading from \"tmp.jpg\"");
+ goto error_file;
+ }
+
+ fclose(src_file);
+ rewind(dest_file); // from beginning for upload
+
+ // upload
+ curl_global_init(CURL_GLOBAL_ALL);
+ CURL *curl = curl_easy_init();
+ if (curl == NULL) {
+ fprintf(stderr, "ERROR: curl_easy_init\n");
+ curl_global_cleanup();
+ goto error_file;
+ }
+
+ struct curl_slist *header = NULL;
+ header = curl_slist_append(header, "Authorization: Bearer " APIKEY);
+ header = curl_slist_append(header, dropbox_arg);
+ header = curl_slist_append(header, "Content-Type: application/octet-stream");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
+
+ curl_easy_setopt(curl, CURLOPT_URL, "https://content.dropboxapi.com/2/files/upload");
+
+ curl_easy_setopt(curl, CURLOPT_POST, 1L); // post request
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, dest_fsize); // file size
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); // use read callback
+ curl_easy_setopt(curl, CURLOPT_READDATA, dest_file); // file pointer
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); // default callback
+
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); // disable output
+
+ CURLcode ret = curl_easy_perform(curl);
+ if (ret != CURLE_OK) {
+ fprintf(stderr, "ERROR: curl_easy_perform: %s\n", curl_easy_strerror(ret));
+ goto error_curl;
+ }
+
+ curl_slist_free_all(header);
+ curl_easy_cleanup(curl);
+
+ curl_global_cleanup();
+
+ fclose(dest_file);
+
+ return 0;
+
+ error_curl:
+ curl_slist_free_all(header);
+ curl_easy_cleanup(curl);
+
+ curl_global_cleanup();
+
+ error_file:
+ fclose(dest_file);
+
+ return -1;
+}