From 915e8c34973258955ab3170ca43fca00b4207e4e Mon Sep 17 00:00:00 2001
From: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Date: Mon, 26 Aug 2024 01:18:42 +0200
Subject: [PATCH 3/3] WIP multi-file uploads

TODO: send file data on-the-fly instead of dumping file contents into
memory.
---
 src/dialog.cc | 15 -----------
 src/dialog.hh |  2 --
 src/form.cc   | 75 +++++++++++++++++++++++++++++++++++++--------------
 src/uicmd.cc  |  4 +--
 src/uicmd.hh  |  3 ++-
 5 files changed, 59 insertions(+), 40 deletions(-)

diff --git a/src/dialog.cc b/src/dialog.cc
index 6e4f6e6d..e818d028 100644
--- a/src/dialog.cc
+++ b/src/dialog.cc
@@ -249,21 +249,6 @@ const char *a_Dialog_save_file(const char *title,
    return fl_file_chooser(title, pattern, fname);
 }
 
-/**
- * Show the select file dialog.
- *
- * @return pointer to chosen filename, or NULL on Cancel.
- */
-const char *a_Dialog_select_file(const char *title,
-                                 const char *pattern, const char *fname)
-{
-   /*
-    * FileChooser::type(MULTI) appears to allow multiple files to be selected,
-    * but just follow save_file's path for now.
-    */
-   return a_Dialog_save_file(title, pattern, fname);
-}
-
 /**
  * Show the open file dialog.
  *
diff --git a/src/dialog.hh b/src/dialog.hh
index 4a360494..61a65090 100644
--- a/src/dialog.hh
+++ b/src/dialog.hh
@@ -18,8 +18,6 @@ const char *a_Dialog_input(const char *title, const char *msg);
 const char *a_Dialog_passwd(const char *title, const char *msg);
 const char *a_Dialog_save_file(const char *title,
                                const char *pattern, const char *fname);
-const char *a_Dialog_select_file(const char *title,
-                                 const char *pattern, const char *fname);
 Dlist *a_Dialog_select_files(const char *title,
                          const char *pattern, const char *fname);
 char *a_Dialog_open_file(const char *title,
diff --git a/src/form.cc b/src/form.cc
index 6e81edf6..b1407ab7 100644
--- a/src/form.cc
+++ b/src/form.cc
@@ -13,6 +13,7 @@
 #include "html_common.hh"
 
 #include <errno.h>
+#include <stdio.h>
 #include <iconv.h>
 
 #include "lout/misc.hh"
@@ -150,13 +151,12 @@ public:  //BUG: for now everything is public
                          entries, it is the initial value */
    DilloHtmlSelect *select;
    bool init_val;     /* only meaningful for buttons */
-   Dstr *file_data;   /* only meaningful for file inputs.
-                         TODO: may become a list... */
+   Dlist *file_list;   /* only meaningful for file inputs. */
 
 private:
    void connectTo(DilloHtmlReceiver *form_receiver);
    void activate(DilloHtmlForm *form, int num_entry_fields,EventButton *event);
-   void readFile(BrowserWindow *bw);
+   void getFileList(BrowserWindow *bw);
 
 public:
    DilloHtmlInput (DilloHtmlInputType type, Embed *embed,
@@ -1175,6 +1175,7 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit)
 
          if ((valcount = dList_length(values)) > 0) {
             if (input->type == DILLO_HTML_INPUT_FILE) {
+#if 0
                if (valcount > 1)
                   MSG_WARN("multiple files per form control not supported\n");
                Dstr *file = (Dstr *) dList_nth_data(values, 0);
@@ -1195,6 +1196,7 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit)
                   dStr_free(dfilename, 1);
                }
                dStr_free(file, 1);
+#endif
             } else if (input->type == DILLO_HTML_INPUT_INDEX) {
                /* no name */
                Dstr *val = (Dstr *) dList_nth_data(values, 0);
@@ -1290,6 +1292,7 @@ char *DilloHtmlForm::makeMultipartBoundary(iconv_t char_encoder,
          dStr_free(dstr, 1);
       }
       if (input->type == DILLO_HTML_INPUT_FILE) {
+#if 0
          LabelButtonResource *lbr =
             (LabelButtonResource*)input->embed->getResource();
          const char *filename = lbr->getLabel();
@@ -1299,6 +1302,7 @@ char *DilloHtmlForm::makeMultipartBoundary(iconv_t char_encoder,
             dStr_append_l(DataStr, dstr->str, dstr->len);
             dStr_free(dstr, 1);
          }
+#endif
       }
       int length = dList_length(values);
       for (int i = 0; i < length; i++) {
@@ -1659,7 +1663,8 @@ void DilloHtmlReceiver::clicked (Resource *resource,
  */
 DilloHtmlInput::DilloHtmlInput (DilloHtmlInputType type2, Embed *embed2,
                                 const char *name2, const char *init_str2,
-                                bool init_val2)
+                                bool init_val2) :
+   file_list(NULL)
 {
    type = type2;
    embed = embed2;
@@ -1675,7 +1680,6 @@ DilloHtmlInput::DilloHtmlInput (DilloHtmlInputType type2, Embed *embed2,
    default:
       break;
    }
-   file_data = NULL;
    reset ();
 }
 
@@ -1686,7 +1690,14 @@ DilloHtmlInput::~DilloHtmlInput ()
 {
    dFree(name);
    dFree(init_str);
-   dStr_free(file_data, 1);
+
+   if (file_list) {
+      for (int i = 0; i < file_list->len; i++)
+         free(file_list->list[i]);
+   }
+
+   dList_free(file_list);
+
    if (select)
       delete select;
 }
@@ -1721,7 +1732,7 @@ void DilloHtmlInput::activate(DilloHtmlForm *form, int num_entry_fields,
 {
    switch (type) {
    case DILLO_HTML_INPUT_FILE:
-      readFile (form->html->bw);
+      getFileList(form->html->bw);
       break;
    case DILLO_HTML_INPUT_RESET:
    case DILLO_HTML_INPUT_BUTTON_RESET:
@@ -1747,21 +1758,32 @@ void DilloHtmlInput::activate(DilloHtmlForm *form, int num_entry_fields,
 /**
  * Read a file into cache
  */
-void DilloHtmlInput::readFile (BrowserWindow *bw)
-{
-   const char *filename = a_UIcmd_select_file();
-   if (filename) {
-      a_UIcmd_set_msg(bw, "Loading file...");
-      dStr_free(file_data, 1);
-      file_data = a_Misc_file2dstr(filename);
-      if (file_data) {
-         a_UIcmd_set_msg(bw, "File loaded.");
-         LabelButtonResource *lbr = (LabelButtonResource*)embed->getResource();
-         lbr->setLabel(filename);
-      } else {
-         a_UIcmd_set_msg(bw, "ERROR: can't load: %s", filename);
+void DilloHtmlInput::getFileList (BrowserWindow *bw)
+{
+   file_list = a_UIcmd_select_files();
+
+   if (!file_list)
+      return;
+
+   LabelButtonResource *lbr = (LabelButtonResource*)embed->getResource();
+   char buf[sizeof "18446744073709551615 files selected"];
+   const char *label;
+
+   if (file_list->len > 1) {
+      int n = snprintf(buf, sizeof(buf), "%d files selected",
+         file_list->len);
+
+      if (n < 0 || (size_t)n >= sizeof(buf)) {
+         printf("getFileList: snprintf(3) returned %d", n);
+         return;
       }
+
+      label = buf;
+   } else {
+      label = (const char *)file_list->list[0];
    }
+
+   lbr->setLabel(label);
 }
 
 /**
@@ -1810,6 +1832,16 @@ void DilloHtmlInput::appendValuesTo(Dlist *values, bool is_active_submit)
       break;
    case DILLO_HTML_INPUT_FILE:
       {
+         if (!file_list) {
+            fprintf(stderr, "Upload file list is empty\n");
+            break;
+         }
+
+         for (int i = 0; i < file_list->len; i++) {
+            dList_append(values, dStr_new((const char *)file_list->list[i]));
+         }
+
+#if 0
          LabelButtonResource *lbr = (LabelButtonResource*)embed->getResource();
          const char *filename = lbr->getLabel();
          if (filename[0] && strcmp(filename, init_str)) {
@@ -1821,6 +1853,9 @@ void DilloHtmlInput::appendValuesTo(Dlist *values, bool is_active_submit)
                MSG("FORM file input \"%s\" not loaded.\n", filename);
             }
          }
+#else
+#warning TODO
+#endif
       }
       break;
    case DILLO_HTML_INPUT_IMAGE:
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 187aeabc..c66e2c30 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -1070,9 +1070,9 @@ void a_UIcmd_save(void *vbw)
 /*
  * Select a file
  */
-const char *a_UIcmd_select_file()
+Dlist *a_UIcmd_select_files()
 {
-   return a_Dialog_select_file("Dillo: Select a File", NULL, NULL);
+   return a_Dialog_select_files("Dillo: Select a File", NULL, NULL);
 }
 
 /*
diff --git a/src/uicmd.hh b/src/uicmd.hh
index 0a5c8fb5..deeec29e 100644
--- a/src/uicmd.hh
+++ b/src/uicmd.hh
@@ -14,6 +14,7 @@
 #define __UICMD_HH__
 
 #include "bw.h"
+#include "dlib/dlib.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,7 +45,7 @@ void a_UIcmd_stop(void *vbw);
 void a_UIcmd_tools(void *vbw, int x, int y);
 void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url);
 void a_UIcmd_open_file(void *vbw);
-const char *a_UIcmd_select_file(void);
+Dlist *a_UIcmd_select_files(void);
 void a_UIcmd_search_dialog(void *vbw);
 const char *a_UIcmd_get_passwd(const char *user);
 void a_UIcmd_book(void *vbw);
-- 
2.34.1

