summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-07-24 08:37:34 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-07-24 08:37:34 +0300
commit7d6ff9d0fadfe281fedf2f5da26ef577cfe07529 (patch)
tree8cb47924f95e47c73b18e6cdff7a36dfa15bac61 /src
parent4824970e2b07fc89d428095ce27113756adbe47a (diff)
Added site-specific configuration; default Titan port
When using the upload shortcut, enable configuring a specific port for Titan via site-specific parameters.
Diffstat (limited to 'src')
-rw-r--r--src/app.c3
-rw-r--r--src/sitespec.c158
-rw-r--r--src/sitespec.h37
-rw-r--r--src/ui/uploadwidget.c61
4 files changed, 251 insertions, 8 deletions
diff --git a/src/app.c b/src/app.c
index e5c47a17..abfd584a 100644
--- a/src/app.c
+++ b/src/app.c
@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32#include "history.h" 32#include "history.h"
33#include "ipc.h" 33#include "ipc.h"
34#include "periodic.h" 34#include "periodic.h"
35#include "sitespec.h"
35#include "ui/certimportwidget.h" 36#include "ui/certimportwidget.h"
36#include "ui/color.h" 37#include "ui/color.h"
37#include "ui/command.h" 38#include "ui/command.h"
@@ -752,6 +753,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
752 } 753 }
753#endif 754#endif
754 init_Prefs(&d->prefs); 755 init_Prefs(&d->prefs);
756 init_SiteSpec(dataDir_App_());
755 setCStr_String(&d->prefs.downloadDir, downloadDir_App_()); 757 setCStr_String(&d->prefs.downloadDir, downloadDir_App_());
756 set_Atomic(&d->pendingRefresh, iFalse); 758 set_Atomic(&d->pendingRefresh, iFalse);
757 d->isRunning = iFalse; 759 d->isRunning = iFalse;
@@ -832,6 +834,7 @@ static void deinit_App(iApp *d) {
832 deinit_Feeds(); 834 deinit_Feeds();
833 save_Keys(dataDir_App_()); 835 save_Keys(dataDir_App_());
834 deinit_Keys(); 836 deinit_Keys();
837 deinit_SiteSpec();
835 savePrefs_App_(d); 838 savePrefs_App_(d);
836 deinit_Prefs(&d->prefs); 839 deinit_Prefs(&d->prefs);
837 save_Bookmarks(d->bookmarks, dataDir_App_()); 840 save_Bookmarks(d->bookmarks, dataDir_App_());
diff --git a/src/sitespec.c b/src/sitespec.c
new file mode 100644
index 00000000..4df62a9f
--- /dev/null
+++ b/src/sitespec.c
@@ -0,0 +1,158 @@
1/* Copyright 2021 Jaakko Keränen <jaakko.keranen@iki.fi>
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are met:
5
61. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
82. Redistributions in binary form must reproduce the above copyright notice,
9 this list of conditions and the following disclaimer in the documentation
10 and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23#include "sitespec.h"
24
25#include <the_Foundation/file.h>
26#include <the_Foundation/path.h>
27#include <the_Foundation/stringhash.h>
28
29iDeclareClass(SiteParams)
30iDeclareObjectConstruction(SiteParams)
31
32struct Impl_SiteParams {
33 iObject object;
34 uint16_t titanPort;
35 /* TODO: theme seed, style settings */
36};
37
38void init_SiteParams(iSiteParams *d) {
39 d->titanPort = 0; /* undefined */
40}
41
42void deinit_SiteParams(iSiteParams *d) {
43 iUnused(d);
44}
45
46iDefineClass(SiteParams)
47iDefineObjectConstruction(SiteParams)
48
49/*----------------------------------------------------------------------------------------------*/
50
51struct Impl_SiteSpec {
52 iString savePath;
53 iStringHash sites;
54};
55
56static iSiteSpec siteSpec_;
57
58static void load_SiteSpec_(iSiteSpec *d) {
59 iFile *f = iClob(new_File(&d->savePath));
60 if (open_File(f, readOnly_FileMode | text_FileMode)) {
61 iString *src = collect_String(readString_File(f));
62 iRangecc split = iNullRange;
63 iString *key = collectNew_String();
64 iSiteParams *params = NULL;
65 while (nextSplit_Rangecc(range_String(src), "\n", &split)) {
66 iRangecc line = split;
67 trim_Rangecc(&line);
68 if (isEmpty_Range(&line)) {
69 continue;
70 }
71 if (startsWith_Rangecc(line, "# ")) {
72 if (params && !isEmpty_String(key)) {
73 insert_StringHash(&d->sites, key, params);
74 iReleasePtr(&params);
75 }
76 line.start += 2;
77 setRange_String(key, line);
78 params = new_SiteParams();
79 continue;
80 }
81 if (startsWith_Rangecc(line, "titanPort: ")) {
82 line.start += 11;
83 if (params) {
84 params->titanPort = atoi(cstr_Rangecc(line));
85 }
86 continue;
87 }
88 }
89 if (params && !isEmpty_String(key)) {
90 insert_StringHash(&d->sites, key, params);
91 iReleasePtr(&params);
92 }
93 }
94}
95
96static void save_SiteSpec_(iSiteSpec *d) {
97 iFile *f = new_File(&d->savePath);
98 if (open_File(f, writeOnly_FileMode | text_FileMode)) {
99 iString *buf = new_String();
100 iConstForEach(StringHash, i, &d->sites) {
101 const iBlock * key = &i.value->keyBlock;
102 const iSiteParams *params = i.value->object;
103 format_String(buf, "# %s\n", cstr_Block(key));
104 appendFormat_String(buf, "titanPort: %u\n", params->titanPort);
105 write_File(f, utf8_String(buf));
106 }
107 delete_String(buf);
108 }
109 iRelease(f);
110}
111
112void init_SiteSpec(const char *saveDir) {
113 iSiteSpec *d = &siteSpec_;
114 initCStr_String(&d->savePath, concatPath_CStr(saveDir, "sitespec.txt"));
115 init_StringHash(&d->sites);
116 load_SiteSpec_(d);
117}
118
119void deinit_SiteSpec(void) {
120 iSiteSpec *d = &siteSpec_;
121 deinit_StringHash(&d->sites);
122 deinit_String(&d->savePath);
123}
124
125void setValue_SiteSpec(const iString *site, enum iSiteSpecKey key, int value) {
126 iSiteSpec *d = &siteSpec_;
127 const iString *hashKey = collect_String(lower_String(site));
128 iSiteParams *params = value_StringHash(&d->sites, hashKey);
129 if (!params) {
130 params = new_SiteParams();
131 insert_StringHash(&d->sites, hashKey, params);
132 }
133 iBool needSave = iFalse;
134 switch (key) {
135 case titanPort_SiteSpecKey:
136 params->titanPort = iClamp(value, 0, 0xffff);
137 needSave = iTrue;
138 default:
139 break;
140 }
141 if (needSave) {
142 save_SiteSpec_(d);
143 }
144}
145
146int value_SiteSpec(const iString *site, enum iSiteSpecKey key) {
147 iSiteSpec *d = &siteSpec_;
148 const iSiteParams *params = constValue_StringHash(&d->sites, collect_String(lower_String(site)));
149 if (!params) {
150 return 0;
151 }
152 switch (key) {
153 case titanPort_SiteSpecKey:
154 return params->titanPort;
155 default:
156 return 0;
157 }
158}
diff --git a/src/sitespec.h b/src/sitespec.h
new file mode 100644
index 00000000..ee08f81f
--- /dev/null
+++ b/src/sitespec.h
@@ -0,0 +1,37 @@
1/* Copyright 2021 Jaakko Keränen <jaakko.keranen@iki.fi>
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are met:
5
61. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
82. Redistributions in binary form must reproduce the above copyright notice,
9 this list of conditions and the following disclaimer in the documentation
10 and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23#pragma once
24
25#include <the_Foundation/string.h>
26
27iDeclareType(SiteSpec)
28
29enum iSiteSpecKey {
30 titanPort_SiteSpecKey,
31};
32
33void init_SiteSpec (const char *saveDir);
34void deinit_SiteSpec (void);
35
36void setValue_SiteSpec (const iString *site, enum iSiteSpecKey key, int value); /* changes saved immediately */
37int value_SiteSpec (const iString *site, enum iSiteSpecKey key);
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index eb8039c3..22c3adf6 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27#include "color.h" 27#include "color.h"
28#include "command.h" 28#include "command.h"
29#include "gmrequest.h" 29#include "gmrequest.h"
30#include "sitespec.h"
30#include "app.h" 31#include "app.h"
31 32
32#include <the_Foundation/file.h> 33#include <the_Foundation/file.h>
@@ -36,6 +37,7 @@ iDefineObjectConstruction(UploadWidget)
36 37
37struct Impl_UploadWidget { 38struct Impl_UploadWidget {
38 iWidget widget; 39 iWidget widget;
40 iString originalUrl;
39 iString url; 41 iString url;
40 iDocumentWidget *viewer; 42 iDocumentWidget *viewer;
41 iGmRequest * request; 43 iGmRequest * request;
@@ -65,6 +67,7 @@ void init_UploadWidget(iUploadWidget *d) {
65 init_Widget(w); 67 init_Widget(w);
66 setId_Widget(w, "upload"); 68 setId_Widget(w, "upload");
67 useSheetStyle_Widget(w); 69 useSheetStyle_Widget(w);
70 init_String(&d->originalUrl);
68 init_String(&d->url); 71 init_String(&d->url);
69 d->viewer = NULL; 72 d->viewer = NULL;
70 d->request = NULL; 73 d->request = NULL;
@@ -126,15 +129,17 @@ void init_UploadWidget(iUploadWidget *d) {
126 /* Buttons. */ { 129 /* Buttons. */ {
127 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 130 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
128 iWidget *buttons = 131 iWidget *buttons =
129 makeDialogButtons_Widget((iMenuItem[]){ { "${cancel}", SDLK_ESCAPE, 0, "upload.cancel" }, 132 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" },
133 { "---", 0, 0, NULL },
134 { "${cancel}", SDLK_ESCAPE, 0, "upload.cancel" },
130 { uiTextAction_ColorEscape "${dlg.upload.send}", 135 { uiTextAction_ColorEscape "${dlg.upload.send}",
131 SDLK_RETURN, 136 SDLK_RETURN,
132 KMOD_PRIMARY, 137 KMOD_PRIMARY,
133 "upload.accept" } }, 138 "upload.accept" } },
134 2); 139 4);
135 setId_Widget(addChildPosFlags_Widget(buttons, 140 setId_Widget(insertChildAfterFlags_Widget(buttons,
136 iClob(d->counter = new_LabelWidget("", NULL)), 141 iClob(d->counter = new_LabelWidget("", NULL)),
137 front_WidgetAddPos, frameless_WidgetFlag), 142 0, frameless_WidgetFlag),
138 "upload.counter"); 143 "upload.counter");
139 addChild_Widget(w, iClob(buttons)); 144 addChild_Widget(w, iClob(buttons));
140 } 145 }
@@ -146,20 +151,44 @@ void init_UploadWidget(iUploadWidget *d) {
146 setBackupFileName_InputWidget(d->input, "uploadbackup.txt"); 151 setBackupFileName_InputWidget(d->input, "uploadbackup.txt");
147} 152}
148 153
149void deinit_UploadWidget(iUploadWidget *d) { 154void deinit_UploadWidget(iUploadWidget *d) {
150 deinit_String(&d->filePath); 155 deinit_String(&d->filePath);
151 deinit_String(&d->url); 156 deinit_String(&d->url);
157 deinit_String(&d->originalUrl);
152 iRelease(d->request); 158 iRelease(d->request);
153} 159}
154 160
155void setUrl_UploadWidget(iUploadWidget *d, const iString *url) { 161static uint16_t titanPortForUrl_(const iString *url) {
162 uint16_t port = 0;
163 const iString *root = collectNewRange_String(urlRoot_String(url));
156 iUrl parts; 164 iUrl parts;
157 init_Url(&parts, url); 165 init_Url(&parts, url);
166 /* If the port is not specified, use the site-specific configuration. */
167 if (isEmpty_Range(&parts.port) || equalCase_Rangecc(parts.scheme, "gemini")) {
168 port = value_SiteSpec(root, titanPort_SiteSpecKey);
169 }
170 else {
171 port = atoi(cstr_Rangecc(parts.port));
172 }
173 return port ? port : GEMINI_DEFAULT_PORT;
174}
175
176static void setUrlPort_UploadWidget_(iUploadWidget *d, const iString *url, uint16_t overridePort) {
177 set_String(&d->originalUrl, url);
178 iUrl parts;
179 const iString *root = collectNewRange_String(urlRoot_String(url));
180 init_Url(&parts, url);
158 setCStr_String(&d->url, "titan"); 181 setCStr_String(&d->url, "titan");
159 appendRange_String(&d->url, (iRangecc){ parts.scheme.end, constEnd_String(url) }); 182 appendRange_String(&d->url, (iRangecc){ parts.scheme.end, parts.host.end });
183 appendFormat_String(&d->url, ":%u", overridePort ? overridePort : titanPortForUrl_(url));
184 appendRange_String(&d->url, (iRangecc){ parts.path.start, constEnd_String(url) });
160 setText_LabelWidget(d->info, &d->url); 185 setText_LabelWidget(d->info, &d->url);
161} 186}
162 187
188void setUrl_UploadWidget(iUploadWidget *d, const iString *url) {
189 setUrlPort_UploadWidget_(d, url, 0);
190}
191
163void setResponseViewer_UploadWidget(iUploadWidget *d, iDocumentWidget *doc) { 192void setResponseViewer_UploadWidget(iUploadWidget *d, iDocumentWidget *doc) {
164 d->viewer = doc; 193 d->viewer = doc;
165} 194}
@@ -182,13 +211,29 @@ static void requestFinished_UploadWidget_(iUploadWidget *d, iGmRequest *req) {
182 211
183static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) { 212static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {
184 iWidget *w = as_Widget(d); 213 iWidget *w = as_Widget(d);
214 const char *cmd = command_UserEvent(ev);
185 if (isCommand_Widget(w, ev, "upload.cancel")) { 215 if (isCommand_Widget(w, ev, "upload.cancel")) {
186 /* TODO: If text has been entered, ask for confirmation. */ 216 /* TODO: If text has been entered, ask for confirmation. */
187 setupSheetTransition_Mobile(w, iFalse); 217 setupSheetTransition_Mobile(w, iFalse);
188 destroy_Widget(w); 218 destroy_Widget(w);
189 return iTrue; 219 return iTrue;
190 } 220 }
191 const char *cmd = command_UserEvent(ev); 221 if (isCommand_Widget(w, ev, "upload.setport")) {
222 if (hasLabel_Command(cmd, "value")) {
223 setValue_SiteSpec(collectNewRange_String(urlRoot_String(&d->originalUrl)),
224 titanPort_SiteSpecKey, arg_Command(cmd));
225 setUrlPort_UploadWidget_(d, &d->originalUrl, arg_Command(cmd));
226 }
227 else {
228 makeValueInput_Widget(w,
229 collectNewFormat_String("%u", titanPortForUrl_(&d->originalUrl)),
230 uiHeading_ColorEscape "${heading.uploadport}",
231 "${dlg.uploadport.msg}",
232 "${dlg.uploadport.set}",
233 format_CStr("upload.setport ptr:%p", d));
234 }
235 return iTrue;
236 }
192 if (isCommand_Widget(w, ev, "upload.accept")) { 237 if (isCommand_Widget(w, ev, "upload.accept")) {
193 iWidget * tabs = findChild_Widget(w, "upload.tabs"); 238 iWidget * tabs = findChild_Widget(w, "upload.tabs");
194 const int tabIndex = tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs)); 239 const int tabIndex = tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs));