diff options
Diffstat (limited to 'src/gmrequest.c')
-rw-r--r-- | src/gmrequest.c | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/src/gmrequest.c b/src/gmrequest.c index 996c77ea..2b6ee9f9 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -2,11 +2,13 @@ | |||
2 | #include "gmutil.h" | 2 | #include "gmutil.h" |
3 | #include "gmcerts.h" | 3 | #include "gmcerts.h" |
4 | #include "app.h" /* dataDir_App() */ | 4 | #include "app.h" /* dataDir_App() */ |
5 | #include "embedded.h" | ||
5 | 6 | ||
6 | #include <the_Foundation/file.h> | 7 | #include <the_Foundation/file.h> |
7 | #include <the_Foundation/tlsrequest.h> | ||
8 | #include <the_Foundation/mutex.h> | 8 | #include <the_Foundation/mutex.h> |
9 | #include <the_Foundation/path.h> | 9 | #include <the_Foundation/path.h> |
10 | #include <the_Foundation/regexp.h> | ||
11 | #include <the_Foundation/tlsrequest.h> | ||
10 | 12 | ||
11 | #include <SDL_timer.h> | 13 | #include <SDL_timer.h> |
12 | 14 | ||
@@ -81,17 +83,17 @@ enum iGmRequestState { | |||
81 | }; | 83 | }; |
82 | 84 | ||
83 | struct Impl_GmRequest { | 85 | struct Impl_GmRequest { |
84 | iObject object; | 86 | iObject object; |
85 | iMutex mutex; | 87 | iMutex mutex; |
86 | iGmCerts * certs; /* not owned */ | 88 | iGmCerts * certs; /* not owned */ |
87 | enum iGmRequestState state; | 89 | enum iGmRequestState state; |
88 | iString url; | 90 | iString url; |
89 | iTlsRequest * req; | 91 | iTlsRequest * req; |
90 | iGmResponse resp; | 92 | iGmResponse resp; |
91 | uint32_t timeoutId; /* in case server doesn't close the connection */ | 93 | uint32_t timeoutId; /* in case server doesn't close the connection */ |
92 | iAudience * updated; | 94 | iAudience * updated; |
93 | iAudience * timeout; | 95 | iAudience * timeout; |
94 | iAudience * finished; | 96 | iAudience * finished; |
95 | }; | 97 | }; |
96 | 98 | ||
97 | iDefineObjectConstructionArgs(GmRequest, (iGmCerts *certs), certs) | 99 | iDefineObjectConstructionArgs(GmRequest, (iGmCerts *certs), certs) |
@@ -261,6 +263,40 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
261 | iNotifyAudience(d, finished, GmRequestFinished); | 263 | iNotifyAudience(d, finished, GmRequestFinished); |
262 | } | 264 | } |
263 | 265 | ||
266 | static const iBlock *aboutPageSource_(iRangecc path) { | ||
267 | const iBlock *src = NULL; | ||
268 | if (equalCase_Rangecc(&path, "lagrange")) { | ||
269 | return &blobAbout_Embedded; | ||
270 | } | ||
271 | if (equalCase_Rangecc(&path, "help")) { | ||
272 | return &blobHelp_Embedded; | ||
273 | } | ||
274 | if (equalCase_Rangecc(&path, "version")) { | ||
275 | return &blobVersion_Embedded; | ||
276 | } | ||
277 | return src; | ||
278 | } | ||
279 | |||
280 | static const iBlock *replaceVariables_(const iBlock *block) { | ||
281 | iRegExp *var = new_RegExp("\\$\\{([A-Z_]+)\\}", 0); | ||
282 | iRegExpMatch m; | ||
283 | if (matchRange_RegExp(var, range_Block(block), &m)) { | ||
284 | iBlock *replaced = collect_Block(copy_Block(block)); | ||
285 | do { | ||
286 | const iRangei span = m.range; | ||
287 | remove_Block(replaced, span.start, size_Range(&span)); | ||
288 | const iRangecc name = capturedRange_RegExpMatch(&m, 1); | ||
289 | if (equal_Rangecc(&name, "APP_VERSION")) { | ||
290 | insertData_Block(replaced, span.start, | ||
291 | LAGRANGE_APP_VERSION, strlen(LAGRANGE_APP_VERSION)); | ||
292 | } | ||
293 | } while (matchRange_RegExp(var, range_Block(replaced), &m)); | ||
294 | block = replaced; | ||
295 | } | ||
296 | iRelease(var); | ||
297 | return block; | ||
298 | } | ||
299 | |||
264 | void submit_GmRequest(iGmRequest *d) { | 300 | void submit_GmRequest(iGmRequest *d) { |
265 | iAssert(d->state == initialized_GmRequestState); | 301 | iAssert(d->state == initialized_GmRequestState); |
266 | if (d->state != initialized_GmRequestState) { | 302 | if (d->state != initialized_GmRequestState) { |
@@ -272,25 +308,11 @@ void submit_GmRequest(iGmRequest *d) { | |||
272 | /* Check for special protocols. */ | 308 | /* Check for special protocols. */ |
273 | /* TODO: If this were a library, these could be handled via callbacks. */ | 309 | /* TODO: If this were a library, these could be handled via callbacks. */ |
274 | if (equalCase_Rangecc(&url.protocol, "about")) { | 310 | if (equalCase_Rangecc(&url.protocol, "about")) { |
275 | if (equalCase_Rangecc(&url.path, "home")) { | 311 | const iBlock *src = aboutPageSource_(url.path); |
312 | if (src) { | ||
276 | d->resp.statusCode = success_GmStatusCode; | 313 | d->resp.statusCode = success_GmStatusCode; |
277 | setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8"); | 314 | setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8"); |
278 | setCStr_Block(&d->resp.body, | 315 | set_Block(&d->resp.body, replaceVariables_(src)); |
279 | "```\n" | ||
280 | "ooooo\n" | ||
281 | "`888'\n" | ||
282 | " 888 .oooo. .oooooooo oooo d8b .oooo. ooo. .oo. .oooooooo .ooooo. \n" | ||
283 | " 888 `P )88b 888' `88b `888\"\"8P `P )88b `888P\"Y88b 888' `88b d88' `88b \n" | ||
284 | " 888 .oP\"888 888 888 888 .oP\"888 888 888 888 888 888ooo888 \n" | ||
285 | " 888 o d8( 888 `88bod8P' 888 d8( 888 888 888 `88bod8P' 888 .o \n" | ||
286 | "o888ooooood8 `Y888\"\"8o `8oooooo. d888b `Y888\"\"8o o888o o888o `8oooooo. `Y8bod8P' \n" | ||
287 | " d\" YD d\" YD\n" | ||
288 | " \"Y88888P' \"Y88888P'\n" | ||
289 | "```\n" | ||
290 | "# A Beautiful Gemini Client\n" | ||
291 | "## Version " LAGRANGE_APP_VERSION "\n\n" | ||
292 | "=> https://skyjake.fi/@jk by Jaakko Keränen <code@iki.fi>\n" | ||
293 | "Crafted with \u2615 in Finland\n"); | ||
294 | d->state = receivingBody_GmRequestState; | 316 | d->state = receivingBody_GmRequestState; |
295 | iNotifyAudience(d, updated, GmRequestUpdated); | 317 | iNotifyAudience(d, updated, GmRequestUpdated); |
296 | } | 318 | } |