2020-05-01 04:22:05 +00:00
|
|
|
.Dd May 1, 2020
|
2020-04-30 23:26:33 +00:00
|
|
|
.Dt LIBGEMINICLIENT 3
|
|
|
|
.Os
|
|
|
|
.Sh NAME
|
2020-05-01 04:22:05 +00:00
|
|
|
.Nm gemini_create , gemini_init , gemini_connect ,
|
|
|
|
.Nm gemini_connect_query , gemini_read , gemini_reset , gemini_fini ,
|
|
|
|
.Nm gemini_destroy
|
2020-04-30 23:26:33 +00:00
|
|
|
.Sh SYNOPSIS
|
|
|
|
.In libgeminiclient.h
|
|
|
|
.Ft struct gemini *
|
|
|
|
.Fn gemini_create void
|
|
|
|
.Ft void
|
|
|
|
.Fn gemini_init "struct gemini *ctx"
|
|
|
|
.Ft int
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect "struct gemini *ctx" "const char *url"
|
|
|
|
.Ft int
|
|
|
|
.Fn gemini_connect_query "struct gemini *ctx" "const char *url" \
|
|
|
|
"const char *query"
|
2020-04-30 23:26:33 +00:00
|
|
|
.Ft ssize_t
|
|
|
|
.Fn gemini_read "struct gemini *ctx" "void *buffer" "size_t size"
|
|
|
|
.Ft void
|
|
|
|
.Fn gemini_reset "struct gemini *ctx"
|
|
|
|
.Ft void
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_fini "struct gemini *ctx"
|
2020-04-30 23:26:33 +00:00
|
|
|
.Ft void
|
|
|
|
.Fn gemini_destroy "struct gemini *ctx"
|
|
|
|
.Sh DESCRIPTION
|
|
|
|
.Fn gemini_create
|
|
|
|
allocates a
|
|
|
|
.Vt gemini
|
|
|
|
structure and calls
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_init
|
|
|
|
on it.
|
2020-04-30 23:26:33 +00:00
|
|
|
.Pp
|
|
|
|
.Fn gemini_init
|
2020-05-01 04:22:05 +00:00
|
|
|
Initializes the provided
|
2020-04-30 23:26:33 +00:00
|
|
|
.Vt gemini
|
|
|
|
structure.
|
|
|
|
.Pp
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect
|
2020-04-30 23:26:33 +00:00
|
|
|
opens a connection to the provided
|
|
|
|
.Fa url ,
|
|
|
|
and sets up the
|
|
|
|
.Vt gemini
|
|
|
|
structure for reading.
|
|
|
|
.Pp
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect_query
|
|
|
|
calls
|
|
|
|
.Fn gemini_connect
|
|
|
|
with the escaped
|
|
|
|
.Fa query
|
|
|
|
appended to
|
|
|
|
.Fa url
|
|
|
|
separated by a question-mark.
|
|
|
|
.Pp
|
2020-04-30 23:26:33 +00:00
|
|
|
.Fn gemini_read
|
|
|
|
attempts to read using the
|
|
|
|
.Vt gemini
|
|
|
|
structure previously set up by
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect ,
|
2020-04-30 23:26:33 +00:00
|
|
|
sending the request and parsing the response as needed.
|
|
|
|
After a successful return the
|
|
|
|
.Fa meta ,
|
|
|
|
.Fa metalen ,
|
|
|
|
and
|
|
|
|
.Fa status
|
|
|
|
are set to that received by the response.
|
|
|
|
.Fa meta
|
|
|
|
will always be NUL terminated, but it may contain NUL characters itself.
|
|
|
|
.Pp
|
|
|
|
Categories of
|
|
|
|
.Fa status
|
|
|
|
values are as follows:
|
|
|
|
.Bl -tag -width Ds -compact
|
|
|
|
.It Li 1X
|
|
|
|
Request for user-input.
|
|
|
|
META contains the prompt.
|
|
|
|
.It Li 2X
|
|
|
|
Success.
|
|
|
|
META contains the MIME-type.
|
|
|
|
.It Li 3X
|
|
|
|
Redirect.
|
|
|
|
META contains the new URL.
|
|
|
|
.It Li 4X
|
|
|
|
Temporary failure.
|
|
|
|
META contains the error string.
|
|
|
|
.It Li 5X
|
|
|
|
Permanent failure.
|
|
|
|
META contains the error string.
|
|
|
|
.It Li 6X
|
|
|
|
Certificate required.
|
|
|
|
META contains additional information.
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
.Fn gemini_reset
|
|
|
|
prepares the provided
|
|
|
|
.Vt gemini
|
|
|
|
structure to be reused for
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect
|
2020-04-30 23:26:33 +00:00
|
|
|
while keeping reusable data.
|
|
|
|
This prevents user-configurable information from being reset,
|
|
|
|
and prevents
|
|
|
|
.Fa certfile ,
|
|
|
|
.Fa keyfile ,
|
|
|
|
and
|
|
|
|
.Fa tofufile
|
|
|
|
from being reopened.
|
|
|
|
.Pp
|
|
|
|
.Fn gemini_close
|
|
|
|
Closes and reinitializes the provided
|
|
|
|
.Vt gemini
|
|
|
|
structure.
|
|
|
|
.Pp
|
|
|
|
.Fn gemini_destroy
|
|
|
|
calls
|
|
|
|
.Fn gemini_close
|
|
|
|
on the provided
|
|
|
|
.Vt gemini
|
|
|
|
structure and frees it.
|
|
|
|
.Pp
|
|
|
|
The useful members of the
|
|
|
|
.Vt gemini
|
|
|
|
structure are as follows:
|
|
|
|
.Bd -literal -offset indent -compact
|
|
|
|
struct gemini {
|
|
|
|
char meta[GEMINI_META_MAX + 1];
|
|
|
|
const char *certfile; /* Certificate file */
|
|
|
|
const char *keyfile; /* Key file */
|
|
|
|
const char *tofufile; /* Known-hosts file */
|
|
|
|
size_t metalen; /* Length of `meta' */
|
|
|
|
int flags; /* Configuration flags */
|
|
|
|
int maxredirects; /* Default 5 */
|
2020-05-01 04:38:28 +00:00
|
|
|
int socketfd; /* The socket to use */
|
2020-04-30 23:26:33 +00:00
|
|
|
short status; /* Response STATUS */
|
|
|
|
short port; /* Default port */
|
|
|
|
};
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
Possible
|
|
|
|
.Fa flags
|
|
|
|
are as follows:
|
|
|
|
.Bl -tag -width Ds -compact
|
|
|
|
.It Dv GEMINI_TOFU_WRITE
|
|
|
|
Write any new certificate information to
|
|
|
|
.Fa tofufile
|
|
|
|
on
|
|
|
|
.Dn gemini_close .
|
2020-05-05 11:25:38 +00:00
|
|
|
.It Dv GEMINI_STRICT
|
|
|
|
Enforce a strict interpretation of the Gemini protocol.
|
2020-04-30 23:26:33 +00:00
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
All knows
|
|
|
|
.Fa status
|
|
|
|
values are as follows:
|
|
|
|
.Bl -tag -width Ds
|
|
|
|
.It Li 10
|
|
|
|
The server requested user-input.
|
|
|
|
META contains the suggested prompt to show the user.
|
|
|
|
.It Li 20
|
|
|
|
The request was successful, and the requested data will follow the
|
|
|
|
response.
|
|
|
|
META contains the MIME-type of the data.
|
|
|
|
.It Li 21
|
|
|
|
The request was successful, the requested data will follow the
|
|
|
|
response, and the user-defined certificate can retired.
|
|
|
|
META contains the MIME-type of the data.
|
|
|
|
.It Li 30
|
|
|
|
The requested resource currently exists at a different location.
|
|
|
|
META contains the new URL.
|
|
|
|
.It Li 31
|
|
|
|
The requested resource can be assumed to exist at a different location.
|
|
|
|
META contains the new URL.
|
|
|
|
.It Li 40
|
|
|
|
The request failed in a temporary manner.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 41
|
|
|
|
The server is currently unavailable.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 42
|
|
|
|
There was a CGI error.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 43
|
|
|
|
The requested host does not match the server, and the proxied request
|
|
|
|
failed.
|
|
|
|
the request.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 44
|
|
|
|
The request was rejected due to rate-limiting.
|
|
|
|
META contains an estimated amount of seconds before a retry may be
|
|
|
|
successful.
|
|
|
|
.It Li 50
|
|
|
|
The request failed in a permanent manner.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 51
|
|
|
|
The requested resource was not found by the server.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 52
|
|
|
|
The requested resource no longer exists at that URL.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 53
|
|
|
|
The requested host does not match the server, and it refused to proxy
|
|
|
|
the request.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 59
|
|
|
|
The server says that the client's request was invalid.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 60
|
|
|
|
An user-defined certificate is required.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 61
|
|
|
|
A transient user-defined certificate is required.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 62
|
|
|
|
An authorized user-defined certificate is required.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 63
|
|
|
|
The user-defined certificate was rejected because was not considered
|
|
|
|
valid by the server.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 64
|
|
|
|
The user-defined certificate was rejected because it is not yet valid.
|
|
|
|
META may contain additional information.
|
|
|
|
.It Li 65
|
|
|
|
The user-defined certificate was rejected because it is expired.
|
|
|
|
META may contain additional information.
|
|
|
|
.El
|
|
|
|
.Sh RETURN VALUES
|
|
|
|
.Fn gemini_create
|
|
|
|
returns a pointer to a newly initialized
|
|
|
|
.Vt gemini
|
|
|
|
structure, or a NULL on a failure.
|
|
|
|
.Pp
|
2020-05-01 04:22:05 +00:00
|
|
|
.Fn gemini_connect
|
|
|
|
and
|
|
|
|
.Fn gemini_connect_query
|
2020-04-30 23:26:33 +00:00
|
|
|
returns a 0 on success and a -1 on an error.
|
2020-05-01 04:38:28 +00:00
|
|
|
They can also return
|
|
|
|
.Dv TLS_WANT_POLLIN
|
|
|
|
and
|
|
|
|
.Dv TLS_WANT_POLLOUT
|
|
|
|
if
|
|
|
|
.Fa socketfd
|
|
|
|
is set to a non-blocking file-descriptor, even if they do it is safe to
|
|
|
|
call
|
|
|
|
.Fn gemini_read
|
|
|
|
at this point.
|
2020-04-30 23:26:33 +00:00
|
|
|
.Pp
|
|
|
|
.Fn gemini_read
|
|
|
|
returns a -1 on an error, otherwise it returns the amount of data
|
|
|
|
read into the buffer, with 0 only being returned when there is nothing
|
2020-05-01 04:22:05 +00:00
|
|
|
left to read after successfully reading the response header.
|
2020-05-01 04:38:28 +00:00
|
|
|
It can also return
|
|
|
|
.Dv TLS_WANT_POLLIN
|
|
|
|
and
|
|
|
|
.Dv TLS_WANT_POLLOUT
|
|
|
|
if
|
|
|
|
.Fa socketfd
|
|
|
|
is set to a non-blocking file-descriptor.
|
2020-04-30 23:26:33 +00:00
|
|
|
.Sh EXAMPLES
|
|
|
|
The following example shows how you initialize various values:
|
|
|
|
.Bd -literal -offset indent -compact
|
|
|
|
gemini = gemini_create();
|
|
|
|
gemini->keyfile = keyfile;
|
|
|
|
gemini->certfile = certfile;
|
|
|
|
gemini->tofufile = tofufile;
|
|
|
|
gemini->flags |= GEMINI_TOFU_WRITE;
|
|
|
|
gemini->port = port;
|
|
|
|
while ((url = get_url()) != NULL)
|
2020-05-01 04:22:05 +00:00
|
|
|
if (gemini_connect(gemini) != 0)
|
2020-04-30 23:26:33 +00:00
|
|
|
continue;
|
|
|
|
...
|
|
|
|
gemini_reset(gemini);
|
|
|
|
}
|
|
|
|
gemini_destroy(gemini);
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
The following example shows how to handle redirects and other status
|
|
|
|
codes yourself:
|
|
|
|
.Bd -literal -offset indent -compact
|
|
|
|
gemini->maxredirects = 0;
|
|
|
|
while ((url = get_url()) != NULL) {
|
2020-05-01 04:22:05 +00:00
|
|
|
if (gemini_connect(gemini, url) != 0) {
|
2020-04-30 23:26:33 +00:00
|
|
|
warn("Could not open: %s", url);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while ((r = gemini_read(gemini, buf, bufsize)) > 0) {
|
|
|
|
...
|
|
|
|
}
|
2020-05-01 04:22:05 +00:00
|
|
|
if (r < 0) {
|
|
|
|
warn("Error while reading");
|
|
|
|
gemini_reset(gemini);
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-30 23:26:33 +00:00
|
|
|
switch (gemini->status / 10) {
|
|
|
|
...
|
|
|
|
case 3:
|
2020-05-01 04:38:28 +00:00
|
|
|
if (yesno("Redirected to \\"%s\\" [Y/n]?",
|
|
|
|
gemini->meta))
|
2020-04-30 23:26:33 +00:00
|
|
|
prepend_url(gemini->meta);
|
|
|
|
break;
|
|
|
|
...
|
|
|
|
default:
|
2020-05-01 04:38:28 +00:00
|
|
|
warn("Bad status %02hd: %s", gemini->status,
|
|
|
|
gemini->meta);
|
2020-04-30 23:26:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
gemini_reset(gemini);
|
|
|
|
}
|
|
|
|
.Ed
|
|
|
|
.Sh SEE ALSO
|
|
|
|
.Xr tls_read 3
|