// Upload handler
//
-// Copyright (c) 1996-2022 by the citadel.org team
+// Copyright (c) 1996-2023 by the citadel.org team
//
// This program is open source software. Use, duplication, or
// disclosure are subject to the GNU General Public License v3.
#include "webcit.h"
+struct uploaded_file {
+ char id[64];
+ char filename[256];
+ char content_type[256];
+ long length;
+ FILE *fp;
+};
+
+Array *upload_list = NULL; // all files uploaded to this webcit instance
+pthread_mutex_t upload_list_mutex = PTHREAD_MUTEX_INITIALIZER; // Lock it before modifying
+
+
// This function is called by the MIME parser to handle data uploaded by the browser.
void upload_handler(char *name, char *filename, char *partnum, char *disp,
void *content, char *cbtype, char *cbcharset,
syslog(LOG_DEBUG, " encoding: %s", encoding);
syslog(LOG_DEBUG, " id: %s", cbid);
- // Write the upload to a file that we can pull later when the user saves the message.
- char tempfile[PATH_MAX];
- snprintf(tempfile, sizeof tempfile, "/tmp/ctdl_upload_XXXXXX");
- int fd = mkstemp(tempfile);
- if (fd < 0) {
- syslog(LOG_ERR, "upload: %s: %m", tempfile);
+ struct uploaded_file u;
+ generate_uuid(u.id);
+ safestrncpy(u.filename, filename, sizeof(u.filename));
+ safestrncpy(u.content_type, cbtype, sizeof(u.content_type));
+ u.length = length;
+
+ // Write the upload to a file that we can access later when the user saves the message.
+ u.fp = tmpfile();
+ if (!u.fp) {
+ syslog(LOG_ERR, "upload: %m");
return;
}
- write(fd, content, length);
- close(fd);
+ fwrite(content, length, 1, u.fp); // this file will be deleted by the OS when it is closed
+
+ // Create a JSON object describing this upload
+ JsonValue *j_one_upload = NewJsonObject(HKEY(""));
+ JsonObjectAppend(j_one_upload, NewJsonPlainString(HKEY("ref"), u.id, -1));
+ JsonObjectAppend(j_one_upload, NewJsonPlainString(HKEY("uploadfilename"), u.filename, -1));
+ JsonObjectAppend(j_one_upload, NewJsonPlainString(HKEY("contenttype"), u.content_type, -1));
+ JsonObjectAppend(j_one_upload, NewJsonNumber(HKEY("contentlength"), u.length));
+
+ // ...and attach it to the array of uploads
+ JsonValue *j_uploads = (JsonValue *) userdata;
+ JsonArrayAppend(j_uploads, j_one_upload);
}
// upload handler
void upload_files(struct http_transaction *h, struct ctdlsession *c) {
// FIXME reject uploads if we're not logged in
+ // This will be a JSON Array of all files that were uploaded during this HTTP transaction.
+ // Normally the browser will upload only one file per transaction, but that behavior is not guaranteed.
+ JsonValue *j_uploads = NewJsonArray(HKEY(""));
+
// h->request_body will contain the upload(s) in MIME format
- mime_parser(h->request_body, (h->request_body + h->request_body_length), *upload_handler, NULL, NULL, NULL, 0);
+ mime_parser(h->request_body, (h->request_body + h->request_body_length), *upload_handler, NULL, NULL, j_uploads, 0);
// probably do something more clever here
h->response_code = 200;
h->response_string = strdup("OK");
+
+ // send back a JSON array of all files uploaded
+ StrBuf *sj = NewStrBuf();
+ SerializeJson(sj, j_uploads, 1); // '1' == free the source object
add_response_header(h, strdup("Content-type"), strdup("application/json"));
- h->response_body = "{}";
- h->response_body_length = strlen(h->response_body);
-}
\ No newline at end of file
+ h->response_code = 200;
+ h->response_string = strdup("OK");
+ h->response_body_length = StrLength(sj);
+ h->response_body = SmashStrBuf(&sj);
+}
+
+
+// Dispatcher for paths starting with /ctdl/p/
+void ctdl_p(struct http_transaction *h, struct ctdlsession *c) {
+ if (!strcasecmp(h->url, "/ctdl/p/")) { // upload files
+ upload_files(h, c);
+ return;
+ }
+
+ do_404(h); // unknown
+}