summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/en.po11
-rw-r--r--res/lang/de.binbin24222 -> 24289 bytes
-rw-r--r--res/lang/en.binbin22823 -> 22890 bytes
-rw-r--r--res/lang/es.binbin25346 -> 25420 bytes
-rw-r--r--res/lang/fi.binbin25351 -> 25425 bytes
-rw-r--r--res/lang/fr.binbin26320 -> 26394 bytes
-rw-r--r--res/lang/ia.binbin24950 -> 25017 bytes
-rw-r--r--res/lang/ie.binbin24705 -> 24779 bytes
-rw-r--r--res/lang/pl.binbin25883 -> 25950 bytes
-rw-r--r--res/lang/ru.binbin37602 -> 37676 bytes
-rw-r--r--res/lang/sr.binbin37259 -> 37333 bytes
-rw-r--r--res/lang/tok.binbin23141 -> 23215 bytes
-rw-r--r--res/lang/zh_Hans.binbin21902 -> 21969 bytes
-rw-r--r--res/lang/zh_Hant.binbin22087 -> 22154 bytes
-rw-r--r--src/defs.h1
-rw-r--r--src/gmrequest.c12
-rw-r--r--src/gmrequest.h2
-rw-r--r--src/ui/mobile.c12
-rw-r--r--src/ui/mobile.h2
-rw-r--r--src/ui/uploadwidget.c94
20 files changed, 124 insertions, 10 deletions
diff --git a/po/en.po b/po/en.po
index 96026528..76045819 100644
--- a/po/en.po
+++ b/po/en.po
@@ -927,6 +927,15 @@ msgstr "Upload Page with Titan…"
927msgid "heading.upload" 927msgid "heading.upload"
928msgstr "UPLOAD WITH TITAN" 928msgstr "UPLOAD WITH TITAN"
929 929
930msgid "upload.id"
931msgstr "Identity:"
932
933msgid "dlg.upload.id.none"
934msgstr "None"
935
936msgid "dlg.upload.id.default"
937msgstr "Default"
938
930msgid "heading.upload.text" 939msgid "heading.upload.text"
931msgstr "Text" 940msgstr "Text"
932 941
@@ -949,7 +958,7 @@ msgid "upload.mime"
949msgstr "MIME type:" 958msgstr "MIME type:"
950 959
951msgid "upload.token" 960msgid "upload.token"
952msgstr "Upload token:" 961msgstr "Token:"
953 962
954msgid "hint.upload.token" 963msgid "hint.upload.token"
955msgstr "see server's instructions" 964msgstr "see server's instructions"
diff --git a/res/lang/de.bin b/res/lang/de.bin
index f5a6b07e..e03b96b5 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index df3c4025..8d6d5e2e 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 9f5a169f..2ed64493 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index ac3b99ef..0ec7cb1c 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 7d40e32c..9b96418a 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index d10ab85e..c916a78a 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 14349637..202c26a2 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index 9ddd137f..e009d285 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 366c6ee5..b4393e88 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index 870b0950..1972d923 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index dac5fb33..758b0442 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 3407c485..9d00b171 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index b9001e2d..5278c7b2 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
diff --git a/src/defs.h b/src/defs.h
index c3a23596..edaaecde 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -112,6 +112,7 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {
112#define star_Icon "\u2605" 112#define star_Icon "\u2605"
113#define whiteStar_Icon "\u2606" 113#define whiteStar_Icon "\u2606"
114#define person_Icon "\U0001f464" 114#define person_Icon "\U0001f464"
115#define key_Icon "\U0001f511"
115#define download_Icon "\u2ba7" 116#define download_Icon "\u2ba7"
116#define upload_Icon "\u2ba5" 117#define upload_Icon "\u2ba5"
117#define export_Icon "\U0001f4e4" 118#define export_Icon "\U0001f4e4"
diff --git a/src/gmrequest.c b/src/gmrequest.c
index 00a02983..1a9e83a9 100644
--- a/src/gmrequest.c
+++ b/src/gmrequest.c
@@ -158,6 +158,7 @@ struct Impl_GmRequest {
158 uint32_t id; 158 uint32_t id;
159 iMutex * mtx; 159 iMutex * mtx;
160 iGmCerts * certs; /* not owned */ 160 iGmCerts * certs; /* not owned */
161 const iGmIdentity * identity;
161 enum iGmRequestState state; 162 enum iGmRequestState state;
162 iString url; 163 iString url;
163 iTitanData * titan; 164 iTitanData * titan;
@@ -527,6 +528,7 @@ static void beginGopherConnection_GmRequest_(iGmRequest *d, const iString *host,
527void init_GmRequest(iGmRequest *d, iGmCerts *certs) { 528void init_GmRequest(iGmRequest *d, iGmCerts *certs) {
528 d->mtx = new_Mutex(); 529 d->mtx = new_Mutex();
529 d->id = add_Atomic(&idGen_, 1) + 1; 530 d->id = add_Atomic(&idGen_, 1) + 1;
531 d->identity = NULL;
530 d->resp = new_GmResponse(); 532 d->resp = new_GmResponse();
531 d->isFilterEnabled = iTrue; 533 d->isFilterEnabled = iTrue;
532 d->isRespLocked = iFalse; 534 d->isRespLocked = iFalse;
@@ -582,6 +584,11 @@ void setUrl_GmRequest(iGmRequest *d, const iString *url) {
582 the web. */ 584 the web. */
583 urlEncodePath_String(&d->url); 585 urlEncodePath_String(&d->url);
584 urlEncodeSpaces_String(&d->url); 586 urlEncodeSpaces_String(&d->url);
587 d->identity = identityForUrl_GmCerts(d->certs, &d->url);
588}
589
590void setIdentity_GmRequest(iGmRequest *d, const iGmIdentity *id) {
591 d->identity = id;
585} 592}
586 593
587static iBool isTitan_GmRequest_(const iGmRequest *d) { 594static iBool isTitan_GmRequest_(const iGmRequest *d) {
@@ -902,9 +909,8 @@ void submit_GmRequest(iGmRequest *d) {
902 } 909 }
903 d->state = receivingHeader_GmRequestState; 910 d->state = receivingHeader_GmRequestState;
904 d->req = new_TlsRequest(); 911 d->req = new_TlsRequest();
905 const iGmIdentity *identity = identityForUrl_GmCerts(d->certs, &d->url); 912 if (d->identity) {
906 if (identity) { 913 setCertificate_TlsRequest(d->req, d->identity->cert);
907 setCertificate_TlsRequest(d->req, identity->cert);
908 } 914 }
909 iConnect(TlsRequest, d->req, readyRead, d, readIncoming_GmRequest_); 915 iConnect(TlsRequest, d->req, readyRead, d, readIncoming_GmRequest_);
910 iConnect(TlsRequest, d->req, sent, d, bytesSent_GmRequest_); 916 iConnect(TlsRequest, d->req, sent, d, bytesSent_GmRequest_);
diff --git a/src/gmrequest.h b/src/gmrequest.h
index 97b23f3c..a377ac91 100644
--- a/src/gmrequest.h
+++ b/src/gmrequest.h
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
28#include "gmutil.h" 28#include "gmutil.h"
29 29
30iDeclareType(GmCerts) 30iDeclareType(GmCerts)
31iDeclareType(GmIdentity)
31iDeclareType(GmResponse) 32iDeclareType(GmResponse)
32 33
33enum iGmCertFlag { 34enum iGmCertFlag {
@@ -69,6 +70,7 @@ typedef void (*iGmRequestProgressFunc)(iGmRequest *, size_t current, size_t tota
69 70
70void enableFilters_GmRequest (iGmRequest *, iBool enable); 71void enableFilters_GmRequest (iGmRequest *, iBool enable);
71void setUrl_GmRequest (iGmRequest *, const iString *url); 72void setUrl_GmRequest (iGmRequest *, const iString *url);
73void setIdentity_GmRequest (iGmRequest *, const iGmIdentity *id);
72void setTitanData_GmRequest (iGmRequest *, const iString *mime, 74void setTitanData_GmRequest (iGmRequest *, const iString *mime,
73 const iBlock *payload, const iString *token); 75 const iBlock *payload, const iString *token);
74void setSendProgressFunc_GmRequest(iGmRequest *, iGmRequestProgressFunc func); 76void setSendProgressFunc_GmRequest(iGmRequest *, iGmRequestProgressFunc func);
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 459e9ce7..05e88815 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -156,6 +156,18 @@ static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd)
156 return iFalse; 156 return iFalse;
157} 157}
158 158
159size_t currentPanelIndex_Mobile(const iWidget *panels) {
160 size_t index = 0;
161 iConstForEach(ObjectList, i, children_Widget(findChild_Widget(panels, "detailstack"))) {
162 const iWidget *child = i.object;
163 if (isVisible_Widget(child)) {
164 return index;
165 }
166 index++;
167 }
168 return iInvalidPos;
169}
170
159static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) { 171static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) {
160 const iBool isPortrait = !isSideBySideLayout_(); 172 const iBool isPortrait = !isSideBySideLayout_();
161 if (equal_Command(cmd, "panel.open")) { 173 if (equal_Command(cmd, "panel.open")) {
diff --git a/src/ui/mobile.h b/src/ui/mobile.h
index e1131953..957c0e42 100644
--- a/src/ui/mobile.h
+++ b/src/ui/mobile.h
@@ -39,6 +39,8 @@ void initPanels_Mobile (iWidget *panels, iWidget *parentWidget,
39 const iMenuItem *itemsNullTerminated, 39 const iMenuItem *itemsNullTerminated,
40 const iMenuItem *actions, size_t numActions); 40 const iMenuItem *actions, size_t numActions);
41 41
42size_t currentPanelIndex_Mobile (const iWidget *panels);
43
42enum iTransitionFlags { 44enum iTransitionFlags {
43 incoming_TransitionFlag = iBit(1), 45 incoming_TransitionFlag = iBit(1),
44 dirMask_TransitionFlag = iBit(2) | iBit(3), 46 dirMask_TransitionFlag = iBit(2) | iBit(3),
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index c3f71ab9..34cace08 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -30,12 +30,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
30#include "gmrequest.h" 30#include "gmrequest.h"
31#include "sitespec.h" 31#include "sitespec.h"
32#include "window.h" 32#include "window.h"
33#include "gmcerts.h"
33#include "app.h" 34#include "app.h"
34 35
35#include <the_Foundation/file.h> 36#include <the_Foundation/file.h>
36#include <the_Foundation/fileinfo.h> 37#include <the_Foundation/fileinfo.h>
37 38
38iDefineObjectConstruction(UploadWidget) 39iDefineObjectConstruction(UploadWidget)
40
41enum iUploadIdentity {
42 none_UploadIdentity,
43 defaultForUrl_UploadIdentity,
44 dropdown_UploadIdentity,
45};
39 46
40struct Impl_UploadWidget { 47struct Impl_UploadWidget {
41 iWidget widget; 48 iWidget widget;
@@ -52,6 +59,8 @@ struct Impl_UploadWidget {
52 iLabelWidget * counter; 59 iLabelWidget * counter;
53 iString filePath; 60 iString filePath;
54 size_t fileSize; 61 size_t fileSize;
62 enum iUploadIdentity idMode;
63 iBlock idFingerprint;
55 iAtomicInt isRequestUpdated; 64 iAtomicInt isRequestUpdated;
56}; 65};
57 66
@@ -80,6 +89,26 @@ static void updateInputMaxHeight_UploadWidget_(iUploadWidget *d) {
80 (avail - inputPos.y) / lineHeight_Text(font_InputWidget(d->input)))); 89 (avail - inputPos.y) / lineHeight_Text(font_InputWidget(d->input))));
81} 90}
82 91
92static const iArray *makeIdentityItems_UploadWidget_(const iUploadWidget *d) {
93 iArray *items = collectNew_Array(sizeof(iMenuItem));
94 const iGmIdentity *urlId = identityForUrl_GmCerts(certs_App(), &d->url);
95 pushBack_Array(items, &(iMenuItem){ format_CStr("${dlg.upload.id.default} (%s)",
96 urlId ? cstr_String(name_GmIdentity(urlId)) : "${dlg.upload.id.none}"),
97 0, 0, "upload.setid arg:1" });
98 pushBack_Array(items, &(iMenuItem){ "${dlg.upload.id.none}", 0, 0, "upload.setid arg:0" });
99 pushBack_Array(items, &(iMenuItem){ "---" });
100 iConstForEach(PtrArray, i, listIdentities_GmCerts(certs_App(), NULL, NULL)) {
101 const iGmIdentity *id = i.ptr;
102 pushBack_Array(
103 items,
104 &(iMenuItem){ cstr_String(name_GmIdentity(id)), 0, 0,
105 format_CStr("upload.setid fp:%s",
106 cstrCollect_String(hexEncode_Block(&id->fingerprint))) });
107 }
108 pushBack_Array(items, &(iMenuItem){ NULL });
109 return items;
110}
111
83void init_UploadWidget(iUploadWidget *d) { 112void init_UploadWidget(iUploadWidget *d) {
84 iWidget *w = as_Widget(d); 113 iWidget *w = as_Widget(d);
85 init_Widget(w); 114 init_Widget(w);
@@ -90,6 +119,8 @@ void init_UploadWidget(iUploadWidget *d) {
90 d->request = NULL; 119 d->request = NULL;
91 init_String(&d->filePath); 120 init_String(&d->filePath);
92 d->fileSize = 0; 121 d->fileSize = 0;
122 d->idMode = defaultForUrl_UploadIdentity;
123 init_Block(&d->idFingerprint, 0);
93 const iMenuItem actions[] = { 124 const iMenuItem actions[] = {
94 { "${upload.port}", 0, 0, "upload.setport" }, 125 { "${upload.port}", 0, 0, "upload.setport" },
95 { "---" }, 126 { "---" },
@@ -117,11 +148,11 @@ void init_UploadWidget(iUploadWidget *d) {
117 initPanels_Mobile(w, NULL, (iMenuItem[]){ 148 initPanels_Mobile(w, NULL, (iMenuItem[]){
118 { "title id:heading.upload" }, 149 { "title id:heading.upload" },
119 { "label id:upload.info" }, 150 { "label id:upload.info" },
120// { "padding" },
121 { "panel id:dlg.upload.text icon:0x1f5b9", 0, 0, (const void *) textItems }, 151 { "panel id:dlg.upload.text icon:0x1f5b9", 0, 0, (const void *) textItems },
122 { "panel id:dlg.upload.file icon:0x1f4c1", 0, 0, (const void *) fileItems }, 152 { "panel id:dlg.upload.file icon:0x1f4c1", 0, 0, (const void *) fileItems },
123 { "padding" }, 153 { "padding" },
124 { "input id:upload.token hint:hint.upload.token" }, 154 { "dropdown id:upload.id icon:0x1f464", 0, 0, constData_Array(makeIdentityItems_UploadWidget_(d)) },
155 { "input id:upload.token hint:hint.upload.token icon:0x1f511" },
125 { NULL } 156 { NULL }
126 }, actions, iElemCount(actions)); 157 }, actions, iElemCount(actions));
127 d->info = findChild_Widget(w, "upload.info"); 158 d->info = findChild_Widget(w, "upload.info");
@@ -205,7 +236,8 @@ void init_UploadWidget(iUploadWidget *d) {
205 updateInputMaxHeight_UploadWidget_(d); 236 updateInputMaxHeight_UploadWidget_(d);
206} 237}
207 238
208void deinit_UploadWidget(iUploadWidget *d) { 239void deinit_UploadWidget(iUploadWidget *d) {
240 deinit_Block(&d->idFingerprint);
209 deinit_String(&d->filePath); 241 deinit_String(&d->filePath);
210 deinit_String(&d->url); 242 deinit_String(&d->url);
211 deinit_String(&d->originalUrl); 243 deinit_String(&d->originalUrl);
@@ -263,6 +295,15 @@ static void requestFinished_UploadWidget_(iUploadWidget *d, iGmRequest *req) {
263 postCommand_Widget(d, "upload.request.finished reqid:%u", id_GmRequest(req)); 295 postCommand_Widget(d, "upload.request.finished reqid:%u", id_GmRequest(req));
264} 296}
265 297
298static void updateIdentityDropdown_UploadWidget_(iUploadWidget *d) {
299 updateDropdownSelection_LabelWidget(
300 findChild_Widget(as_Widget(d), "upload.id"),
301 d->idMode == none_UploadIdentity ? " arg:0"
302 : d->idMode == defaultForUrl_UploadIdentity
303 ? " arg:1"
304 : format_CStr(" fp:%s", cstrCollect_String(hexEncode_Block(&d->idFingerprint))));
305}
306
266static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) { 307static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {
267 iWidget *w = as_Widget(d); 308 iWidget *w = as_Widget(d);
268 const char *cmd = command_UserEvent(ev); 309 const char *cmd = command_UserEvent(ev);
@@ -290,9 +331,36 @@ static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {
290 } 331 }
291 return iTrue; 332 return iTrue;
292 } 333 }
334 if (isCommand_Widget(w, ev, "upload.setid")) {
335 if (hasLabel_Command(cmd, "fp")) {
336 set_Block(&d->idFingerprint, collect_Block(hexDecode_Rangecc(range_Command(cmd, "fp"))));
337 d->idMode = dropdown_UploadIdentity;
338 }
339 else if (arg_Command(cmd)) {
340 clear_Block(&d->idFingerprint);
341 d->idMode = defaultForUrl_UploadIdentity;
342 }
343 else {
344 clear_Block(&d->idFingerprint);
345 d->idMode = none_UploadIdentity;
346 }
347 updateIdentityDropdown_UploadWidget_(d);
348 return iTrue;
349 }
293 if (isCommand_Widget(w, ev, "upload.accept")) { 350 if (isCommand_Widget(w, ev, "upload.accept")) {
294 iWidget * tabs = findChild_Widget(w, "upload.tabs"); 351 iBool isText;
295 const int tabIndex = tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs)); 352 iWidget *tabs = findChild_Widget(w, "upload.tabs");
353 if (tabs) {
354 const size_t tabIndex = tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs));
355 isText = (tabIndex == 0);
356 }
357 else {
358 const size_t panelIndex = currentPanelIndex_Mobile(w);
359 if (panelIndex == iInvalidPos) {
360 return iTrue;
361 }
362 isText = (currentPanelIndex_Mobile(w) == 0);
363 }
296 /* Make a GmRequest and send the data. */ 364 /* Make a GmRequest and send the data. */
297 iAssert(d->request == NULL); 365 iAssert(d->request == NULL);
298 iAssert(!isEmpty_String(&d->url)); 366 iAssert(!isEmpty_String(&d->url));
@@ -300,7 +368,21 @@ static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {
300 setSendProgressFunc_GmRequest(d->request, updateProgress_UploadWidget_); 368 setSendProgressFunc_GmRequest(d->request, updateProgress_UploadWidget_);
301 setUserData_Object(d->request, d); 369 setUserData_Object(d->request, d);
302 setUrl_GmRequest(d->request, &d->url); 370 setUrl_GmRequest(d->request, &d->url);
303 if (tabIndex == 0) { 371 switch (d->idMode) {
372 case defaultForUrl_UploadIdentity:
373 break; /* GmRequest handles it */
374 case none_UploadIdentity:
375 setIdentity_GmRequest(d->request, NULL);
376 signOut_GmCerts(certs_App(), url_GmRequest(d->request));
377 break;
378 case dropdown_UploadIdentity: {
379 iGmIdentity *ident = findIdentity_GmCerts(certs_App(), &d->idFingerprint);
380 setIdentity_GmRequest(d->request, ident);
381 signIn_GmCerts(certs_App(), ident, url_GmRequest(d->request));
382 break;
383 }
384 }
385 if (isText) {
304 /* Uploading text. */ 386 /* Uploading text. */
305 setTitanData_GmRequest(d->request, 387 setTitanData_GmRequest(d->request,
306 collectNewCStr_String("text/plain"), 388 collectNewCStr_String("text/plain"),