diff options
-rw-r--r-- | po/en.po | 9 | ||||
-rw-r--r-- | res/about/version.gmi | 5 | ||||
-rw-r--r-- | res/lang/cs.bin | bin | 30899 -> 30962 bytes | |||
-rw-r--r-- | res/lang/de.bin | bin | 29906 -> 29969 bytes | |||
-rw-r--r-- | res/lang/en.bin | bin | 26003 -> 26066 bytes | |||
-rw-r--r-- | res/lang/eo.bin | bin | 24957 -> 25020 bytes | |||
-rw-r--r-- | res/lang/es.bin | bin | 29730 -> 29793 bytes | |||
-rw-r--r-- | res/lang/es_MX.bin | bin | 27062 -> 27125 bytes | |||
-rw-r--r-- | res/lang/fi.bin | bin | 29563 -> 29626 bytes | |||
-rw-r--r-- | res/lang/fr.bin | bin | 30710 -> 30773 bytes | |||
-rw-r--r-- | res/lang/gl.bin | bin | 28915 -> 28978 bytes | |||
-rw-r--r-- | res/lang/hu.bin | bin | 30735 -> 30798 bytes | |||
-rw-r--r-- | res/lang/ia.bin | bin | 28062 -> 28125 bytes | |||
-rw-r--r-- | res/lang/ie.bin | bin | 28650 -> 28713 bytes | |||
-rw-r--r-- | res/lang/isv.bin | bin | 24723 -> 24786 bytes | |||
-rw-r--r-- | res/lang/pl.bin | bin | 29338 -> 29401 bytes | |||
-rw-r--r-- | res/lang/ru.bin | bin | 44098 -> 44161 bytes | |||
-rw-r--r-- | res/lang/sk.bin | bin | 25059 -> 25122 bytes | |||
-rw-r--r-- | res/lang/sr.bin | bin | 43524 -> 43587 bytes | |||
-rw-r--r-- | res/lang/tok.bin | bin | 26772 -> 26835 bytes | |||
-rw-r--r-- | res/lang/tr.bin | bin | 28956 -> 29019 bytes | |||
-rw-r--r-- | res/lang/uk.bin | bin | 43443 -> 43506 bytes | |||
-rw-r--r-- | res/lang/zh_Hans.bin | bin | 24957 -> 25020 bytes | |||
-rw-r--r-- | res/lang/zh_Hant.bin | bin | 25155 -> 25218 bytes | |||
-rw-r--r-- | src/app.c | 19 | ||||
-rw-r--r-- | src/gmcerts.c | 9 | ||||
-rw-r--r-- | src/gmcerts.h | 5 | ||||
-rw-r--r-- | src/sitespec.c | 81 | ||||
-rw-r--r-- | src/sitespec.h | 20 | ||||
-rw-r--r-- | src/ui/root.c | 89 |
30 files changed, 214 insertions, 23 deletions
@@ -321,6 +321,10 @@ msgstr "Show History" | |||
321 | msgid "menu.show.identities" | 321 | msgid "menu.show.identities" |
322 | msgstr "Show Identities" | 322 | msgstr "Show Identities" |
323 | 323 | ||
324 | # Active identity toolbar menu. | ||
325 | msgid "menu.hide.identities" | ||
326 | msgstr "Hide Identities" | ||
327 | "" | ||
324 | # Used in the View menu on macOS. Shows sidebar and switches sidebar tab. | 328 | # Used in the View menu on macOS. Shows sidebar and switches sidebar tab. |
325 | msgid "menu.show.outline" | 329 | msgid "menu.show.outline" |
326 | msgstr "Show Page Outline" | 330 | msgstr "Show Page Outline" |
@@ -629,6 +633,11 @@ msgstr "Stop Using Everywhere" | |||
629 | msgid "ident.export" | 633 | msgid "ident.export" |
630 | msgstr "Export" | 634 | msgstr "Export" |
631 | 635 | ||
636 | # The %s represents the name of an identity. | ||
637 | #, c-format | ||
638 | msgid "ident.switch" | ||
639 | msgstr "Switch to %s" | ||
640 | |||
632 | msgid "heading.ident.use" | 641 | msgid "heading.ident.use" |
633 | msgstr "IDENTITY USAGE" | 642 | msgstr "IDENTITY USAGE" |
634 | 643 | ||
diff --git a/res/about/version.gmi b/res/about/version.gmi index a9043b2c..7a14e79b 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi | |||
@@ -6,6 +6,10 @@ | |||
6 | ``` | 6 | ``` |
7 | # Release notes | 7 | # Release notes |
8 | 8 | ||
9 | ## 1.10 | ||
10 | New features: | ||
11 | * Identity toolbar menu can be used to switch between alternate identities that have been used on the site. If you have multiple accounts on a site, this makes it more convenient to switch between them. | ||
12 | |||
9 | ## 1.9.2 | 13 | ## 1.9.2 |
10 | * Windows: Use the correct version number for update checks. | 14 | * Windows: Use the correct version number for update checks. |
11 | * Shorter label for "Mark All as Read" in Feeds sidebar actions. | 15 | * Shorter label for "Mark All as Read" in Feeds sidebar actions. |
@@ -22,7 +26,6 @@ | |||
22 | * Fixed the New Tab button not staying at the right edge of the window, depending on how many tabs are open. | 26 | * Fixed the New Tab button not staying at the right edge of the window, depending on how many tabs are open. |
23 | 27 | ||
24 | ## 1.9 | 28 | ## 1.9 |
25 | |||
26 | New features: | 29 | New features: |
27 | * Added a toolbar button for toggling the left sidebar. | 30 | * Added a toolbar button for toggling the left sidebar. |
28 | * Added an unsplit button in the toolbar when in split view mode. | 31 | * Added an unsplit button in the toolbar when in split view mode. |
diff --git a/res/lang/cs.bin b/res/lang/cs.bin index 647e1f34..d3e06c73 100644 --- a/res/lang/cs.bin +++ b/res/lang/cs.bin | |||
Binary files differ | |||
diff --git a/res/lang/de.bin b/res/lang/de.bin index b2bb35a0..b9d155a7 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 fbf4c73c..5bb8299a 100644 --- a/res/lang/en.bin +++ b/res/lang/en.bin | |||
Binary files differ | |||
diff --git a/res/lang/eo.bin b/res/lang/eo.bin index 7156b7c8..ff1ddb01 100644 --- a/res/lang/eo.bin +++ b/res/lang/eo.bin | |||
Binary files differ | |||
diff --git a/res/lang/es.bin b/res/lang/es.bin index 1acb50d1..ba9b2343 100644 --- a/res/lang/es.bin +++ b/res/lang/es.bin | |||
Binary files differ | |||
diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin index 078de89d..f4ddcc72 100644 --- a/res/lang/es_MX.bin +++ b/res/lang/es_MX.bin | |||
Binary files differ | |||
diff --git a/res/lang/fi.bin b/res/lang/fi.bin index ccd3e133..f73891d6 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 96c1148e..0851f535 100644 --- a/res/lang/fr.bin +++ b/res/lang/fr.bin | |||
Binary files differ | |||
diff --git a/res/lang/gl.bin b/res/lang/gl.bin index 4269b5ed..80215589 100644 --- a/res/lang/gl.bin +++ b/res/lang/gl.bin | |||
Binary files differ | |||
diff --git a/res/lang/hu.bin b/res/lang/hu.bin index 7b7edb50..7d7ed94e 100644 --- a/res/lang/hu.bin +++ b/res/lang/hu.bin | |||
Binary files differ | |||
diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 4750b545..572015c2 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 e4c90ef9..bb485f4e 100644 --- a/res/lang/ie.bin +++ b/res/lang/ie.bin | |||
Binary files differ | |||
diff --git a/res/lang/isv.bin b/res/lang/isv.bin index 80754fc5..f90a1e7d 100644 --- a/res/lang/isv.bin +++ b/res/lang/isv.bin | |||
Binary files differ | |||
diff --git a/res/lang/pl.bin b/res/lang/pl.bin index c0affedf..753e595b 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 966deaea..edcebb14 100644 --- a/res/lang/ru.bin +++ b/res/lang/ru.bin | |||
Binary files differ | |||
diff --git a/res/lang/sk.bin b/res/lang/sk.bin index deda3b69..b843a383 100644 --- a/res/lang/sk.bin +++ b/res/lang/sk.bin | |||
Binary files differ | |||
diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 8d8591e6..1ef302d9 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 1b0c0733..6e3c7af7 100644 --- a/res/lang/tok.bin +++ b/res/lang/tok.bin | |||
Binary files differ | |||
diff --git a/res/lang/tr.bin b/res/lang/tr.bin index 60ef518d..71b9382f 100644 --- a/res/lang/tr.bin +++ b/res/lang/tr.bin | |||
Binary files differ | |||
diff --git a/res/lang/uk.bin b/res/lang/uk.bin index 2ed16909..f7040f2f 100644 --- a/res/lang/uk.bin +++ b/res/lang/uk.bin | |||
Binary files differ | |||
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 3a83dd40..3ccab576 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 7da4b273..39393417 100644 --- a/res/lang/zh_Hant.bin +++ b/res/lang/zh_Hant.bin | |||
Binary files differ | |||
@@ -3149,6 +3149,25 @@ iBool handleCommand_App(const char *cmd) { | |||
3149 | postCommand_App("idents.changed"); | 3149 | postCommand_App("idents.changed"); |
3150 | return iTrue; | 3150 | return iTrue; |
3151 | } | 3151 | } |
3152 | else if (equal_Command(cmd, "ident.switch")) { | ||
3153 | /* This is different than "ident.signin" in that the currently used identity's activation | ||
3154 | URL is used instead of the current one. */ | ||
3155 | const iString *docUrl = url_DocumentWidget(document_App()); | ||
3156 | const iGmIdentity *cur = identityForUrl_GmCerts(d->certs, docUrl); | ||
3157 | iGmIdentity *dst = findIdentity_GmCerts( | ||
3158 | d->certs, collect_Block(hexDecode_Rangecc(range_Command(cmd, "fp")))); | ||
3159 | if (cur && dst && cur != dst) { | ||
3160 | iString *useUrl = copy_String(findUse_GmIdentity(cur, docUrl)); | ||
3161 | if (isEmpty_String(useUrl)) { | ||
3162 | useUrl = copy_String(docUrl); | ||
3163 | } | ||
3164 | signIn_GmCerts(d->certs, dst, useUrl); | ||
3165 | postCommand_App("idents.changed"); | ||
3166 | postCommand_App("navigate.reload"); | ||
3167 | delete_String(useUrl); | ||
3168 | } | ||
3169 | return iTrue; | ||
3170 | } | ||
3152 | else if (equal_Command(cmd, "idents.changed")) { | 3171 | else if (equal_Command(cmd, "idents.changed")) { |
3153 | saveIdentities_GmCerts(d->certs); | 3172 | saveIdentities_GmCerts(d->certs); |
3154 | return iFalse; | 3173 | return iFalse; |
diff --git a/src/gmcerts.c b/src/gmcerts.c index f95fea7d..345c36e0 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c | |||
@@ -201,6 +201,15 @@ void clearUse_GmIdentity(iGmIdentity *d) { | |||
201 | clear_StringSet(d->useUrls); | 201 | clear_StringSet(d->useUrls); |
202 | } | 202 | } |
203 | 203 | ||
204 | const iString *findUse_GmIdentity(const iGmIdentity *d, const iString *url) { | ||
205 | iConstForEach(StringSet, using, d->useUrls) { | ||
206 | if (startsWith_String(url, cstr_String(using.value))) { | ||
207 | return using.value; | ||
208 | } | ||
209 | } | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
204 | const iString *name_GmIdentity(const iGmIdentity *d) { | 213 | const iString *name_GmIdentity(const iGmIdentity *d) { |
205 | iString *name = collect_String(subject_TlsCertificate(d->cert)); | 214 | iString *name = collect_String(subject_TlsCertificate(d->cert)); |
206 | if (startsWith_String(name, "CN = ")) { | 215 | if (startsWith_String(name, "CN = ")) { |
diff --git a/src/gmcerts.h b/src/gmcerts.h index 02a41c14..6ece1954 100644 --- a/src/gmcerts.h +++ b/src/gmcerts.h | |||
@@ -48,8 +48,9 @@ iBool isUsed_GmIdentity (const iGmIdentity *); | |||
48 | iBool isUsedOn_GmIdentity (const iGmIdentity *, const iString *url); | 48 | iBool isUsedOn_GmIdentity (const iGmIdentity *, const iString *url); |
49 | iBool isUsedOnDomain_GmIdentity (const iGmIdentity *, const iRangecc domain); | 49 | iBool isUsedOnDomain_GmIdentity (const iGmIdentity *, const iRangecc domain); |
50 | 50 | ||
51 | void setUse_GmIdentity (iGmIdentity *, const iString *url, iBool use); | 51 | void setUse_GmIdentity (iGmIdentity *, const iString *url, iBool use); |
52 | void clearUse_GmIdentity (iGmIdentity *); | 52 | void clearUse_GmIdentity (iGmIdentity *); |
53 | const iString *findUse_GmIdentity (const iGmIdentity *, const iString *url); | ||
53 | 54 | ||
54 | const iString *name_GmIdentity(const iGmIdentity *); | 55 | const iString *name_GmIdentity(const iGmIdentity *); |
55 | 56 | ||
diff --git a/src/sitespec.c b/src/sitespec.c index 6f4546f0..f8b77c86 100644 --- a/src/sitespec.c +++ b/src/sitespec.c | |||
@@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
25 | #include <the_Foundation/file.h> | 25 | #include <the_Foundation/file.h> |
26 | #include <the_Foundation/path.h> | 26 | #include <the_Foundation/path.h> |
27 | #include <the_Foundation/stringhash.h> | 27 | #include <the_Foundation/stringhash.h> |
28 | #include <the_Foundation/stringarray.h> | ||
28 | #include <the_Foundation/toml.h> | 29 | #include <the_Foundation/toml.h> |
29 | 30 | ||
30 | iDeclareClass(SiteParams) | 31 | iDeclareClass(SiteParams) |
@@ -35,6 +36,7 @@ struct Impl_SiteParams { | |||
35 | uint16_t titanPort; | 36 | uint16_t titanPort; |
36 | iString titanIdentity; /* fingerprint */ | 37 | iString titanIdentity; /* fingerprint */ |
37 | int dismissWarnings; | 38 | int dismissWarnings; |
39 | iStringArray usedIdentities; /* fingerprints; latest ones at the end */ | ||
38 | /* TODO: theme seed, style settings */ | 40 | /* TODO: theme seed, style settings */ |
39 | }; | 41 | }; |
40 | 42 | ||
@@ -42,12 +44,23 @@ void init_SiteParams(iSiteParams *d) { | |||
42 | d->titanPort = 0; /* undefined */ | 44 | d->titanPort = 0; /* undefined */ |
43 | init_String(&d->titanIdentity); | 45 | init_String(&d->titanIdentity); |
44 | d->dismissWarnings = 0; | 46 | d->dismissWarnings = 0; |
47 | init_StringArray(&d->usedIdentities); | ||
45 | } | 48 | } |
46 | 49 | ||
47 | void deinit_SiteParams(iSiteParams *d) { | 50 | void deinit_SiteParams(iSiteParams *d) { |
51 | deinit_StringArray(&d->usedIdentities); | ||
48 | deinit_String(&d->titanIdentity); | 52 | deinit_String(&d->titanIdentity); |
49 | } | 53 | } |
50 | 54 | ||
55 | static size_t findUsedIdentity_SiteParams_(const iSiteParams *d, const iString *fingerprint) { | ||
56 | iConstForEach(StringArray, i, &d->usedIdentities) { | ||
57 | if (equal_String(i.value, fingerprint)) { | ||
58 | return index_StringArrayConstIterator(&i); | ||
59 | } | ||
60 | } | ||
61 | return iInvalidPos; | ||
62 | } | ||
63 | |||
51 | iDefineClass(SiteParams) | 64 | iDefineClass(SiteParams) |
52 | iDefineObjectConstruction(SiteParams) | 65 | iDefineObjectConstruction(SiteParams) |
53 | 66 | ||
@@ -130,6 +143,12 @@ static void handleIniKeyValue_SiteSpec_(void *context, const iString *table, con | |||
130 | else if (!cmp_String(key, "dismissWarnings") && value->type == int64_TomlType) { | 143 | else if (!cmp_String(key, "dismissWarnings") && value->type == int64_TomlType) { |
131 | d->loadParams->dismissWarnings = value->value.int64; | 144 | d->loadParams->dismissWarnings = value->value.int64; |
132 | } | 145 | } |
146 | else if (!cmp_String(key, "usedIdentities") && value->type == string_TomlType) { | ||
147 | iRangecc seg = iNullRange; | ||
148 | while (nextSplit_Rangecc(range_String(value->value.string), " ", &seg)) { | ||
149 | pushBack_StringArray(&d->loadParams->usedIdentities, collectNewRange_String(seg)); | ||
150 | } | ||
151 | } | ||
133 | } | 152 | } |
134 | 153 | ||
135 | static iBool load_SiteSpec_(iSiteSpec *d) { | 154 | static iBool load_SiteSpec_(iSiteSpec *d) { |
@@ -151,6 +170,7 @@ static void save_SiteSpec_(iSiteSpec *d) { | |||
151 | if (open_File(f, writeOnly_FileMode | text_FileMode)) { | 170 | if (open_File(f, writeOnly_FileMode | text_FileMode)) { |
152 | iString *buf = new_String(); | 171 | iString *buf = new_String(); |
153 | iConstForEach(StringHash, i, &d->sites) { | 172 | iConstForEach(StringHash, i, &d->sites) { |
173 | iBeginCollect(); | ||
154 | const iBlock * key = &i.value->keyBlock; | 174 | const iBlock * key = &i.value->keyBlock; |
155 | const iSiteParams *params = i.value->object; | 175 | const iSiteParams *params = i.value->object; |
156 | format_String(buf, "[%s]\n", cstr_Block(key)); | 176 | format_String(buf, "[%s]\n", cstr_Block(key)); |
@@ -164,8 +184,15 @@ static void save_SiteSpec_(iSiteSpec *d) { | |||
164 | if (params->dismissWarnings) { | 184 | if (params->dismissWarnings) { |
165 | appendFormat_String(buf, "dismissWarnings = 0x%x\n", params->dismissWarnings); | 185 | appendFormat_String(buf, "dismissWarnings = 0x%x\n", params->dismissWarnings); |
166 | } | 186 | } |
187 | if (!isEmpty_StringArray(¶ms->usedIdentities)) { | ||
188 | appendFormat_String( | ||
189 | buf, | ||
190 | "usedIdentities = \"%s\"\n", | ||
191 | cstrCollect_String(joinCStr_StringArray(¶ms->usedIdentities, " "))); | ||
192 | } | ||
167 | appendCStr_String(buf, "\n"); | 193 | appendCStr_String(buf, "\n"); |
168 | write_File(f, utf8_String(buf)); | 194 | write_File(f, utf8_String(buf)); |
195 | iEndCollect(); | ||
169 | } | 196 | } |
170 | delete_String(buf); | 197 | delete_String(buf); |
171 | } | 198 | } |
@@ -188,14 +215,19 @@ void deinit_SiteSpec(void) { | |||
188 | deinit_String(&d->saveDir); | 215 | deinit_String(&d->saveDir); |
189 | } | 216 | } |
190 | 217 | ||
191 | void setValue_SiteSpec(const iString *site, enum iSiteSpecKey key, int value) { | 218 | static iSiteParams *findParams_SiteSpec_(iSiteSpec *d, const iString *site) { |
192 | iSiteSpec *d = &siteSpec_; | ||
193 | const iString *hashKey = collect_String(lower_String(site)); | 219 | const iString *hashKey = collect_String(lower_String(site)); |
194 | iSiteParams *params = value_StringHash(&d->sites, hashKey); | 220 | iSiteParams *params = value_StringHash(&d->sites, hashKey); |
195 | if (!params) { | 221 | if (!params) { |
196 | params = new_SiteParams(); | 222 | params = new_SiteParams(); |
197 | insert_StringHash(&d->sites, hashKey, params); | 223 | insert_StringHash(&d->sites, hashKey, params); |
198 | } | 224 | } |
225 | return params; | ||
226 | } | ||
227 | |||
228 | void setValue_SiteSpec(const iString *site, enum iSiteSpecKey key, int value) { | ||
229 | iSiteSpec *d = &siteSpec_; | ||
230 | iSiteParams *params = findParams_SiteSpec_(d, site); | ||
199 | iBool needSave = iFalse; | 231 | iBool needSave = iFalse; |
200 | switch (key) { | 232 | switch (key) { |
201 | case titanPort_SiteSpecKey: | 233 | case titanPort_SiteSpecKey: |
@@ -216,12 +248,7 @@ void setValue_SiteSpec(const iString *site, enum iSiteSpecKey key, int value) { | |||
216 | 248 | ||
217 | void setValueString_SiteSpec(const iString *site, enum iSiteSpecKey key, const iString *value) { | 249 | void setValueString_SiteSpec(const iString *site, enum iSiteSpecKey key, const iString *value) { |
218 | iSiteSpec *d = &siteSpec_; | 250 | iSiteSpec *d = &siteSpec_; |
219 | const iString *hashKey = collect_String(lower_String(site)); | 251 | iSiteParams *params = findParams_SiteSpec_(d, site); |
220 | iSiteParams *params = value_StringHash(&d->sites, hashKey); | ||
221 | if (!params) { | ||
222 | params = new_SiteParams(); | ||
223 | insert_StringHash(&d->sites, hashKey, params); | ||
224 | } | ||
225 | iBool needSave = iFalse; | 252 | iBool needSave = iFalse; |
226 | switch (key) { | 253 | switch (key) { |
227 | case titanIdentity_SiteSpecKey: | 254 | case titanIdentity_SiteSpecKey: |
@@ -238,6 +265,44 @@ void setValueString_SiteSpec(const iString *site, enum iSiteSpecKey key, const i | |||
238 | } | 265 | } |
239 | } | 266 | } |
240 | 267 | ||
268 | static void insertOrRemoveString_SiteSpec_(iSiteSpec *d, const iString *site, enum iSiteSpecKey key, | ||
269 | const iString *value, iBool doInsert) { | ||
270 | iSiteParams *params = findParams_SiteSpec_(d, site); | ||
271 | iBool needSave = iFalse; | ||
272 | switch (key) { | ||
273 | case usedIdentities_SiteSpecKey: { | ||
274 | const size_t index = findUsedIdentity_SiteParams_(params, value); | ||
275 | if (doInsert && index == iInvalidPos) { | ||
276 | pushBack_StringArray(¶ms->usedIdentities, value); | ||
277 | needSave = iTrue; | ||
278 | } | ||
279 | else if (!doInsert && index != iInvalidPos) { | ||
280 | remove_StringArray(¶ms->usedIdentities, index); | ||
281 | needSave = iTrue; | ||
282 | } | ||
283 | break; | ||
284 | } | ||
285 | default: | ||
286 | break; | ||
287 | } | ||
288 | if (needSave) { | ||
289 | save_SiteSpec_(d); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | void insertString_SiteSpec(const iString *site, enum iSiteSpecKey key, const iString *value) { | ||
294 | insertOrRemoveString_SiteSpec_(&siteSpec_, site, key, value, iTrue); | ||
295 | } | ||
296 | |||
297 | void removeString_SiteSpec(const iString *site, enum iSiteSpecKey key, const iString *value) { | ||
298 | insertOrRemoveString_SiteSpec_(&siteSpec_, site, key, value, iFalse); | ||
299 | } | ||
300 | |||
301 | const iStringArray *strings_SiteSpec(const iString *site, enum iSiteSpecKey key) { | ||
302 | const iSiteParams *params = findParams_SiteSpec_(&siteSpec_, site); | ||
303 | return ¶ms->usedIdentities; | ||
304 | } | ||
305 | |||
241 | int value_SiteSpec(const iString *site, enum iSiteSpecKey key) { | 306 | int value_SiteSpec(const iString *site, enum iSiteSpecKey key) { |
242 | iSiteSpec *d = &siteSpec_; | 307 | iSiteSpec *d = &siteSpec_; |
243 | const iSiteParams *params = constValue_StringHash(&d->sites, collect_String(lower_String(site))); | 308 | const iSiteParams *params = constValue_StringHash(&d->sites, collect_String(lower_String(site))); |
diff --git a/src/sitespec.h b/src/sitespec.h index 5adaeb8c..11c40e3c 100644 --- a/src/sitespec.h +++ b/src/sitespec.h | |||
@@ -22,22 +22,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
22 | 22 | ||
23 | #pragma once | 23 | #pragma once |
24 | 24 | ||
25 | #include <the_Foundation/string.h> | 25 | #include <the_Foundation/stringarray.h> |
26 | 26 | ||
27 | iDeclareType(SiteSpec) | 27 | iDeclareType(SiteSpec) |
28 | 28 | ||
29 | enum iSiteSpecKey { | 29 | enum iSiteSpecKey { |
30 | titanPort_SiteSpecKey, | 30 | titanPort_SiteSpecKey, /* int */ |
31 | titanIdentity_SiteSpecKey, | 31 | titanIdentity_SiteSpecKey, /* String */ |
32 | dismissWarnings_SiteSpecKey, | 32 | dismissWarnings_SiteSpecKey, /* int */ |
33 | usedIdentities_SiteSpecKey, /* StringArray */ | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | void init_SiteSpec (const char *saveDir); | 36 | void init_SiteSpec (const char *saveDir); |
36 | void deinit_SiteSpec (void); | 37 | void deinit_SiteSpec (void); |
37 | 38 | ||
38 | /* changes saved immediately */ | 39 | /* changes saved immediately */ |
39 | void setValue_SiteSpec (const iString *site, enum iSiteSpecKey key, int value); | 40 | void setValue_SiteSpec (const iString *site, enum iSiteSpecKey key, int value); |
40 | void setValueString_SiteSpec (const iString *site, enum iSiteSpecKey key, const iString *value); | 41 | void setValueString_SiteSpec (const iString *site, enum iSiteSpecKey key, const iString *value); |
42 | void insertString_SiteSpec (const iString *site, enum iSiteSpecKey key, const iString *value); | ||
43 | void removeString_SiteSpec (const iString *site, enum iSiteSpecKey key, const iString *value); | ||
41 | 44 | ||
42 | int value_SiteSpec (const iString *site, enum iSiteSpecKey key); | 45 | int value_SiteSpec (const iString *site, enum iSiteSpecKey key); |
43 | const iString * valueString_SiteSpec (const iString *site, enum iSiteSpecKey key); | 46 | const iString * valueString_SiteSpec (const iString *site, enum iSiteSpecKey key); |
47 | const iStringArray *strings_SiteSpec (const iString *site, enum iSiteSpecKey key); | ||
diff --git a/src/ui/root.c b/src/ui/root.c index c2161d80..f06ae842 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
38 | #include "../history.h" | 38 | #include "../history.h" |
39 | #include "../gmcerts.h" | 39 | #include "../gmcerts.h" |
40 | #include "../gmutil.h" | 40 | #include "../gmutil.h" |
41 | #include "../sitespec.h" | ||
41 | #include "../visited.h" | 42 | #include "../visited.h" |
42 | 43 | ||
43 | #if defined (iPlatformMsys) | 44 | #if defined (iPlatformMsys) |
@@ -330,6 +331,66 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
330 | openMenuFlags_Widget(menu, zero_I2(), postCommands_MenuOpenFlags | center_MenuOpenFlags); | 331 | openMenuFlags_Widget(menu, zero_I2(), postCommands_MenuOpenFlags | center_MenuOpenFlags); |
331 | return iTrue; | 332 | return iTrue; |
332 | } | 333 | } |
334 | else if (equal_Command(cmd, "identmenu.open")) { | ||
335 | iWidget *button = findWidget_Root("navbar.ident"); | ||
336 | iArray items; | ||
337 | init_Array(&items, sizeof(iMenuItem)); | ||
338 | /* Current identity. */ | ||
339 | const iString *docUrl = url_DocumentWidget(document_App()); | ||
340 | const iGmIdentity *ident = identityForUrl_GmCerts(certs_App(), docUrl); | ||
341 | const iString *fp = collect_String(hexEncode_Block(&ident->fingerprint)); | ||
342 | pushBackN_Array(&items, | ||
343 | (iMenuItem[]){ { format_CStr("///" uiHeading_ColorEscape "%s", | ||
344 | ident ? cstr_String(name_GmIdentity(ident)) | ||
345 | : "${menu.identity.notactive}") }, | ||
346 | { "---" } }, | ||
347 | 2); | ||
348 | /* Alternate identities. */ { | ||
349 | const iString *site = collectNewRange_String(urlRoot_String(docUrl)); | ||
350 | iBool haveAlts = iFalse; | ||
351 | iConstForEach(StringArray, i, strings_SiteSpec(site, usedIdentities_SiteSpecKey)) { | ||
352 | if (!equal_String(i.value, fp)) { | ||
353 | const iBlock *otherFp = collect_Block(hexDecode_Rangecc(range_String(i.value))); | ||
354 | const iGmIdentity *other = findIdentity_GmCerts(certs_App(), otherFp); | ||
355 | if (other) { | ||
356 | pushBack_Array( | ||
357 | &items, | ||
358 | &(iMenuItem){ | ||
359 | format_CStr(translateCStr_Lang("\U0001f816 ${ident.switch}"), | ||
360 | cstr_String(name_GmIdentity(other))), | ||
361 | 0, | ||
362 | 0, | ||
363 | format_CStr("ident.switch fp:%s", cstr_String(i.value)) }); | ||
364 | haveAlts = iTrue; | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | if (haveAlts) { | ||
369 | pushBack_Array(&items, &(iMenuItem){ "---" }); | ||
370 | } | ||
371 | } | ||
372 | iSidebarWidget *sidebar = findWidget_App("sidebar"); | ||
373 | pushBackN_Array( | ||
374 | &items, | ||
375 | (iMenuItem[]){ | ||
376 | { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" }, | ||
377 | { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, | ||
378 | { "---" }, | ||
379 | { isVisible_Widget(sidebar) && mode_SidebarWidget(sidebar) == identities_SidebarMode | ||
380 | ? leftHalf_Icon " ${menu.hide.identities}" | ||
381 | : leftHalf_Icon " ${menu.show.identities}", | ||
382 | 0, | ||
383 | 0, | ||
384 | deviceType_App() == phone_AppDeviceType ? "toolbar.showident" | ||
385 | : "sidebar.mode arg:3 toggle:1" }, | ||
386 | }, | ||
387 | 4); | ||
388 | iWidget *menu = | ||
389 | makeMenu_Widget(button, constData_Array(&items), size_Array(&items)); | ||
390 | openMenu_Widget(menu, topLeft_Rect(bounds_Widget(button))); | ||
391 | deinit_Array(&items); | ||
392 | return iTrue; | ||
393 | } | ||
333 | else if (equal_Command(cmd, "contextclick")) { | 394 | else if (equal_Command(cmd, "contextclick")) { |
334 | iBool showBarMenu = iFalse; | 395 | iBool showBarMenu = iFalse; |
335 | if (equal_Rangecc(range_Command(cmd, "id"), "buttons")) { | 396 | if (equal_Rangecc(range_Command(cmd, "id"), "buttons")) { |
@@ -780,6 +841,26 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
780 | dismissPortraitPhoneSidebars_Root(get_Root()); | 841 | dismissPortraitPhoneSidebars_Root(get_Root()); |
781 | updateNavBarIdentity_(navBar); | 842 | updateNavBarIdentity_(navBar); |
782 | updateNavDirButtons_(navBar); | 843 | updateNavDirButtons_(navBar); |
844 | /* Update site-specific used identities. */ { | ||
845 | const iGmIdentity *ident = | ||
846 | identityForUrl_GmCerts(certs_App(), url_DocumentWidget(document_App())); | ||
847 | if (ident) { | ||
848 | const iString *site = | ||
849 | collectNewRange_String(urlRoot_String(canonicalUrl_String(urlStr))); | ||
850 | const iStringArray *usedIdents = | ||
851 | strings_SiteSpec(site, usedIdentities_SiteSpecKey); | ||
852 | const iString *fingerprint = collect_String(hexEncode_Block(&ident->fingerprint)); | ||
853 | /* Keep this identity at the end of the list. */ | ||
854 | removeString_SiteSpec(site, usedIdentities_SiteSpecKey, fingerprint); | ||
855 | insertString_SiteSpec(site, usedIdentities_SiteSpecKey, fingerprint); | ||
856 | /* Keep the list short. */ | ||
857 | while (size_StringArray(usedIdents) > 5) { | ||
858 | removeString_SiteSpec(site, | ||
859 | usedIdentities_SiteSpecKey, | ||
860 | constAt_StringArray(usedIdents, 0)); | ||
861 | } | ||
862 | } | ||
863 | } | ||
783 | /* Icon updates should be limited to automatically chosen icons if the user | 864 | /* Icon updates should be limited to automatically chosen icons if the user |
784 | is allowed to pick their own in the future. */ | 865 | is allowed to pick their own in the future. */ |
785 | if (updateBookmarkIcon_Bookmarks(bookmarks_App(), urlStr, | 866 | if (updateBookmarkIcon_Bookmarks(bookmarks_App(), urlStr, |
@@ -1268,10 +1349,10 @@ void createUserInterface_Root(iRoot *d) { | |||
1268 | setId_Widget(addChild_Widget(rightEmbed, iClob(makePadding_Widget(0))), "url.embedpad"); | 1349 | setId_Widget(addChild_Widget(rightEmbed, iClob(makePadding_Widget(0))), "url.embedpad"); |
1269 | } | 1350 | } |
1270 | /* The active identity menu. */ { | 1351 | /* The active identity menu. */ { |
1271 | iLabelWidget *idMenu = makeMenuButton_LabelWidget( | 1352 | iLabelWidget *idButton = new_LabelWidget(person_Icon, "identmenu.open"); |
1272 | "\U0001f464", identityButtonMenuItems_, iElemCount(identityButtonMenuItems_)); | 1353 | // "\U0001f464", identityButtonMenuItems_, iElemCount(identityButtonMenuItems_)); |
1273 | setAlignVisually_LabelWidget(idMenu, iTrue); | 1354 | setAlignVisually_LabelWidget(idButton, iTrue); |
1274 | setId_Widget(addChildFlags_Widget(navBar, iClob(idMenu), collapse_WidgetFlag), "navbar.ident"); | 1355 | setId_Widget(addChildFlags_Widget(navBar, iClob(idButton), collapse_WidgetFlag), "navbar.ident"); |
1275 | } | 1356 | } |
1276 | addChildFlags_Widget(navBar, iClob(new_Widget()), expand_WidgetFlag); | 1357 | addChildFlags_Widget(navBar, iClob(new_Widget()), expand_WidgetFlag); |
1277 | setId_Widget(addChildFlags_Widget(navBar, | 1358 | setId_Widget(addChildFlags_Widget(navBar, |